rubyjs / mini_racer

Minimal embedded v8
MIT License
585 stars 91 forks source link

Unexpected token p in JSON at position #274

Closed phstc closed 1 year ago

phstc commented 1 year ago

I'm trying to set a variable var with a JSON content.

request_var = { 'body' => '{"param1":"some value","param2":"some other value"}' }

# request_var_to_json: "{\"body\":\"{\\\"param1\\\":\\\"some value\\\",\\\"param2\\\":\\\"some other value\\\"}\"}"
request_var_to_json = request_var.to_json

v8_ctx.eval("var request=JSON.parse('#{request_var_to_json}');")

and I'm getting "Unexpected token p in JSON at position".

This same code used to work properly with therubyracer.

If I try to JSON.parse the request_var_to_json using JavaScript, it works fine.

image

Any ideas on what it could be?

tisba commented 1 year ago

If you closely compare the code you've put into your browser console, you'll notice it is not the same you have in your Ruby code.

It's a quoting issue. I think your example can be simplified to this:

data = { "foo" => %q(") }
str_to_eval = %Q|JSON.parse('#{data.to_json}')|
puts str_to_eval

which prints: JSON.parse('{"foo":"\""}'). Which is not a valid JSON string after JS evaluation. You have to keep in mind, that the \ needs to be escaped as well as we want the literal "forward slash". While the previous JS code snippet won't work, but JSON.parse('{"foo":"\\""}') does. This has nothing to to with mini_racer or Node.js or Chrome.

Depending on your use case, it might be easier to define a function and use Context#call, so you don't have to worry so much about properly embedding the escaped string into the code.

Alternatively you can do the following. I'm not sure if there is a nicer way to do that, but this works:

data = { 'body' => '{"param1":"some value","param2":"some other value"}' } # your example input
data == JSON.parse(MiniRacer::Context.new.eval(data.to_json.to_json))
=> true

The String#to_json trick will make sure the String is properly escaped and it will look like this: "{\"body\":\"{\\\"param1\\\":\\\"some value\\\",\\\"param2\\\":\\\"some other value\\\"}\"}" (everything here is printed as literal characters).

Escaping across so many layers is always confusing 😅 Hope that helps understanding the issue!

phstc commented 1 year ago

@tisba thank you for troubleshooting this! ❤️