quickjs-emscripten-sync 1.3.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -37
- package/dist/index.d.ts +29 -22
- package/dist/quickjs-emscripten-sync.mjs +842 -0
- package/dist/quickjs-emscripten-sync.umd.js +15 -15
- package/package.json +12 -21
- package/src/default.ts +2 -2
- package/src/index.test.ts +159 -65
- package/src/index.ts +67 -66
- package/src/marshal/custom.test.ts +50 -0
- package/src/marshal/custom.ts +36 -0
- package/src/marshal/function.test.ts +60 -72
- package/src/marshal/function.ts +15 -18
- package/src/marshal/index.test.ts +88 -84
- package/src/marshal/index.ts +16 -18
- package/src/marshal/json.test.ts +32 -38
- package/src/marshal/json.ts +5 -7
- package/src/marshal/object.test.ts +52 -79
- package/src/marshal/object.ts +8 -15
- package/src/marshal/primitive.test.ts +16 -21
- package/src/marshal/primitive.ts +11 -10
- package/src/marshal/promise.test.ts +21 -22
- package/src/marshal/promise.ts +6 -13
- package/src/marshal/properties.test.ts +21 -26
- package/src/marshal/properties.ts +15 -17
- package/src/unmarshal/custom.test.ts +50 -0
- package/src/unmarshal/custom.ts +31 -0
- package/src/unmarshal/function.test.ts +52 -74
- package/src/unmarshal/function.ts +13 -22
- package/src/unmarshal/index.test.ts +58 -50
- package/src/unmarshal/index.ts +12 -13
- package/src/unmarshal/object.test.ts +37 -43
- package/src/unmarshal/object.ts +16 -20
- package/src/unmarshal/primitive.test.ts +15 -15
- package/src/unmarshal/primitive.ts +11 -18
- package/src/unmarshal/promise.test.ts +13 -13
- package/src/unmarshal/promise.ts +10 -19
- package/src/unmarshal/properties.test.ts +8 -8
- package/src/unmarshal/properties.ts +44 -45
- package/src/util.test.ts +2 -7
- package/src/util.ts +3 -8
- package/src/vmmap.test.ts +72 -88
- package/src/vmmap.ts +26 -44
- package/src/vmutil.test.ts +73 -89
- package/src/vmutil.ts +24 -47
- package/src/wrapper.test.ts +108 -148
- package/src/wrapper.ts +59 -62
- package/dist/quickjs-emscripten-sync.es.js +0 -951
- package/src/marshal/symbol.test.ts +0 -24
- package/src/marshal/symbol.ts +0 -20
- package/src/unmarshal/symbol.test.ts +0 -25
- package/src/unmarshal/symbol.ts +0 -12
|
@@ -4,15 +4,12 @@ import { expect, test, vi } from "vitest";
|
|
|
4
4
|
import unmarshalObject from "./object";
|
|
5
5
|
|
|
6
6
|
test("normal object", async () => {
|
|
7
|
-
const
|
|
8
|
-
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
9
|
-
|
|
10
|
-
false,
|
|
11
|
-
]);
|
|
12
|
-
const preUnmarshal = vi.fn((a) => a);
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [ctx.dump(v), false]);
|
|
9
|
+
const preUnmarshal = vi.fn(a => a);
|
|
13
10
|
|
|
14
|
-
const handle =
|
|
15
|
-
const obj = unmarshalObject(
|
|
11
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`({ a: 1, b: true })`));
|
|
12
|
+
const obj = unmarshalObject(ctx, handle, unmarshal, preUnmarshal);
|
|
16
13
|
if (!obj) throw new Error("obj is undefined");
|
|
17
14
|
expect(obj).toEqual({ a: 1, b: true });
|
|
18
15
|
expect(unmarshal).toReturnTimes(4);
|
|
@@ -24,20 +21,20 @@ test("normal object", async () => {
|
|
|
24
21
|
expect(preUnmarshal).toBeCalledWith(obj, handle);
|
|
25
22
|
|
|
26
23
|
handle.dispose();
|
|
27
|
-
|
|
24
|
+
ctx.dispose();
|
|
28
25
|
});
|
|
29
26
|
|
|
30
27
|
test("properties", async () => {
|
|
31
|
-
const
|
|
28
|
+
const ctx = (await getQuickJS()).newContext();
|
|
32
29
|
const disposables: QuickJSHandle[] = [];
|
|
33
30
|
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
34
31
|
disposables.push(v);
|
|
35
|
-
return [
|
|
32
|
+
return [ctx.typeof(v) === "function" ? () => {} : ctx.dump(v), false];
|
|
36
33
|
});
|
|
37
|
-
const preUnmarshal = vi.fn(
|
|
34
|
+
const preUnmarshal = vi.fn(a => a);
|
|
38
35
|
|
|
39
|
-
const handle =
|
|
40
|
-
|
|
36
|
+
const handle = ctx.unwrapResult(
|
|
37
|
+
ctx.evalCode(`{
|
|
41
38
|
const obj = {};
|
|
42
39
|
Object.defineProperties(obj, {
|
|
43
40
|
a: { value: 1, writable: true, configurable: true, enumerable: true },
|
|
@@ -45,9 +42,9 @@ test("properties", async () => {
|
|
|
45
42
|
c: { get: () => {}, set: () => {} },
|
|
46
43
|
});
|
|
47
44
|
obj
|
|
48
|
-
}`)
|
|
45
|
+
}`),
|
|
49
46
|
);
|
|
50
|
-
const obj = unmarshalObject(
|
|
47
|
+
const obj = unmarshalObject(ctx, handle, unmarshal, preUnmarshal);
|
|
51
48
|
if (!obj) throw new Error("obj is undefined");
|
|
52
49
|
expect(obj).toEqual({
|
|
53
50
|
a: 1,
|
|
@@ -72,21 +69,18 @@ test("properties", async () => {
|
|
|
72
69
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
73
70
|
expect(preUnmarshal).toBeCalledWith(obj, handle);
|
|
74
71
|
|
|
75
|
-
disposables.forEach(
|
|
72
|
+
disposables.forEach(d => d.dispose());
|
|
76
73
|
handle.dispose();
|
|
77
|
-
|
|
74
|
+
ctx.dispose();
|
|
78
75
|
});
|
|
79
76
|
|
|
80
77
|
test("array", async () => {
|
|
81
|
-
const
|
|
82
|
-
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
83
|
-
|
|
84
|
-
false,
|
|
85
|
-
]);
|
|
86
|
-
const preUnmarshal = vi.fn((a) => a);
|
|
78
|
+
const ctx = (await getQuickJS()).newContext();
|
|
79
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [ctx.dump(v), false]);
|
|
80
|
+
const preUnmarshal = vi.fn(a => a);
|
|
87
81
|
|
|
88
|
-
const handle =
|
|
89
|
-
const array = unmarshalObject(
|
|
82
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`[1, true, "a"]`));
|
|
83
|
+
const array = unmarshalObject(ctx, handle, unmarshal, preUnmarshal);
|
|
90
84
|
expect((array as any)[0]).toEqual(1);
|
|
91
85
|
expect(Array.isArray(array)).toBe(true);
|
|
92
86
|
expect(unmarshal.mock.results[0].value).toEqual(["0", false]);
|
|
@@ -100,19 +94,19 @@ test("array", async () => {
|
|
|
100
94
|
expect(preUnmarshal).toBeCalledWith(array, handle);
|
|
101
95
|
|
|
102
96
|
handle.dispose();
|
|
103
|
-
|
|
97
|
+
ctx.dispose();
|
|
104
98
|
});
|
|
105
99
|
|
|
106
100
|
test("prototype", async () => {
|
|
107
|
-
const
|
|
101
|
+
const ctx = (await getQuickJS()).newContext();
|
|
108
102
|
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
109
|
-
|
|
103
|
+
ctx.typeof(v) === "object" ? { a: () => 1 } : ctx.dump(v),
|
|
110
104
|
false,
|
|
111
105
|
]);
|
|
112
|
-
const preUnmarshal = vi.fn(
|
|
106
|
+
const preUnmarshal = vi.fn(a => a);
|
|
113
107
|
|
|
114
|
-
const handle =
|
|
115
|
-
const obj = unmarshalObject(
|
|
108
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`Object.create({ a: () => 1 })`));
|
|
109
|
+
const obj = unmarshalObject(ctx, handle, unmarshal, preUnmarshal) as any;
|
|
116
110
|
if (!obj) throw new Error("obj is undefined");
|
|
117
111
|
expect(Object.getPrototypeOf(obj)).toEqual({ a: expect.any(Function) });
|
|
118
112
|
expect(obj.a()).toBe(1);
|
|
@@ -122,25 +116,25 @@ test("prototype", async () => {
|
|
|
122
116
|
expect(preUnmarshal).toBeCalledWith(obj, handle);
|
|
123
117
|
|
|
124
118
|
handle.dispose();
|
|
125
|
-
|
|
119
|
+
ctx.dispose();
|
|
126
120
|
});
|
|
127
121
|
|
|
128
122
|
test("undefined", async () => {
|
|
129
|
-
const
|
|
123
|
+
const ctx = (await getQuickJS()).newContext();
|
|
130
124
|
const f = vi.fn();
|
|
131
125
|
|
|
132
|
-
expect(unmarshalObject(
|
|
133
|
-
expect(unmarshalObject(
|
|
134
|
-
expect(unmarshalObject(
|
|
135
|
-
expect(unmarshalObject(
|
|
136
|
-
expect(unmarshalObject(
|
|
137
|
-
expect(unmarshalObject(
|
|
126
|
+
expect(unmarshalObject(ctx, ctx.undefined, f, f)).toEqual(undefined);
|
|
127
|
+
expect(unmarshalObject(ctx, ctx.true, f, f)).toEqual(undefined);
|
|
128
|
+
expect(unmarshalObject(ctx, ctx.false, f, f)).toEqual(undefined);
|
|
129
|
+
expect(unmarshalObject(ctx, ctx.null, f, f)).toEqual(undefined);
|
|
130
|
+
expect(unmarshalObject(ctx, ctx.newString("hoge"), f, f)).toEqual(undefined);
|
|
131
|
+
expect(unmarshalObject(ctx, ctx.newNumber(-10), f, f)).toEqual(undefined);
|
|
138
132
|
|
|
139
|
-
const func =
|
|
140
|
-
expect(unmarshalObject(
|
|
133
|
+
const func = ctx.newFunction("", () => {});
|
|
134
|
+
expect(unmarshalObject(ctx, func, f, f)).toEqual(undefined);
|
|
141
135
|
|
|
142
136
|
expect(f).toBeCalledTimes(0);
|
|
143
137
|
|
|
144
138
|
func.dispose();
|
|
145
|
-
|
|
139
|
+
ctx.dispose();
|
|
146
140
|
});
|
package/src/unmarshal/object.ts
CHANGED
|
@@ -1,41 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
3
3
|
import { call } from "../vmutil";
|
|
4
4
|
|
|
5
|
+
import unmarshalProperties from "./properties";
|
|
6
|
+
|
|
5
7
|
export default function unmarshalObject(
|
|
6
|
-
|
|
8
|
+
ctx: QuickJSContext,
|
|
7
9
|
handle: QuickJSHandle,
|
|
8
10
|
unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
|
|
9
|
-
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
11
|
+
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined,
|
|
10
12
|
): object | undefined {
|
|
11
13
|
if (
|
|
12
|
-
|
|
14
|
+
ctx.typeof(handle) !== "object" ||
|
|
13
15
|
// null check
|
|
14
|
-
|
|
15
|
-
.unwrapResult(
|
|
16
|
-
.consume((n)
|
|
17
|
-
vm.dump(vm.unwrapResult(vm.callFunction(n, vm.undefined, handle)))
|
|
18
|
-
)
|
|
16
|
+
ctx
|
|
17
|
+
.unwrapResult(ctx.evalCode("o => o === null"))
|
|
18
|
+
.consume(n => ctx.dump(ctx.unwrapResult(ctx.callFunction(n, ctx.undefined, handle))))
|
|
19
19
|
)
|
|
20
20
|
return;
|
|
21
21
|
|
|
22
|
-
const raw = call(
|
|
23
|
-
vm.dump(r)
|
|
24
|
-
)
|
|
25
|
-
? []
|
|
26
|
-
: {};
|
|
22
|
+
const raw = call(ctx, "Array.isArray", undefined, handle).consume(r => ctx.dump(r)) ? [] : {};
|
|
27
23
|
const obj = preUnmarshal(raw, handle) ?? raw;
|
|
28
24
|
|
|
29
25
|
const prototype = call(
|
|
30
|
-
|
|
26
|
+
ctx,
|
|
31
27
|
`o => {
|
|
32
28
|
const p = Object.getPrototypeOf(o);
|
|
33
29
|
return !p || p === Object.prototype || p === Array.prototype ? undefined : p;
|
|
34
30
|
}`,
|
|
35
31
|
undefined,
|
|
36
|
-
handle
|
|
37
|
-
).consume(
|
|
38
|
-
if (
|
|
32
|
+
handle,
|
|
33
|
+
).consume(prototype => {
|
|
34
|
+
if (ctx.typeof(prototype) === "undefined") return;
|
|
39
35
|
const [proto] = unmarshal(prototype);
|
|
40
36
|
return proto;
|
|
41
37
|
});
|
|
@@ -43,7 +39,7 @@ export default function unmarshalObject(
|
|
|
43
39
|
Object.setPrototypeOf(obj, prototype);
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
unmarshalProperties(
|
|
42
|
+
unmarshalProperties(ctx, handle, raw, unmarshal);
|
|
47
43
|
|
|
48
44
|
return obj;
|
|
49
45
|
}
|
|
@@ -4,27 +4,27 @@ import { expect, test } from "vitest";
|
|
|
4
4
|
import unmarshalPrimitive from "./primitive";
|
|
5
5
|
|
|
6
6
|
test("works", async () => {
|
|
7
|
-
const
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
8
|
|
|
9
|
-
expect(unmarshalPrimitive(
|
|
10
|
-
expect(unmarshalPrimitive(
|
|
11
|
-
expect(unmarshalPrimitive(
|
|
12
|
-
expect(unmarshalPrimitive(
|
|
13
|
-
expect(unmarshalPrimitive(
|
|
14
|
-
expect(unmarshalPrimitive(
|
|
9
|
+
expect(unmarshalPrimitive(ctx, ctx.undefined)).toEqual([undefined, true]);
|
|
10
|
+
expect(unmarshalPrimitive(ctx, ctx.true)).toEqual([true, true]);
|
|
11
|
+
expect(unmarshalPrimitive(ctx, ctx.false)).toEqual([false, true]);
|
|
12
|
+
expect(unmarshalPrimitive(ctx, ctx.null)).toEqual([null, true]);
|
|
13
|
+
expect(unmarshalPrimitive(ctx, ctx.newString("hoge"))).toEqual(["hoge", true]);
|
|
14
|
+
expect(unmarshalPrimitive(ctx, ctx.newNumber(-10))).toEqual([-10, true]);
|
|
15
15
|
// expect(
|
|
16
|
-
// unmarshalPrimitive(
|
|
16
|
+
// unmarshalPrimitive(ctx, ctx.unwrapResult(vm.evalCode(`BigInt(1)`)))
|
|
17
17
|
// ).toEqual([BigInt(1), true]);
|
|
18
18
|
|
|
19
|
-
const obj =
|
|
20
|
-
expect(unmarshalPrimitive(
|
|
21
|
-
const array =
|
|
22
|
-
expect(unmarshalPrimitive(
|
|
23
|
-
const func =
|
|
24
|
-
expect(unmarshalPrimitive(
|
|
19
|
+
const obj = ctx.newObject();
|
|
20
|
+
expect(unmarshalPrimitive(ctx, obj)).toEqual([undefined, false]);
|
|
21
|
+
const array = ctx.newArray();
|
|
22
|
+
expect(unmarshalPrimitive(ctx, array)).toEqual([undefined, false]);
|
|
23
|
+
const func = ctx.newFunction("", () => {});
|
|
24
|
+
expect(unmarshalPrimitive(ctx, func)).toEqual([undefined, false]);
|
|
25
25
|
|
|
26
26
|
obj.dispose();
|
|
27
27
|
array.dispose();
|
|
28
28
|
func.dispose();
|
|
29
|
-
|
|
29
|
+
ctx.dispose();
|
|
30
30
|
});
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
2
|
|
|
3
3
|
export default function unmarshalPrimitive(
|
|
4
|
-
|
|
5
|
-
handle: QuickJSHandle
|
|
4
|
+
ctx: QuickJSContext,
|
|
5
|
+
handle: QuickJSHandle,
|
|
6
6
|
): [any, boolean] {
|
|
7
|
-
const ty =
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
ty === "number" ||
|
|
11
|
-
ty === "string" ||
|
|
12
|
-
ty === "boolean"
|
|
13
|
-
) {
|
|
14
|
-
return [vm.dump(handle), true];
|
|
7
|
+
const ty = ctx.typeof(handle);
|
|
8
|
+
if (ty === "undefined" || ty === "number" || ty === "string" || ty === "boolean") {
|
|
9
|
+
return [ctx.dump(handle), true];
|
|
15
10
|
} else if (ty === "object") {
|
|
16
|
-
const isNull =
|
|
17
|
-
.unwrapResult(
|
|
18
|
-
.consume((n)
|
|
19
|
-
vm.dump(vm.unwrapResult(vm.callFunction(n, vm.undefined, handle)))
|
|
20
|
-
);
|
|
11
|
+
const isNull = ctx
|
|
12
|
+
.unwrapResult(ctx.evalCode("a => a === null"))
|
|
13
|
+
.consume(n => ctx.dump(ctx.unwrapResult(ctx.callFunction(n, ctx.undefined, handle))));
|
|
21
14
|
if (isNull) {
|
|
22
15
|
return [null, true];
|
|
23
16
|
}
|
|
@@ -25,10 +18,10 @@ export default function unmarshalPrimitive(
|
|
|
25
18
|
|
|
26
19
|
// BigInt is not supported by quickjs-emscripten
|
|
27
20
|
// if (ty === "bigint") {
|
|
28
|
-
// const str =
|
|
21
|
+
// const str = ctx
|
|
29
22
|
// .getProp(handle, "toString")
|
|
30
23
|
// .consume(toString => vm.unwrapResult(vm.callFunction(toString, handle)))
|
|
31
|
-
// .consume(str =>
|
|
24
|
+
// .consume(str => ctx.getString(str));
|
|
32
25
|
// const bi = BigInt(str);
|
|
33
26
|
// return [bi, true];
|
|
34
27
|
// }
|
|
@@ -4,40 +4,40 @@ import { expect, test, vi } from "vitest";
|
|
|
4
4
|
import unmarshalPromise from "./promise";
|
|
5
5
|
|
|
6
6
|
const testPromise = (reject: boolean) => async () => {
|
|
7
|
-
const
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
8
|
const disposables: Disposable[] = [];
|
|
9
9
|
const marshal = vi.fn((v): [QuickJSHandle, boolean] => {
|
|
10
|
-
const f =
|
|
11
|
-
v(
|
|
10
|
+
const f = ctx.newFunction(v.name, h => {
|
|
11
|
+
v(ctx.dump(h));
|
|
12
12
|
});
|
|
13
13
|
disposables.push(f);
|
|
14
14
|
return [f, false];
|
|
15
15
|
});
|
|
16
|
-
const preUnmarshal = vi.fn(
|
|
16
|
+
const preUnmarshal = vi.fn(a => a);
|
|
17
17
|
|
|
18
|
-
const deferred =
|
|
18
|
+
const deferred = ctx.newPromise();
|
|
19
19
|
disposables.push(deferred);
|
|
20
|
-
const promise = unmarshalPromise(
|
|
20
|
+
const promise = unmarshalPromise(ctx, deferred.handle, marshal, preUnmarshal);
|
|
21
21
|
|
|
22
22
|
expect(marshal).toBeCalledTimes(2);
|
|
23
23
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
24
|
-
expect(
|
|
24
|
+
expect(ctx.runtime.hasPendingJob()).toBe(false);
|
|
25
25
|
|
|
26
26
|
if (reject) {
|
|
27
|
-
deferred.reject(
|
|
27
|
+
deferred.reject(ctx.newString("hoge"));
|
|
28
28
|
} else {
|
|
29
|
-
deferred.resolve(
|
|
29
|
+
deferred.resolve(ctx.newString("hoge"));
|
|
30
30
|
}
|
|
31
|
-
expect(
|
|
32
|
-
expect(
|
|
31
|
+
expect(ctx.runtime.hasPendingJob()).toBe(true);
|
|
32
|
+
expect(ctx.unwrapResult(ctx.runtime.executePendingJobs())).toBe(1);
|
|
33
33
|
if (reject) {
|
|
34
34
|
expect(promise).rejects.toThrow("hoge");
|
|
35
35
|
} else {
|
|
36
36
|
expect(promise).resolves.toBe("hoge");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
disposables.forEach(
|
|
40
|
-
|
|
39
|
+
disposables.forEach(d => d.dispose());
|
|
40
|
+
ctx.dispose();
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
test("resolve", testPromise(false));
|
package/src/unmarshal/promise.ts
CHANGED
|
@@ -1,40 +1,31 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
2
|
|
|
3
3
|
import { newDeferred } from "../util";
|
|
4
4
|
import { call, instanceOf } from "../vmutil";
|
|
5
5
|
|
|
6
6
|
export default function unmarshalPromise<T = unknown>(
|
|
7
|
-
|
|
7
|
+
ctx: QuickJSContext,
|
|
8
8
|
handle: QuickJSHandle,
|
|
9
9
|
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
10
10
|
marshal: (value: unknown) => [QuickJSHandle, boolean],
|
|
11
|
-
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
11
|
+
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined,
|
|
12
12
|
): Promise<T> | undefined {
|
|
13
|
-
if (!isPromiseHandle(handle)) return;
|
|
13
|
+
if (!isPromiseHandle(ctx, handle)) return;
|
|
14
14
|
|
|
15
15
|
const deferred = newDeferred<T>();
|
|
16
16
|
const [resHandle, resShouldBeDisposed] = marshal(deferred.resolve);
|
|
17
17
|
const [rejHandle, rejShouldBeDisposed] = marshal(deferred.reject);
|
|
18
|
-
call(
|
|
19
|
-
vm,
|
|
20
|
-
"(p, res, rej) => { p.then(res, rej); }",
|
|
21
|
-
undefined,
|
|
22
|
-
handle,
|
|
23
|
-
resHandle,
|
|
24
|
-
rejHandle
|
|
25
|
-
);
|
|
18
|
+
call(ctx, "(p, res, rej) => { p.then(res, rej); }", undefined, handle, resHandle, rejHandle);
|
|
26
19
|
if (resShouldBeDisposed) resHandle.dispose();
|
|
27
20
|
if (rejShouldBeDisposed) rejHandle.dispose();
|
|
28
21
|
|
|
29
22
|
return preUnmarshal(deferred.promise, handle) ?? deferred.promise;
|
|
30
23
|
}
|
|
31
24
|
|
|
32
|
-
function isPromiseHandle(handle: QuickJSHandle): boolean {
|
|
25
|
+
function isPromiseHandle(ctx: QuickJSContext, handle: QuickJSHandle): boolean {
|
|
33
26
|
if (!handle.owner) return false;
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return instanceOf(handle.owner, handle, promise);
|
|
39
|
-
});
|
|
27
|
+
return ctx.unwrapResult(ctx.evalCode("Promise")).consume(promise => {
|
|
28
|
+
if (!handle.owner) return false;
|
|
29
|
+
return instanceOf(ctx, handle, promise);
|
|
30
|
+
});
|
|
40
31
|
}
|
|
@@ -4,16 +4,16 @@ import { expect, test, vi } from "vitest";
|
|
|
4
4
|
import unmarshalProperties from "./properties";
|
|
5
5
|
|
|
6
6
|
test("works", async () => {
|
|
7
|
-
const
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
8
|
const disposables: QuickJSHandle[] = [];
|
|
9
9
|
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
10
10
|
disposables.push(v);
|
|
11
|
-
return [
|
|
11
|
+
return [ctx.typeof(v) === "function" ? () => {} : ctx.dump(v), false];
|
|
12
12
|
});
|
|
13
13
|
const obj = {};
|
|
14
14
|
|
|
15
|
-
const handle =
|
|
16
|
-
|
|
15
|
+
const handle = ctx.unwrapResult(
|
|
16
|
+
ctx.evalCode(`{
|
|
17
17
|
const obj = {};
|
|
18
18
|
Object.defineProperties(obj, {
|
|
19
19
|
a: { value: 1, writable: true, configurable: true, enumerable: true },
|
|
@@ -21,10 +21,10 @@ test("works", async () => {
|
|
|
21
21
|
c: { get: () => {}, set: () => {} },
|
|
22
22
|
});
|
|
23
23
|
obj
|
|
24
|
-
}`)
|
|
24
|
+
}`),
|
|
25
25
|
);
|
|
26
26
|
|
|
27
|
-
unmarshalProperties(
|
|
27
|
+
unmarshalProperties(ctx, handle, obj, unmarshal);
|
|
28
28
|
|
|
29
29
|
expect(obj).toEqual({
|
|
30
30
|
a: 1,
|
|
@@ -47,7 +47,7 @@ test("works", async () => {
|
|
|
47
47
|
expect(unmarshal).toReturnWith(["c", false]);
|
|
48
48
|
expect(unmarshal).toReturnWith([expect.any(Function), false]); // get, set
|
|
49
49
|
|
|
50
|
-
disposables.forEach(
|
|
50
|
+
disposables.forEach(d => d.dispose());
|
|
51
51
|
handle.dispose();
|
|
52
|
-
|
|
52
|
+
ctx.dispose();
|
|
53
53
|
});
|
|
@@ -1,61 +1,60 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import { call } from "../vmutil";
|
|
3
4
|
|
|
4
5
|
export default function unmarshalProperties(
|
|
5
|
-
|
|
6
|
+
ctx: QuickJSContext,
|
|
6
7
|
handle: QuickJSHandle,
|
|
7
8
|
target: object | Function,
|
|
8
|
-
unmarshal: (handle: QuickJSHandle) => [unknown, boolean]
|
|
9
|
+
unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
|
|
9
10
|
) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
typeof keyName !== "string" &&
|
|
14
|
-
|
|
15
|
-
typeof keyName !== "symbol"
|
|
16
|
-
)
|
|
17
|
-
return;
|
|
11
|
+
ctx
|
|
12
|
+
.newFunction("", (key, value) => {
|
|
13
|
+
const [keyName] = unmarshal(key);
|
|
14
|
+
if (typeof keyName !== "string" && typeof keyName !== "number" && typeof keyName !== "symbol")
|
|
15
|
+
return;
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
const desc = (
|
|
18
|
+
[
|
|
19
|
+
["value", true],
|
|
20
|
+
["get", true],
|
|
21
|
+
["set", true],
|
|
22
|
+
["configurable", false],
|
|
23
|
+
["enumerable", false],
|
|
24
|
+
["writable", false],
|
|
25
|
+
] as const
|
|
26
|
+
).reduce<PropertyDescriptor>((desc, [key, unmarshable]) => {
|
|
27
|
+
const h = ctx.getProp(value, key);
|
|
28
|
+
const ty = ctx.typeof(h);
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
if (ty === "undefined") return desc;
|
|
31
|
+
if (!unmarshable && ty === "boolean") {
|
|
32
|
+
desc[key] = ctx.dump(ctx.getProp(value, key));
|
|
33
|
+
return desc;
|
|
34
|
+
}
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
const [v, alreadyExists] = unmarshal(h);
|
|
37
|
+
if (alreadyExists) {
|
|
38
|
+
h.dispose();
|
|
39
|
+
}
|
|
40
|
+
desc[key] = v;
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
return desc;
|
|
43
|
+
}, {});
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
Object.defineProperty(target, keyName, desc);
|
|
46
|
+
})
|
|
47
|
+
.consume(fn => {
|
|
48
|
+
call(
|
|
49
|
+
ctx,
|
|
50
|
+
`(o, fn) => {
|
|
52
51
|
const descs = Object.getOwnPropertyDescriptors(o);
|
|
53
52
|
Object.entries(descs).forEach(([k, v]) => fn(k, v));
|
|
54
53
|
Object.getOwnPropertySymbols(descs).forEach(k => fn(k, descs[k]));
|
|
55
54
|
}`,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
undefined,
|
|
56
|
+
handle,
|
|
57
|
+
fn,
|
|
58
|
+
).dispose();
|
|
59
|
+
});
|
|
61
60
|
}
|
package/src/util.test.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { expect, test, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
isObject,
|
|
5
|
-
walkObject,
|
|
6
|
-
complexity,
|
|
7
|
-
newDeferred,
|
|
8
|
-
} from "./util";
|
|
2
|
+
|
|
3
|
+
import { isES2015Class, isObject, walkObject, complexity, newDeferred } from "./util";
|
|
9
4
|
|
|
10
5
|
test("isES2015Class", () => {
|
|
11
6
|
expect(isES2015Class(class {})).toBe(true);
|
package/src/util.ts
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
export function isES2015Class(cls: any): cls is new (...args: any[]) => any {
|
|
2
|
-
return (
|
|
3
|
-
typeof cls === "function" &&
|
|
4
|
-
/^class\s/.test(Function.prototype.toString.call(cls))
|
|
5
|
-
);
|
|
2
|
+
return typeof cls === "function" && /^class\s/.test(Function.prototype.toString.call(cls));
|
|
6
3
|
}
|
|
7
4
|
|
|
8
5
|
export function isObject(value: any): value is object | Function {
|
|
9
|
-
return (
|
|
10
|
-
typeof value === "function" || (typeof value === "object" && value !== null)
|
|
11
|
-
);
|
|
6
|
+
return typeof value === "function" || (typeof value === "object" && value !== null);
|
|
12
7
|
}
|
|
13
8
|
|
|
14
9
|
export function walkObject(
|
|
15
10
|
value: any,
|
|
16
|
-
callback?: (target: any, set: Set<any>) => boolean | void
|
|
11
|
+
callback?: (target: any, set: Set<any>) => boolean | void,
|
|
17
12
|
): Set<any> {
|
|
18
13
|
const set = new Set<any>();
|
|
19
14
|
const walk = (v: any) => {
|