0

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
    }
  ]
}
3

1 Answer 1

2

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.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer, this indeed works! Also confirms my direction of thinking.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.