Sander
Sander

Reputation: 1274

Convert js-object (in a string) to JSON

Having a valid JS Object (ES6 formatted with trailing comma) in a string in for example a browser or node, how to get a valid JSON-object out of this? https://www.convertsimple.com/convert-javascript-to-json/ does it for example.

"Of course" I know about JSON.parse and JSON.stringify but not sure it can do the trick in this case. :) (Or at least, I don't see how). I also would like to avoid eval.

Example:

const jsObjectInString = `{
  key: "value",
  test: 1,
  result: [
    {
      subKeyOne: "test"
    },
    {
      subKeyTwo: "test value with space",
      test: 2
    }
  ],
}`;

Expected result:

{
  "key": "value",
  "test": 1,
  "result": [
    {
      "subKeyOne": "test"
    },
    {
      "subKeyTwo": "test value with space",
      "test": 2
    }
  ]
}

Upvotes: 0

Views: 79

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1075189

You'll need a JavaScript parser. You can use the one built into the JavaScript environment where your code is running, but you have to be sure that the string doesn't contain anything malicious, etc., since it won't just parse the code but will also execute it. So it's essential that you don't accept the string from User A and then "parse" it (run it) on User B's machine (unless User B explicitly allows it, like here on SO).

But if you don't trust the source, there are parsers for JavaScript written in JavaScript, such as Esprima, which will give you an AST of the parsed code (like this), which you can then use to build the resulting JSON.

Here's the approach if you can trust the source of the string:

const jsObjectInString = `{
  key: "value",
  test: 1,
  result: [
    {
      subKeyOne: "test"
    },
    {
      subKeyTwo: "test value with space",
      test: 2
    }
  ],
}`;
// The `(0, eval)(...)` thing is called "indirect eval" and it's there to
// prevent `eval` from getting access to the scope where you call it
const json = JSON.stringify(
    (0, eval)("(" + jsObjectInString + ")"),
    null,
    4
);
console.log(json);

Two things to note there:

  1. We don't call eval directly, because eval is magic and gets access to local scope when you call it directly. If you call it indirectly (as above), it doesn't get access to local scope.
  2. We wrap the object in () since otherwise the first { looks like the start of a block to the parser.

Upvotes: 2

Related Questions