From bb7afad761fc39a964303be9c33df96dadad6b9f Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sun, 26 Apr 2020 14:24:25 +0200 Subject: [PATCH] Fixed json issue --- boa/src/builtins/json/json.rs | 99 ++++++++++++++++++++++++++++++++++ boa/src/builtins/json/mod.rs | 80 +++++++++++++++++++++++++++ boa/src/builtins/json/tests.rs | 18 +++++++ 3 files changed, 197 insertions(+) create mode 100644 boa/src/builtins/json/json.rs create mode 100644 boa/src/builtins/json/mod.rs create mode 100644 boa/src/builtins/json/tests.rs diff --git a/boa/src/builtins/json/json.rs b/boa/src/builtins/json/json.rs new file mode 100644 index 0000000000..5837c18c2a --- /dev/null +++ b/boa/src/builtins/json/json.rs @@ -0,0 +1,99 @@ +//! This module implements the global `JSON` object. +//! +//! The `JSON` object contains methods for parsing [JavaScript Object Notation (JSON)][spec] +//! and converting values to JSON. It can't be called or constructed, and aside from its +//! two method properties, it has no interesting functionality of its own. +//! +//! More information: +//! - [ECMAScript reference][spec] +//! - [MDN documentation][mdn] +//! - [JSON specification][json] +//! +//! [spec]: https://tc39.es/ecma262/#sec-json +//! [json]: https://www.json.org/json-en.html +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON + +use crate::builtins::function::NativeFunctionData; +use crate::builtins::value::{to_value, ResultValue, Value, ValueData}; +use crate::exec::Interpreter; +use serde_json::{self, Value as JSONValue}; + +/// `JSON.parse( text[, reviver] )` +/// +/// This `JSON` method parses a JSON string, constructing the JavaScript value or object described by the string. +/// +/// An optional `reviver` function can be provided to perform a transformation on the resulting object before it is returned. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-json.parse +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse +// TODO: implement optional revever argument. +pub fn parse(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { + match serde_json::from_str::( + &args + .get(0) + .expect("cannot get argument for JSON.parse") + .clone() + .to_string(), + ) { + Ok(json) => Ok(to_value(json)), + Err(err) => Err(to_value(err.to_string())), + } +} + +/// `JSON.stringify( value[, replacer[, space]] )` +/// +/// This `JSON` method converts a JavaScript object or value to a JSON string. +/// +/// This medhod optionally replaces values if a `replacer` function is specified or +/// optionally including only the specified properties if a replacer array is specified. +/// +/// An optional `space` argument can be supplied of type `String` or `Number` that's used to insert +/// white space into the output JSON string for readability purposes. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-json.stringify +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify +pub fn stringify(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { + let obj = args.get(0).expect("cannot get argument for JSON.stringify"); + let json = obj.to_json().to_string(); + Ok(to_value(json)) +} + +/// Create a new `JSON` object. +pub fn create_constructor(global: &Value) -> Value { + let json = ValueData::new_obj(Some(global)); + + make_builtin_fn!(parse, named "parse", with length 2, of json); + make_builtin_fn!(stringify, named "stringify", with length 3, of json); + + to_value(json) +} + +#[cfg(test)] +mod tests { + use crate::{exec::Executor, forward, realm::Realm}; + + #[test] + fn json_sanity() { + let realm = Realm::create(); + let mut engine = Executor::new(realm); + assert_eq!( + forward(&mut engine, r#"JSON.parse('{"aaa":"bbb"}').aaa == 'bbb'"#), + "true" + ); + assert_eq!( + forward( + &mut engine, + r#"JSON.stringify({aaa: 'bbb'}) == '{"aaa":"bbb"}'"# + ), + "true" + ); + } +} diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs new file mode 100644 index 0000000000..c0e6e55ec8 --- /dev/null +++ b/boa/src/builtins/json/mod.rs @@ -0,0 +1,80 @@ +//! This module implements the global `JSON` object. +//! +//! The `JSON` object contains methods for parsing [JavaScript Object Notation (JSON)][spec] +//! and converting values to JSON. It can't be called or constructed, and aside from its +//! two method properties, it has no interesting functionality of its own. +//! +//! More information: +//! - [ECMAScript reference][spec] +//! - [MDN documentation][mdn] +//! - [JSON specification][json] +//! +//! [spec]: https://tc39.es/ecma262/#sec-json +//! [json]: https://www.json.org/json-en.html +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON + +use crate::builtins::function::NativeFunctionData; +use crate::builtins::value::{to_value, ResultValue, Value, ValueData}; +use crate::exec::Interpreter; +use serde_json::{self, Value as JSONValue}; + +#[cfg(test)] +mod tests; + +/// `JSON.parse( text[, reviver] )` +/// +/// This `JSON` method parses a JSON string, constructing the JavaScript value or object described by the string. +/// +/// An optional `reviver` function can be provided to perform a transformation on the resulting object before it is returned. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-json.parse +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse +// TODO: implement optional revever argument. +pub fn parse(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { + match serde_json::from_str::( + &args + .get(0) + .expect("cannot get argument for JSON.parse") + .clone() + .to_string(), + ) { + Ok(json) => Ok(to_value(json)), + Err(err) => Err(to_value(err.to_string())), + } +} + +/// `JSON.stringify( value[, replacer[, space]] )` +/// +/// This `JSON` method converts a JavaScript object or value to a JSON string. +/// +/// This medhod optionally replaces values if a `replacer` function is specified or +/// optionally including only the specified properties if a replacer array is specified. +/// +/// An optional `space` argument can be supplied of type `String` or `Number` that's used to insert +/// white space into the output JSON string for readability purposes. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-json.stringify +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify +pub fn stringify(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { + let obj = args.get(0).expect("cannot get argument for JSON.stringify"); + let json = obj.to_json().to_string(); + Ok(to_value(json)) +} + +/// Create a new `JSON` object. +pub fn create_constructor(global: &Value) -> Value { + let json = ValueData::new_obj(Some(global)); + + make_builtin_fn!(parse, named "parse", with length 2, of json); + make_builtin_fn!(stringify, named "stringify", with length 3, of json); + + to_value(json) +} diff --git a/boa/src/builtins/json/tests.rs b/boa/src/builtins/json/tests.rs new file mode 100644 index 0000000000..5143da8cc8 --- /dev/null +++ b/boa/src/builtins/json/tests.rs @@ -0,0 +1,18 @@ +use crate::{exec::Executor, forward, realm::Realm}; + +#[test] +fn json_sanity() { + let realm = Realm::create(); + let mut engine = Executor::new(realm); + assert_eq!( + forward(&mut engine, r#"JSON.parse('{"aaa":"bbb"}').aaa == 'bbb'"#), + "true" + ); + assert_eq!( + forward( + &mut engine, + r#"JSON.stringify({aaa: 'bbb'}) == '{"aaa":"bbb"}'"# + ), + "true" + ); +}