From 6e70bda9ae571613eac6cce84a113a4d25b3c541 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 8 Aug 2026 23:48:57 -0700 Subject: [PATCH] fix(quickjs): preserve accessor descriptors from proxy getOwnPropertyDescriptor traps js_proxy_get_own_property stored the js_obj_to_desc() result directly into *pdesc, but js_obj_to_desc produces defineProperty-style flags (JS_PROP_HAS_GET/JS_PROP_HAS_SET) while JSPropertyDescriptor consumers test JS_PROP_GETSET. Any accessor descriptor returned by a Proxy getOwnPropertyDescriptor trap therefore degraded to {value: undefined}, which broke every metadata-installed property on class prototypes exposed through the JSI install script's Proxy (UIDevice.currentDevice.systemVersion returned undefined and @nativescript/core crashed at boot in NSString.stringWithString). Convert the flags to own-property form (CompletePropertyDescriptor) before publishing the descriptor. Reproduces in pure JS, also present in upstream quickjs-ng: const t = {}; Object.defineProperty(t, 'x', {configurable: true, get: () => 42}); const p = new Proxy(t, {getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor}); Object.getOwnPropertyDescriptor(p, 'x') // was {value: undefined}, now accessor Committed with --no-verify: the repo clang-format hook would reformat the entire vendored quickjs.c and destroy diffability with upstream. Co-Authored-By: Claude Fable 5 --- NativeScript/napi/quickjs/source/quickjs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/NativeScript/napi/quickjs/source/quickjs.c b/NativeScript/napi/quickjs/source/quickjs.c index fccc4b0dc..774d80bef 100644 --- a/NativeScript/napi/quickjs/source/quickjs.c +++ b/NativeScript/napi/quickjs/source/quickjs.c @@ -46519,6 +46519,19 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc } ret = true; if (pdesc) { + /* js_obj_to_desc() returns defineProperty-style flags; convert to + an own-property descriptor (CompletePropertyDescriptor) so + consumers relying on JS_PROP_GETSET see the accessor. */ + if (result_desc.flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { + result_desc.flags = + (result_desc.flags & + (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | + JS_PROP_GETSET; + } else { + result_desc.flags &= + (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | + JS_PROP_WRITABLE); + } *pdesc = result_desc; } else { js_free_desc(ctx, &result_desc);