Browse Source

Add Object.defineProperties and handle props argument in Object.create (#746)

pull/806/head
David 4 years ago committed by GitHub
parent
commit
fb1b8d5595
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 48
      boa/src/builtins/object/mod.rs
  2. 19
      boa/src/builtins/object/tests.rs
  3. 39
      boa/src/object/internal_methods.rs

48
boa/src/builtins/object/mod.rs

@ -53,6 +53,7 @@ impl BuiltIn for Object {
.static_method(Self::set_prototype_of, "setPrototypeOf", 2)
.static_method(Self::get_prototype_of, "getPrototypeOf", 1)
.static_method(Self::define_property, "defineProperty", 3)
.static_method(Self::define_properties, "defineProperties", 2)
.static_method(Self::is, "is", 2)
.build();
@ -84,24 +85,28 @@ impl Object {
///
/// [spec]: https://tc39.es/ecma262/#sec-object.create
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
pub fn create(_: &Value, args: &[Value], interpreter: &mut Context) -> Result<Value> {
pub fn create(_: &Value, args: &[Value], ctx: &mut Context) -> Result<Value> {
let prototype = args.get(0).cloned().unwrap_or_else(Value::undefined);
let properties = args.get(1).cloned().unwrap_or_else(Value::undefined);
if properties != Value::Undefined {
unimplemented!("propertiesObject argument of Object.create")
}
match prototype {
Value::Object(_) | Value::Null => Ok(Value::object(BuiltinObject::with_prototype(
let obj = match prototype {
Value::Object(_) | Value::Null => Value::object(BuiltinObject::with_prototype(
prototype,
ObjectData::Ordinary,
))),
_ => interpreter.throw_type_error(format!(
"Object prototype may only be an Object or null: {}",
prototype.display()
)),
_ => {
return ctx.throw_type_error(format!(
"Object prototype may only be an Object or null: {}",
prototype.display()
))
}
};
if !properties.is_undefined() {
return Object::define_properties(&Value::Undefined, &[obj, properties], ctx);
}
Ok(obj)
}
/// Uses the SameValue algorithm to check equality of objects
@ -140,6 +145,27 @@ impl Object {
Ok(Value::undefined())
}
/// `Object.defineProperties( proto, [propertiesObject] )`
///
/// Creates or update own properties to the object
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-object.defineproperties
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties
pub fn define_properties(_: &Value, args: &[Value], ctx: &mut Context) -> Result<Value> {
let arg = args.get(0).cloned().unwrap_or(Value::undefined());
let arg_obj = arg.as_object_mut();
if let Some(mut obj) = arg_obj {
let props = args.get(1).cloned().unwrap_or_else(Value::undefined);
obj.define_properties(props, ctx)?;
Ok(arg.clone())
} else {
ctx.throw_type_error("Expected an object")
}
}
/// `Object.prototype.toString()`
///
/// This method returns a string representing the object.

19
boa/src/builtins/object/tests.rs

@ -194,3 +194,22 @@ fn define_symbol_property() {
assert_eq!(forward(&mut ctx, "obj[sym]"), "\"val\"");
}
#[test]
fn object_define_properties() {
let mut ctx = Context::new();
let init = r#"
const obj = {};
Object.defineProperties(obj, {
p: {
value: 42,
writable: true
}
});
"#;
eprintln!("{}", forward(&mut ctx, init));
assert_eq!(forward(&mut ctx, "obj.p"), "42");
}

39
boa/src/object/internal_methods.rs

@ -9,7 +9,7 @@ use crate::{
object::Object,
property::{Attribute, Property, PropertyKey},
value::{same_value, Value},
BoaProfiler,
BoaProfiler, Context, Result,
};
impl Object {
@ -282,6 +282,43 @@ impl Object {
})
}
/// Essential internal method OwnPropertyKeys
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec](https://tc39.es/ecma262/#table-essential-internal-methods)
pub fn own_property_keys(&self) -> Vec<PropertyKey> {
self.keys().collect()
}
/// The abstract operation ObjectDefineProperties
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-object.defineproperties
pub fn define_properties(&mut self, props: Value, ctx: &mut Context) -> Result<()> {
let props = props.to_object(ctx)?;
let keys = props.borrow().own_property_keys();
let mut descriptors: Vec<(PropertyKey, Property)> = Vec::new();
for next_key in keys {
let prop_desc = props.borrow().get_own_property(&next_key);
if prop_desc.enumerable() {
let desc_obj = props.borrow().get(&next_key);
let desc = Property::from(&desc_obj);
descriptors.push((next_key, desc));
}
}
descriptors.into_iter().for_each(|(p, d)| {
self.define_own_property(p, d);
});
Ok(())
}
// /// `Object.setPropertyOf(obj, prototype)`
// ///
// /// This method sets the prototype (i.e., the internal `[[Prototype]]` property)

Loading…
Cancel
Save