diff --git a/ChangeLog b/ChangeLog index 81a1afebbe..eb312fd221 100644 --- a/ChangeLog +++ b/ChangeLog @@ -45,6 +45,7 @@ Bangle.js2: Fix regression in E.showMenu so you can use menu items with ':undefined' (as in the example in the reference) Graphics: Ensure that an error is thrown if a palette is used in >8 bit images. It was previously possible to ask for a palette on a 32 bit image, which caused an overflow Fix issue extending a class from a class from a class (fix #1529) + Added Object.getOwnPropertyDescriptors 2v16 : JIT functions now execute in their own function scope (allows arguments) Move older 'HY' boards to use `g` for the built-in graphics, not `LCD` (and change docs) diff --git a/src/jswrap_object.c b/src/jswrap_object.c index 9ad2e72c84..464e1e0ee8 100644 --- a/src/jswrap_object.c +++ b/src/jswrap_object.c @@ -441,6 +441,50 @@ JsVar *jswrap_object_getOwnPropertyDescriptor(JsVar *parent, JsVar *name) { return obj; } +/*JSON{ + "type" : "staticmethod", + "class" : "Object", + "name" : "getOwnPropertyDescriptors", + "ifndef" : "SAVE_ON_FLASH", + "generate" : "jswrap_object_getOwnPropertyDescriptors", + "params" : [ + ["obj","JsVar","The object"] + ], + "return" : ["JsVar","An object containing all the property descriptors of an object"] +} +Get information on all properties in the object (from `Object.getOwnPropertyDescriptor`), or just `{}` if no properties + */ +JsVar *jswrap_object_getOwnPropertyDescriptors(JsVar *parent) { + if (!jsvHasChildren(parent)) { + jsExceptionHere(JSET_TYPEERROR, "First argument must be an object, got %t", parent); + return 0; + } + JsVar *descriptors = jsvNewObject(); + if (!descriptors) return 0; + + /* There is some code mentioned at https://github.com/espruino/Espruino/issues/1302#issuecomment-1430833414 + + const protoPropDescriptor = Object.getOwnPropertyDescriptor(obj, '__proto__'); + const descriptors = protoPropDescriptor ? { ['__proto__']: protoPropDescriptor } : {}; + + which we're not implementing here - but I think the current implementation is fine for 99% of cases + */ + + JsVar *ownPropertyNames = jswrap_object_keys_or_property_names(parent, JSWOKPF_INCLUDE_NON_ENUMERABLE); + JsvObjectIterator it; + jsvObjectIteratorNew(&it, ownPropertyNames); + while (jsvObjectIteratorHasValue(&it)) { + JsVar *propName = jsvObjectIteratorGetValue(&it); + JsVar *propValue = jswrap_object_getOwnPropertyDescriptor(parent, propName); + jsvObjectSetChildVar(descriptors, propName, propValue); + jsvUnLock2(propName, propValue); + jsvObjectIteratorNext(&it); + } + jsvObjectIteratorFree(&it); + jsvUnLock(ownPropertyNames); + return descriptors; +} + /*JSON{ "type" : "method", "class" : "Object", diff --git a/src/jswrap_object.h b/src/jswrap_object.h index 2093b95f95..7974affcb2 100644 --- a/src/jswrap_object.h +++ b/src/jswrap_object.h @@ -43,6 +43,7 @@ JsVar *jswrap_object_keys_or_property_names( JsVar *jswrap_object_values_or_entries(JsVar *object, bool returnEntries); JsVar *jswrap_object_create(JsVar *proto, JsVar *propertiesObject); JsVar *jswrap_object_getOwnPropertyDescriptor(JsVar *parent, JsVar *name); +JsVar *jswrap_object_getOwnPropertyDescriptors(JsVar *parent); bool jswrap_object_hasOwnProperty(JsVar *parent, JsVar *name); JsVar *jswrap_object_defineProperty(JsVar *parent, JsVar *propName, JsVar *desc); JsVar *jswrap_object_defineProperties(JsVar *parent, JsVar *props); diff --git a/tests/test_object_getOwnPropertyDescriptors.js b/tests/test_object_getOwnPropertyDescriptors.js new file mode 100644 index 0000000000..8f0f9ab6a0 --- /dev/null +++ b/tests/test_object_getOwnPropertyDescriptors.js @@ -0,0 +1,19 @@ +var A = { + b : 42, + c : function() {} +}; + +class B { +}; + + +var r = [ + // [JSON.stringify(Object.getOwnPropertyDescriptors(A)),'{"b":{"writable":true,"enumerable":true,"configurable":true,"value":42},"c":{"writable":true,"enumerable":true,"configurable":true}}'], + // this one is not correct as it seems V8 adds 'length' and 'name' fields to classes + //[JSON.stringify(Object.getOwnPropertyDescriptors(B)),"{\"prototype\":{\"writable\":true,\"enumerable\":true,\"configurable\":true,\"value\":{}}}"] +]; + +//console.log(r); + +result = r.every(a => a[0]==a[1]); +