Browse Source

Put JSON functions on the object, not the prototype (#325)

* Move JSON functions to the object, not the prototype

* Fix Value.to_json and add JSON tests

* Update boa/src/builtins/json.rs

* Update boa/src/builtins/json.rs

* Update boa/src/builtins/json.rs

* Update json.rs

* Fix fmt issues.

Co-authored-by: Iban Eguia <razican@protonmail.ch>
Co-authored-by: HalidOdat <halidodat@gmail.com>
pull/355/head
Noah 4 years ago committed by GitHub
parent
commit
271e2b4da6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 59
      boa/src/builtins/json.rs
  2. 12
      boa/src/builtins/value/mod.rs

59
boa/src/builtins/json.rs

@ -1,10 +1,22 @@
//! This module implements the global `JSON` object.
//!
//! The `JSON` object contains methods for parsing [JavaScript Object Notation (JSON)][json]
//! 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::object::{Object, ObjectKind, PROTOTYPE};
/// The JSON Object
/// <https://tc39.es/ecma262/#sec-json-object>
use crate::builtins::value::{to_value, ResultValue, Value, ValueData};
use crate::exec::Interpreter;
use serde_json::{self, to_string_pretty, Value as JSONValue};
use serde_json::{self, Value as JSONValue};
/// Parse a JSON string into a Javascript object
/// <https://tc39.es/ecma262/#sec-json.parse>
@ -20,23 +32,42 @@ pub fn parse(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Err(err) => Err(to_value(err.to_string())),
}
}
/// Process a Javascript object into a JSON string
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();
Ok(to_value(to_string_pretty(&json).expect("")))
let json = obj.to_json().to_string();
Ok(to_value(json))
}
/// Create a new `JSON` object
pub fn create_constructor(global: &Value) -> Value {
let mut json = Object::default();
json.kind = ObjectKind::Ordinary;
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);
let prototype = ValueData::new_obj(Some(global));
make_builtin_fn!(parse, named "parse", with length 2, of prototype);
make_builtin_fn!(stringify, named "stringify", with length 3, of prototype);
to_value(json)
}
#[cfg(test)]
mod tests {
use crate::{exec::Executor, forward, realm::Realm};
let json_value = to_value(json);
json_value.set_field_slice(PROTOTYPE, prototype);
json_value
#[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"
);
}
}

12
boa/src/builtins/value/mod.rs

@ -586,12 +586,12 @@ impl ValueData {
| ValueData::Function(_) => JSONValue::Null,
ValueData::Boolean(b) => JSONValue::Bool(b),
ValueData::Object(ref obj) => {
let mut new_obj = Map::new();
for (k, v) in obj.borrow().internal_slots.iter() {
if k != INSTANCE_PROTOTYPE {
new_obj.insert(k.clone(), v.to_json());
}
}
let new_obj = obj
.borrow()
.properties
.iter()
.map(|(k, _)| (k.clone(), self.get_field_slice(k).to_json()))
.collect::<Map<String, JSONValue>>();
JSONValue::Object(new_obj)
}
ValueData::String(ref str) => JSONValue::String(str.clone()),

Loading…
Cancel
Save