diff --git a/c/interface.c b/c/interface.c index 5e9fa3ae..32e065c4 100644 --- a/c/interface.c +++ b/c/interface.c @@ -1230,6 +1230,14 @@ typedef enum IsEqualOp { QTS_EqualOp_SameValueZero = 2, } IsEqualOp; +int QTS_IsError(JSContext *ctx, JSValueConst *value) { +#ifdef QTS_USE_QUICKJS_NG + return JS_IsError(*value); +#else + return JS_IsError(ctx, *value); +#endif +} + int QTS_IsEqual(JSContext *ctx, JSValueConst *a, JSValueConst *b, IsEqualOp op) { #ifdef QTS_USE_QUICKJS_NG return -1; diff --git a/packages/quickjs-emscripten-core/src/context.ts b/packages/quickjs-emscripten-core/src/context.ts index 9bc7c8a0..c3b35a56 100644 --- a/packages/quickjs-emscripten-core/src/context.ts +++ b/packages/quickjs-emscripten-core/src/context.ts @@ -1349,43 +1349,223 @@ export class QuickJSContext /** * Dump a JSValue to Javascript in a best-effort fashion. - * If the value is a promise, dumps the promise's state. - * Returns `handle.toString()` if it cannot be serialized to JSON. + * If the value is a promise, dumps the promise's state.. */ dump(handle: QuickJSHandle): any { - this.runtime.assertOwned(handle) - const type = this.typeof(handle) + this.runtime.assertOwned(handle); + const type = this.typeof(handle); if (type === "string") { - return this.getString(handle) + return this.getString(handle); } else if (type === "number") { - return this.getNumber(handle) + return this.getNumber(handle); } else if (type === "bigint") { - return this.getBigInt(handle) + return this.getBigInt(handle); } else if (type === "undefined") { - return undefined + return undefined; + } else if (type === "boolean") { + return this.getNumber(handle) !== 0; } else if (type === "symbol") { - return this.getSymbol(handle) + return this.getSymbol(handle); + } else if (type === "function") { + // Dup the handle so the wrapper function can outlive this scope. + const duppedHandle = this.memory.manage(handle.dup()); + return (...args: any[]) => { + const argHandles = args.map((arg) => this.wrap(arg)); + const result = this.callFunction( + duppedHandle, + this.undefined, + argHandles, + ); + argHandles.forEach((h) => h.dispose()); + if (result.error) { + const err = this.dump(result.error); + result.error.dispose(); + throw err; + } + using retHandle = result.value; + return this.dump(retHandle); + }; } // It's confusing if we dump(promise) and just get back {} because promise // has no properties, so dump promise state. - const asPromiseState = this.getPromiseState(handle) + const asPromiseState = this.getPromiseState(handle); if (asPromiseState.type === "fulfilled" && !asPromiseState.notAPromise) { - handle.dispose() - return { type: asPromiseState.type, value: asPromiseState.value.consume(this.dump) } + handle.dispose(); + return { + type: asPromiseState.type, + value: asPromiseState.value.consume(this.dump), + }; } else if (asPromiseState.type === "pending") { - handle.dispose() - return { type: asPromiseState.type } + handle.dispose(); + return { type: asPromiseState.type }; } else if (asPromiseState.type === "rejected") { - handle.dispose() - return { type: asPromiseState.type, error: asPromiseState.error.consume(this.dump) } + handle.dispose(); + return { + type: asPromiseState.type, + error: asPromiseState.error.consume(this.dump), + }; + } + + // Recursively deserialize objects and arrays instead of using QTS_Dump + + // JSON.parse, which allows dump semantics on nested values. + if (type === "object") { + // getOwnPropertyNames returns an error for null (mirrors JS behavior: + // Object.getOwnPropertyNames(null) throws). + using propsResult = this.getOwnPropertyNames(handle); + if (propsResult.error) { + return null; + } + + // Detect arrays via the constructor name — two cheap property reads, + // no VM function call needed. Then recursively dump array elements. + using ctor = this.getProp(handle, "constructor"); + using ctorName = this.getProp(ctor, "name"); + const ctorNameStr = this.getString(ctorName); + if (ctorNameStr === "Array") { + const len = this.getLength(handle) ?? 0; + const arr: any[] = []; + for (let i = 0; i < len; i++) { + using elem = this.getProp(handle, i); + arr.push(this.dump(elem)); + } + return arr; + } + + // Recursively dump enumerable own properties + using props = propsResult.value; + const obj: Record = {}; + const enumerableKeys = new Set(); + for (const key of props) { + const keyStr = this.getString(key); + enumerableKeys.add(keyStr); + using val = this.getProp(handle, key); + obj[keyStr] = this.dump(val); + } + + // For Error objects, also extract non-enumerable error properties + // (name, message, stack, etc.) that getOwnPropertyNames wouldn't include. + const isError = this.ffi.QTS_IsError(this.ctx.value, handle.value) === 1; + if (isError) { + for (const propName of ["name", "message", "stack", "fileName", "lineNumber"]) { + if (!enumerableKeys.has(propName)) { + using val = this.getProp(handle, propName); + if (this.typeof(val) !== "undefined") { + obj[propName] = this.dump(val); + } + } + } + } + + return obj; } - const str = this.memory.consumeJSCharPointer(this.ffi.QTS_Dump(this.ctx.value, handle.value)) + // Fallback for any unrecognised type. + const str = this.memory.consumeJSCharPointer( + this.ffi.QTS_Dump(this.ctx.value, handle.value), + ); try { - return JSON.parse(str) - } catch (err) { - return str + return JSON.parse(str); + } catch { + return str; + } + } + + /** + * Marshal a JS value to QuickJS. Conceptually the opposite of {@link dump} + * @param value any JS value + * @returns The correct QuickJSHandle + */ + wrap(value: any): QuickJSHandle { + if (value === undefined) { + return this.undefined; + } else if (value === null) { + return this.null; + } else if (typeof value === "boolean") { + return value ? this.true : this.false; + } else if (typeof value === "number") { + return this.newNumber(value); + } else if (typeof value === "string") { + return this.newString(value); + } else if (typeof value === "bigint") { + return this.newBigInt(value); + } else if (typeof value === "symbol") { + const key = Symbol.keyFor(value); + return key !== undefined ? this.newSymbolFor(key) : this.newUniqueSymbol(value); + } else if (typeof value === "object") { + if (value instanceof Set) { + using setCtor = this.getProp(this.global, "Set"); + using reflect = this.getProp(this.global, "Reflect"); + using reflectConstruct = this.getProp(reflect, "construct"); + using emptyArgs = this.newArray(); + // No `using` here — ownership transfers to the caller via `return` + const vmSetInstance = this + .callFunction(reflectConstruct, reflect, setCtor, emptyArgs) + .unwrap(); + + for (const val of value) { + using elemHandle = this.wrap(val); + using _addResult = this + .callMethod(vmSetInstance, "add", [elemHandle]) + .unwrap(); + } + return vmSetInstance; + } + + if (value instanceof Map) { + using mapCtor = this.getProp(this.global, "Map"); + using reflect = this.getProp(this.global, "Reflect"); + using reflectConstruct = this.getProp(reflect, "construct"); + using emptyArgs = this.newArray(); + // No `using` here — ownership transfers to the caller via `return` + const vmMapInstance = this + .callFunction(reflectConstruct, reflect, mapCtor, emptyArgs) + .unwrap(); + + for (const [k, v] of value) { + using keyHandle = this.wrap(k); + using valHandle = this.wrap(v); + using _setResult = this + .callMethod(vmMapInstance, "set", [keyHandle, valHandle]) + .unwrap(); + } + return vmMapInstance; + } + + if (value instanceof Date) { + using dateCtor = this.getProp(this.global, "Date"); + using reflect = this.getProp(this.global, "Reflect"); + using reflectConstruct = this.getProp(reflect, "construct"); + using argsArray = this.newArray(); + using timestampHandle = this.newNumber(value.getTime()); + this.setProp(argsArray, 0, timestampHandle); + return this + .callFunction(reflectConstruct, reflect, dateCtor, argsArray) + .unwrap(); + } + + if (value instanceof ArrayBuffer) { + return this.newArrayBuffer(value); + } + + if (Array.isArray(value)) { + const arrHandle = this.newArray(); + value.forEach((elem, index) => { + using elemHandle = this.wrap(elem); + this.setProp(arrHandle, index, elemHandle); + }); + return arrHandle; + } + + // Plain object — recursively wrap enumerable own properties + const objHandle = this.newObject(); + for (const [key, val] of Object.entries(value)) { + using propHandle = this.wrap(val); + this.setProp(objHandle, key, propHandle); + } + return objHandle; + } else { + return this.undefined; } } diff --git a/packages/quickjs-emscripten/src/quickjs.test.ts b/packages/quickjs-emscripten/src/quickjs.test.ts index f603c256..0c800ccc 100644 --- a/packages/quickjs-emscripten/src/quickjs.test.ts +++ b/packages/quickjs-emscripten/src/quickjs.test.ts @@ -211,6 +211,138 @@ function contextTests(getContext: GetTestContext, options: ContextTestOptions = it("can round-trip null", () => { assert.strictEqual(vm.dump(vm.null), null) }) + + it("can dump a function", () => { + const fnHandle = vm.unwrapResult(vm.evalCode("(function add(a, b) { return a + b })")) + const fn = vm.dump(fnHandle) as (...args: any[]) => any + fnHandle.dispose() + + const result = fn(3, 7) + assert.strictEqual(result, 10) + }) + }) + + describe(".wrap", () => { + it("wraps undefined", () => { + using handle = vm.wrap(undefined) + assert.strictEqual(vm.dump(handle), undefined) + }) + + it("wraps null", () => { + using handle = vm.wrap(null) + assert.strictEqual(vm.dump(handle), null) + }) + + it("wraps true", () => { + using handle = vm.wrap(true) + assert.strictEqual(vm.dump(handle), true) + }) + + it("wraps false", () => { + using handle = vm.wrap(false) + assert.strictEqual(vm.dump(handle), false) + }) + + it("wraps a number", () => { + using handle = vm.wrap(42) + assert.strictEqual(vm.dump(handle), 42) + }) + + it("wraps a string", () => { + using handle = vm.wrap("hello world 🌍") + assert.strictEqual(vm.dump(handle), "hello world 🌍") + }) + + it("wraps a bigint", () => { + using handle = vm.wrap(2n ** 64n) + assert.strictEqual(vm.dump(handle), 2n ** 64n) + }) + + it("wraps a global symbol", () => { + const sym = Symbol.for("myGlobalSym") + using handle = vm.wrap(sym) + assert.strictEqual(vm.typeof(handle), "symbol") + assert.strictEqual(vm.getSymbol(handle), sym) + }) + + it("wraps a unique symbol (preserves description)", () => { + const sym = Symbol("mySym") + using handle = vm.wrap(sym) + assert.strictEqual(vm.typeof(handle), "symbol") + const result = vm.getSymbol(handle) + assert.strictEqual(result.description, sym.description) + assert.notStrictEqual(result, sym) + }) + + it("wraps a plain object", () => { + using handle = vm.wrap({ a: 1, b: "two" }) + const dumped = vm.dump(handle) + assert.deepEqual(dumped, { a: 1, b: "two" }) + }) + + it("wraps a nested object", () => { + using handle = vm.wrap({ x: { y: { z: 42 } } }) + const dumped = vm.dump(handle) + assert.deepEqual(dumped, { x: { y: { z: 42 } } }) + }) + + it("wraps an array", () => { + using handle = vm.wrap([1, 2, 3]) + const dumped = vm.dump(handle) + assert.deepEqual(dumped, [1, 2, 3]) + }) + + it("wraps a nested array", () => { + using handle = vm.wrap([[1, 2], [3, 4]]) + const dumped = vm.dump(handle) + assert.deepEqual(dumped, [[1, 2], [3, 4]]) + }) + + it("wraps an object with array values", () => { + using handle = vm.wrap({ nums: [10, 20], flag: true }) + const dumped = vm.dump(handle) + assert.deepEqual(dumped, { nums: [10, 20], flag: true }) + }) + + it("wraps a Set", () => { + using handle = vm.wrap(new Set([1, 2, 3])) + using sizeHandle = vm.getProp(handle, "size") + assert.strictEqual(vm.dump(sizeHandle), 3) + using hasFn = vm.getProp(handle, "has") + using twoHandle = vm.newNumber(2) + using hasResult = vm.callFunction(hasFn, handle, twoHandle).unwrap() + assert.strictEqual(vm.dump(hasResult), true) + }) + + it("wraps a Map", () => { + using handle = vm.wrap(new Map([["a", 1], ["b", 2]])) + using sizeHandle = vm.getProp(handle, "size") + assert.strictEqual(vm.dump(sizeHandle), 2) + using getFn = vm.getProp(handle, "get") + using keyHandle = vm.newString("a") + using valHandle = vm.callFunction(getFn, handle, keyHandle).unwrap() + assert.strictEqual(vm.dump(valHandle), 1) + }) + + it("wraps a Date", () => { + const ts = 1_700_000_000_000 + using handle = vm.wrap(new Date(ts)) + using getTimeFn = vm.getProp(handle, "getTime") + using result = vm.callFunction(getTimeFn, handle).unwrap() + assert.strictEqual(vm.dump(result), ts) + }) + + it("wraps an ArrayBuffer", () => { + const bytes = new Uint8Array([10, 20, 30, 40]) + using handle = vm.wrap(bytes.buffer) + using byteLengthHandle = vm.getProp(handle, "byteLength") + assert.strictEqual(vm.dump(byteLengthHandle), 4) + }) + + it("falls back to undefined for unrecognised types", () => { + using handle = vm.wrap(() => 42) + assert.strictEqual(vm.dump(handle), undefined) + }) }) describe( @@ -827,34 +959,6 @@ export default "the default"; assert.strictEqual(dumped.name, "CustomName") assert.strictEqual(dumped.message, "CustomMessage") }) - - it("returns informative fallback when serialization fails due to memory limit", () => { - // Use a memory limit that allows object creation but fails during JSON serialization - vm.runtime.setMemoryLimit(1024 * 200) // 200KB - - // Create an object that's too large to serialize - const result = vm.evalCode(` - const big = {}; - for (let i = 0; i < 5000; i++) big['key' + i] = 'value' + i; - big; - `) - - if (result.error) { - // OOM during eval is acceptable - remove limit and clean up - vm.runtime.setMemoryLimit(-1) - result.error.dispose() - return - } - - const dumped = vm.dump(result.value) - result.value.dispose() - vm.runtime.setMemoryLimit(-1) // Remove limit for cleanup - - // Format: JS_PrintValue output + "\n---\nnot JSON serializable: ${error}" - assert(typeof dumped === "string", "fallback should be a string") - assert(dumped.includes("---"), "should include separator") - assert(dumped.includes("not JSON serializable"), "should include error context") - }) }) describe(".typeof", () => { diff --git a/packages/quickjs-ffi-types/src/ffi-async.ts b/packages/quickjs-ffi-types/src/ffi-async.ts index e3aa0ad6..7c7a355b 100644 --- a/packages/quickjs-ffi-types/src/ffi-async.ts +++ b/packages/quickjs-ffi-types/src/ffi-async.ts @@ -225,6 +225,7 @@ export interface QuickJSAsyncFFI { out_len: UInt32Pointer, value: JSValuePointer | JSValueConstPointer, ) => number + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/quickjs-ffi-types/src/ffi.ts b/packages/quickjs-ffi-types/src/ffi.ts index bf9e02c6..99886250 100644 --- a/packages/quickjs-ffi-types/src/ffi.ts +++ b/packages/quickjs-ffi-types/src/ffi.ts @@ -173,6 +173,7 @@ export interface QuickJSFFI { out_len: UInt32Pointer, value: JSValuePointer | JSValueConstPointer, ) => number + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-asmjs-mjs-release-sync/src/ffi.ts b/packages/variant-quickjs-asmjs-mjs-release-sync/src/ffi.ts index 17e6ccac..154eb9ae 100644 --- a/packages/variant-quickjs-asmjs-mjs-release-sync/src/ffi.ts +++ b/packages/variant-quickjs-asmjs-mjs-release-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-ng-wasmfile-debug-asyncify/src/ffi.ts b/packages/variant-quickjs-ng-wasmfile-debug-asyncify/src/ffi.ts index a154293f..4f17b981 100644 --- a/packages/variant-quickjs-ng-wasmfile-debug-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-ng-wasmfile-debug-asyncify/src/ffi.ts @@ -444,6 +444,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-ng-wasmfile-debug-sync/src/ffi.ts b/packages/variant-quickjs-ng-wasmfile-debug-sync/src/ffi.ts index 6740134d..6eafa4e9 100644 --- a/packages/variant-quickjs-ng-wasmfile-debug-sync/src/ffi.ts +++ b/packages/variant-quickjs-ng-wasmfile-debug-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-ng-wasmfile-release-asyncify/src/ffi.ts b/packages/variant-quickjs-ng-wasmfile-release-asyncify/src/ffi.ts index e89c9b41..6b415bee 100644 --- a/packages/variant-quickjs-ng-wasmfile-release-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-ng-wasmfile-release-asyncify/src/ffi.ts @@ -441,6 +441,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-ng-wasmfile-release-sync/src/ffi.ts b/packages/variant-quickjs-ng-wasmfile-release-sync/src/ffi.ts index 17e6ccac..154eb9ae 100644 --- a/packages/variant-quickjs-ng-wasmfile-release-sync/src/ffi.ts +++ b/packages/variant-quickjs-ng-wasmfile-release-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-browser-debug-asyncify/src/ffi.ts b/packages/variant-quickjs-singlefile-browser-debug-asyncify/src/ffi.ts index a154293f..4f17b981 100644 --- a/packages/variant-quickjs-singlefile-browser-debug-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-browser-debug-asyncify/src/ffi.ts @@ -444,6 +444,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-browser-debug-sync/src/ffi.ts b/packages/variant-quickjs-singlefile-browser-debug-sync/src/ffi.ts index 6740134d..6eafa4e9 100644 --- a/packages/variant-quickjs-singlefile-browser-debug-sync/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-browser-debug-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-browser-release-asyncify/src/ffi.ts b/packages/variant-quickjs-singlefile-browser-release-asyncify/src/ffi.ts index e89c9b41..6b415bee 100644 --- a/packages/variant-quickjs-singlefile-browser-release-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-browser-release-asyncify/src/ffi.ts @@ -441,6 +441,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-browser-release-sync/src/ffi.ts b/packages/variant-quickjs-singlefile-browser-release-sync/src/ffi.ts index 17e6ccac..154eb9ae 100644 --- a/packages/variant-quickjs-singlefile-browser-release-sync/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-browser-release-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-cjs-debug-asyncify/src/ffi.ts b/packages/variant-quickjs-singlefile-cjs-debug-asyncify/src/ffi.ts index a154293f..4f17b981 100644 --- a/packages/variant-quickjs-singlefile-cjs-debug-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-cjs-debug-asyncify/src/ffi.ts @@ -444,6 +444,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-cjs-debug-sync/src/ffi.ts b/packages/variant-quickjs-singlefile-cjs-debug-sync/src/ffi.ts index 6740134d..6eafa4e9 100644 --- a/packages/variant-quickjs-singlefile-cjs-debug-sync/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-cjs-debug-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-cjs-release-asyncify/src/ffi.ts b/packages/variant-quickjs-singlefile-cjs-release-asyncify/src/ffi.ts index e89c9b41..6b415bee 100644 --- a/packages/variant-quickjs-singlefile-cjs-release-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-cjs-release-asyncify/src/ffi.ts @@ -441,6 +441,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-cjs-release-sync/src/ffi.ts b/packages/variant-quickjs-singlefile-cjs-release-sync/src/ffi.ts index 17e6ccac..154eb9ae 100644 --- a/packages/variant-quickjs-singlefile-cjs-release-sync/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-cjs-release-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-mjs-debug-asyncify/src/ffi.ts b/packages/variant-quickjs-singlefile-mjs-debug-asyncify/src/ffi.ts index a154293f..4f17b981 100644 --- a/packages/variant-quickjs-singlefile-mjs-debug-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-mjs-debug-asyncify/src/ffi.ts @@ -444,6 +444,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-mjs-debug-sync/src/ffi.ts b/packages/variant-quickjs-singlefile-mjs-debug-sync/src/ffi.ts index 6740134d..6eafa4e9 100644 --- a/packages/variant-quickjs-singlefile-mjs-debug-sync/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-mjs-debug-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-mjs-release-asyncify/src/ffi.ts b/packages/variant-quickjs-singlefile-mjs-release-asyncify/src/ffi.ts index e89c9b41..6b415bee 100644 --- a/packages/variant-quickjs-singlefile-mjs-release-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-mjs-release-asyncify/src/ffi.ts @@ -441,6 +441,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-singlefile-mjs-release-sync/src/ffi.ts b/packages/variant-quickjs-singlefile-mjs-release-sync/src/ffi.ts index 17e6ccac..154eb9ae 100644 --- a/packages/variant-quickjs-singlefile-mjs-release-sync/src/ffi.ts +++ b/packages/variant-quickjs-singlefile-mjs-release-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-wasmfile-debug-asyncify/src/ffi.ts b/packages/variant-quickjs-wasmfile-debug-asyncify/src/ffi.ts index a154293f..4f17b981 100644 --- a/packages/variant-quickjs-wasmfile-debug-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-wasmfile-debug-asyncify/src/ffi.ts @@ -444,6 +444,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-wasmfile-debug-sync/src/ffi.ts b/packages/variant-quickjs-wasmfile-debug-sync/src/ffi.ts index 6740134d..6eafa4e9 100644 --- a/packages/variant-quickjs-wasmfile-debug-sync/src/ffi.ts +++ b/packages/variant-quickjs-wasmfile-debug-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-wasmfile-release-asyncify/src/ffi.ts b/packages/variant-quickjs-wasmfile-release-asyncify/src/ffi.ts index e89c9b41..6b415bee 100644 --- a/packages/variant-quickjs-wasmfile-release-asyncify/src/ffi.ts +++ b/packages/variant-quickjs-wasmfile-release-asyncify/src/ffi.ts @@ -441,6 +441,9 @@ export class QuickJSAsyncFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer, diff --git a/packages/variant-quickjs-wasmfile-release-sync/src/ffi.ts b/packages/variant-quickjs-wasmfile-release-sync/src/ffi.ts index 17e6ccac..154eb9ae 100644 --- a/packages/variant-quickjs-wasmfile-release-sync/src/ffi.ts +++ b/packages/variant-quickjs-wasmfile-release-sync/src/ffi.ts @@ -337,6 +337,9 @@ export class QuickJSFFI { value: JSValuePointer | JSValueConstPointer, ) => number = this.module.cwrap("QTS_GetLength", "number", ["number", "number", "number"]) + QTS_IsError: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number = + this.module.cwrap("QTS_IsError", "number", ["number", "number"]) + QTS_IsEqual: ( ctx: JSContextPointer, a: JSValuePointer | JSValueConstPointer,