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
|
@@ -2,71 +2,64 @@ import { getQuickJS } from "quickjs-emscripten";
|
|
|
2
2
|
import { expect, test, vi } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { call } from "../vmutil";
|
|
5
|
+
|
|
5
6
|
import marshalObject from "./object";
|
|
6
7
|
|
|
7
8
|
test("empty object", async () => {
|
|
8
|
-
const
|
|
9
|
-
const prototypeCheck =
|
|
10
|
-
|
|
9
|
+
const ctx = (await getQuickJS()).newContext();
|
|
10
|
+
const prototypeCheck = ctx.unwrapResult(
|
|
11
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
|
|
11
12
|
);
|
|
12
13
|
|
|
13
14
|
const obj = {};
|
|
14
15
|
const marshal = vi.fn();
|
|
15
16
|
const preMarshal = vi.fn((_, a) => a);
|
|
16
17
|
|
|
17
|
-
const handle = marshalObject(
|
|
18
|
+
const handle = marshalObject(ctx, obj, marshal, preMarshal);
|
|
18
19
|
if (!handle) throw new Error("handle is undefined");
|
|
19
20
|
|
|
20
|
-
expect(
|
|
21
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
21
22
|
expect(marshal).toBeCalledTimes(0);
|
|
22
23
|
expect(preMarshal).toBeCalledTimes(1);
|
|
23
24
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
24
25
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
25
|
-
expect(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
).toBe(true);
|
|
26
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
|
|
27
|
+
true,
|
|
28
|
+
);
|
|
30
29
|
|
|
31
30
|
handle.dispose();
|
|
32
31
|
prototypeCheck.dispose();
|
|
33
|
-
|
|
32
|
+
ctx.dispose();
|
|
34
33
|
});
|
|
35
34
|
|
|
36
35
|
test("normal object", async () => {
|
|
37
|
-
const
|
|
38
|
-
const prototypeCheck =
|
|
39
|
-
|
|
36
|
+
const ctx = (await getQuickJS()).newContext();
|
|
37
|
+
const prototypeCheck = ctx.unwrapResult(
|
|
38
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
|
|
40
39
|
);
|
|
41
|
-
const entries =
|
|
40
|
+
const entries = ctx.unwrapResult(ctx.evalCode(`Object.entries`));
|
|
42
41
|
|
|
43
42
|
const obj = { a: 100, b: "hoge" };
|
|
44
|
-
const marshal = vi.fn(
|
|
45
|
-
typeof v === "number"
|
|
46
|
-
? vm.newNumber(v)
|
|
47
|
-
: typeof v === "string"
|
|
48
|
-
? vm.newString(v)
|
|
49
|
-
: vm.null
|
|
43
|
+
const marshal = vi.fn(v =>
|
|
44
|
+
typeof v === "number" ? ctx.newNumber(v) : typeof v === "string" ? ctx.newString(v) : ctx.null,
|
|
50
45
|
);
|
|
51
46
|
const preMarshal = vi.fn((_, a) => a);
|
|
52
47
|
|
|
53
|
-
const handle = marshalObject(
|
|
48
|
+
const handle = marshalObject(ctx, obj, marshal, preMarshal);
|
|
54
49
|
if (!handle) throw new Error("handle is undefined");
|
|
55
50
|
|
|
56
|
-
expect(
|
|
57
|
-
expect(
|
|
58
|
-
expect(
|
|
51
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
52
|
+
expect(ctx.getNumber(ctx.getProp(handle, "a"))).toBe(100);
|
|
53
|
+
expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
|
|
59
54
|
expect(marshal.mock.calls).toEqual([["a"], [100], ["b"], ["hoge"]]);
|
|
60
55
|
expect(preMarshal).toBeCalledTimes(1);
|
|
61
56
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
62
57
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
63
|
-
expect(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
).
|
|
68
|
-
const e = vm.unwrapResult(vm.callFunction(entries, vm.undefined, handle));
|
|
69
|
-
expect(vm.dump(e)).toEqual([
|
|
58
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
|
|
59
|
+
true,
|
|
60
|
+
);
|
|
61
|
+
const e = ctx.unwrapResult(ctx.callFunction(entries, ctx.undefined, handle));
|
|
62
|
+
expect(ctx.dump(e)).toEqual([
|
|
70
63
|
["a", 100],
|
|
71
64
|
["b", "hoge"],
|
|
72
65
|
]);
|
|
@@ -75,89 +68,69 @@ test("normal object", async () => {
|
|
|
75
68
|
handle.dispose();
|
|
76
69
|
prototypeCheck.dispose();
|
|
77
70
|
entries.dispose();
|
|
78
|
-
|
|
71
|
+
ctx.dispose();
|
|
79
72
|
});
|
|
80
73
|
|
|
81
74
|
test("array", async () => {
|
|
82
|
-
const
|
|
83
|
-
const isArray =
|
|
75
|
+
const ctx = (await getQuickJS()).newContext();
|
|
76
|
+
const isArray = ctx.unwrapResult(ctx.evalCode(`Array.isArray`));
|
|
84
77
|
|
|
85
78
|
const array = [1, "aa"];
|
|
86
|
-
const marshal = vi.fn(
|
|
87
|
-
typeof v === "number"
|
|
88
|
-
? vm.newNumber(v)
|
|
89
|
-
: typeof v === "string"
|
|
90
|
-
? vm.newString(v)
|
|
91
|
-
: vm.null
|
|
79
|
+
const marshal = vi.fn(v =>
|
|
80
|
+
typeof v === "number" ? ctx.newNumber(v) : typeof v === "string" ? ctx.newString(v) : ctx.null,
|
|
92
81
|
);
|
|
93
82
|
const preMarshal = vi.fn((_, a) => a);
|
|
94
83
|
|
|
95
|
-
const handle = marshalObject(
|
|
84
|
+
const handle = marshalObject(ctx, array, marshal, preMarshal);
|
|
96
85
|
if (!handle) throw new Error("handle is undefined");
|
|
97
86
|
|
|
98
|
-
expect(
|
|
99
|
-
expect(
|
|
100
|
-
expect(
|
|
101
|
-
expect(
|
|
102
|
-
expect(marshal.mock.calls).toEqual([
|
|
103
|
-
["0"],
|
|
104
|
-
[1],
|
|
105
|
-
["1"],
|
|
106
|
-
["aa"],
|
|
107
|
-
["length"],
|
|
108
|
-
[2],
|
|
109
|
-
]);
|
|
87
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
88
|
+
expect(ctx.getNumber(ctx.getProp(handle, 0))).toBe(1);
|
|
89
|
+
expect(ctx.getString(ctx.getProp(handle, 1))).toBe("aa");
|
|
90
|
+
expect(ctx.getNumber(ctx.getProp(handle, "length"))).toBe(2);
|
|
91
|
+
expect(marshal.mock.calls).toEqual([["0"], [1], ["1"], ["aa"], ["length"], [2]]);
|
|
110
92
|
expect(preMarshal).toBeCalledTimes(1);
|
|
111
93
|
expect(preMarshal.mock.calls[0][0]).toBe(array);
|
|
112
94
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
113
|
-
expect(
|
|
114
|
-
vm.dump(vm.unwrapResult(vm.callFunction(isArray, vm.undefined, handle)))
|
|
115
|
-
).toBe(true);
|
|
95
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))).toBe(true);
|
|
116
96
|
|
|
117
97
|
handle.dispose();
|
|
118
98
|
isArray.dispose();
|
|
119
|
-
|
|
99
|
+
ctx.dispose();
|
|
120
100
|
});
|
|
121
101
|
|
|
122
102
|
test("prototype", async () => {
|
|
123
|
-
const
|
|
103
|
+
const ctx = (await getQuickJS()).newContext();
|
|
124
104
|
|
|
125
105
|
const proto = { a: 100 };
|
|
126
|
-
const protoHandle =
|
|
127
|
-
|
|
106
|
+
const protoHandle = ctx.newObject();
|
|
107
|
+
ctx.setProp(protoHandle, "a", ctx.newNumber(100));
|
|
128
108
|
const preMarshal = vi.fn((_, a) => a);
|
|
129
109
|
|
|
130
110
|
const obj = Object.create(proto);
|
|
131
111
|
obj.b = "hoge";
|
|
132
112
|
const handle = marshalObject(
|
|
133
|
-
|
|
113
|
+
ctx,
|
|
134
114
|
obj,
|
|
135
|
-
(v)
|
|
136
|
-
|
|
137
|
-
? protoHandle
|
|
138
|
-
: typeof v === "string"
|
|
139
|
-
? vm.newString(v)
|
|
140
|
-
: vm.null,
|
|
141
|
-
preMarshal
|
|
115
|
+
v => (v === proto ? protoHandle : typeof v === "string" ? ctx.newString(v) : ctx.null),
|
|
116
|
+
preMarshal,
|
|
142
117
|
);
|
|
143
118
|
if (!handle) throw new Error("handle is undefined");
|
|
144
119
|
|
|
145
120
|
expect(preMarshal).toBeCalledTimes(1);
|
|
146
121
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
147
122
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
148
|
-
expect(
|
|
149
|
-
expect(
|
|
150
|
-
expect(
|
|
151
|
-
const e = call(
|
|
152
|
-
expect(
|
|
153
|
-
const protoHandle2 = call(
|
|
154
|
-
expect(
|
|
155
|
-
vm.dump(call(vm, `Object.is`, undefined, protoHandle, protoHandle2))
|
|
156
|
-
).toBe(true);
|
|
123
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
124
|
+
expect(ctx.getNumber(ctx.getProp(handle, "a"))).toBe(100);
|
|
125
|
+
expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
|
|
126
|
+
const e = call(ctx, "Object.entries", undefined, handle);
|
|
127
|
+
expect(ctx.dump(e)).toEqual([["b", "hoge"]]);
|
|
128
|
+
const protoHandle2 = call(ctx, "Object.getPrototypeOf", ctx.undefined, handle);
|
|
129
|
+
expect(ctx.dump(call(ctx, `Object.is`, undefined, protoHandle, protoHandle2))).toBe(true);
|
|
157
130
|
|
|
158
131
|
protoHandle2.dispose();
|
|
159
132
|
e.dispose();
|
|
160
133
|
handle.dispose();
|
|
161
134
|
protoHandle.dispose();
|
|
162
|
-
|
|
135
|
+
ctx.dispose();
|
|
163
136
|
});
|
package/src/marshal/object.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import { call } from "../vmutil";
|
|
4
|
+
|
|
3
5
|
import marshalProperties from "./properties";
|
|
4
6
|
|
|
5
7
|
export default function marshalObject(
|
|
6
|
-
|
|
8
|
+
ctx: QuickJSContext,
|
|
7
9
|
target: unknown,
|
|
8
10
|
marshal: (target: unknown) => QuickJSHandle,
|
|
9
|
-
preMarshal: (
|
|
10
|
-
target: unknown,
|
|
11
|
-
handle: QuickJSHandle
|
|
12
|
-
) => QuickJSHandle | undefined
|
|
11
|
+
preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
|
|
13
12
|
): QuickJSHandle | undefined {
|
|
14
13
|
if (typeof target !== "object" || target === null) return;
|
|
15
14
|
|
|
16
|
-
const raw = Array.isArray(target) ?
|
|
15
|
+
const raw = Array.isArray(target) ? ctx.newArray() : ctx.newObject();
|
|
17
16
|
const handle = preMarshal(target, raw) ?? raw;
|
|
18
17
|
|
|
19
18
|
// prototype
|
|
@@ -23,16 +22,10 @@ export default function marshalObject(
|
|
|
23
22
|
? marshal(prototype)
|
|
24
23
|
: undefined;
|
|
25
24
|
if (prototypeHandle) {
|
|
26
|
-
call(
|
|
27
|
-
vm,
|
|
28
|
-
"Object.setPrototypeOf",
|
|
29
|
-
undefined,
|
|
30
|
-
handle,
|
|
31
|
-
prototypeHandle
|
|
32
|
-
).dispose();
|
|
25
|
+
call(ctx, "Object.setPrototypeOf", undefined, handle, prototypeHandle).dispose();
|
|
33
26
|
}
|
|
34
27
|
|
|
35
|
-
marshalProperties(
|
|
28
|
+
marshalProperties(ctx, target, raw, marshal);
|
|
36
29
|
|
|
37
30
|
return handle;
|
|
38
31
|
}
|
|
@@ -2,35 +2,30 @@ import { getQuickJS } from "quickjs-emscripten";
|
|
|
2
2
|
import { expect, test } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { eq } from "../vmutil";
|
|
5
|
+
|
|
5
6
|
import marshalPrimitive from "./primitive";
|
|
6
7
|
|
|
7
8
|
test("works", async () => {
|
|
8
|
-
const
|
|
9
|
+
const ctx = (await getQuickJS()).newContext();
|
|
9
10
|
|
|
10
|
-
expect(marshalPrimitive(
|
|
11
|
-
expect(marshalPrimitive(
|
|
12
|
-
expect(marshalPrimitive(
|
|
13
|
-
expect(marshalPrimitive(
|
|
14
|
-
expect(eq(
|
|
15
|
-
|
|
16
|
-
);
|
|
17
|
-
expect(
|
|
18
|
-
eq(vm, marshalPrimitive(vm, -100) ?? vm.undefined, vm.newNumber(-100))
|
|
19
|
-
).toBe(true);
|
|
20
|
-
expect(
|
|
21
|
-
eq(vm, marshalPrimitive(vm, "hoge") ?? vm.undefined, vm.newString("hoge"))
|
|
22
|
-
).toBe(true);
|
|
11
|
+
expect(marshalPrimitive(ctx, undefined)).toBe(ctx.undefined);
|
|
12
|
+
expect(marshalPrimitive(ctx, null)).toBe(ctx.null);
|
|
13
|
+
expect(marshalPrimitive(ctx, false)).toBe(ctx.false);
|
|
14
|
+
expect(marshalPrimitive(ctx, true)).toBe(ctx.true);
|
|
15
|
+
expect(eq(ctx, marshalPrimitive(ctx, 1) ?? ctx.undefined, ctx.newNumber(1))).toBe(true);
|
|
16
|
+
expect(eq(ctx, marshalPrimitive(ctx, -100) ?? ctx.undefined, ctx.newNumber(-100))).toBe(true);
|
|
17
|
+
expect(eq(ctx, marshalPrimitive(ctx, "hoge") ?? ctx.undefined, ctx.newString("hoge"))).toBe(true);
|
|
23
18
|
// expect(
|
|
24
19
|
// eq(
|
|
25
|
-
//
|
|
26
|
-
// marshalPrimitive(
|
|
27
|
-
//
|
|
20
|
+
// ctx,
|
|
21
|
+
// marshalPrimitive(ctx, BigInt(1)) ?? ctx.undefined,
|
|
22
|
+
// ctx.unwrapResult(ctx.evalCode("BigInt(1)"))
|
|
28
23
|
// )
|
|
29
24
|
// ).toBe(true);
|
|
30
25
|
|
|
31
|
-
expect(marshalPrimitive(
|
|
32
|
-
expect(marshalPrimitive(
|
|
33
|
-
expect(marshalPrimitive(
|
|
26
|
+
expect(marshalPrimitive(ctx, () => {})).toBe(undefined);
|
|
27
|
+
expect(marshalPrimitive(ctx, [])).toBe(undefined);
|
|
28
|
+
expect(marshalPrimitive(ctx, {})).toBe(undefined);
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
ctx.dispose();
|
|
36
31
|
});
|
package/src/marshal/primitive.ts
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
// import { call } from "../vmutil";
|
|
3
4
|
|
|
4
5
|
export default function marshalPrimitive(
|
|
5
|
-
|
|
6
|
-
target: unknown
|
|
6
|
+
ctx: QuickJSContext,
|
|
7
|
+
target: unknown,
|
|
7
8
|
): QuickJSHandle | undefined {
|
|
8
9
|
switch (typeof target) {
|
|
9
10
|
case "undefined":
|
|
10
|
-
return
|
|
11
|
+
return ctx.undefined;
|
|
11
12
|
case "number":
|
|
12
|
-
return
|
|
13
|
+
return ctx.newNumber(target);
|
|
13
14
|
case "string":
|
|
14
|
-
return
|
|
15
|
+
return ctx.newString(target);
|
|
15
16
|
case "boolean":
|
|
16
|
-
return target ?
|
|
17
|
+
return target ? ctx.true : ctx.false;
|
|
17
18
|
case "object":
|
|
18
|
-
return target === null ?
|
|
19
|
+
return target === null ? ctx.null : undefined;
|
|
19
20
|
|
|
20
21
|
// BigInt is not supported by quickjs-emscripten
|
|
21
22
|
// case "bigint":
|
|
22
23
|
// return call(
|
|
23
|
-
//
|
|
24
|
+
// ctx,
|
|
24
25
|
// `s => BigInt(s)`,
|
|
25
26
|
// undefined,
|
|
26
|
-
//
|
|
27
|
+
// ctx.newString(target.toString())
|
|
27
28
|
// );
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -5,38 +5,37 @@ import {
|
|
|
5
5
|
type QuickJSHandle,
|
|
6
6
|
} from "quickjs-emscripten";
|
|
7
7
|
import { expect, test, vi } from "vitest";
|
|
8
|
-
import { newDeferred } from "../util";
|
|
9
8
|
|
|
9
|
+
import { newDeferred } from "../util";
|
|
10
10
|
import { fn, json } from "../vmutil";
|
|
11
|
+
|
|
11
12
|
import marshalPromise from "./promise";
|
|
12
13
|
|
|
13
14
|
const testPromise = (reject: boolean) => async () => {
|
|
14
|
-
const
|
|
15
|
+
const ctx = (await getQuickJS()).newContext();
|
|
15
16
|
|
|
16
17
|
const disposables: Disposable[] = [];
|
|
17
|
-
const marshal = vi.fn(
|
|
18
|
-
const handle = json(
|
|
18
|
+
const marshal = vi.fn(v => {
|
|
19
|
+
const handle = json(ctx, v);
|
|
19
20
|
disposables.push(handle);
|
|
20
21
|
return handle;
|
|
21
22
|
});
|
|
22
|
-
const preMarshal = vi.fn(
|
|
23
|
-
(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
);
|
|
23
|
+
const preMarshal = vi.fn((_: any, a: QuickJSDeferredPromise): QuickJSHandle => {
|
|
24
|
+
disposables.push(a);
|
|
25
|
+
return a.handle;
|
|
26
|
+
});
|
|
28
27
|
|
|
29
28
|
const mockNotify = vi.fn();
|
|
30
|
-
const notify =
|
|
31
|
-
const arg1 =
|
|
32
|
-
const arg2 =
|
|
29
|
+
const notify = ctx.newFunction("notify", (handle1, handle2) => {
|
|
30
|
+
const arg1 = ctx.dump(handle1);
|
|
31
|
+
const arg2 = ctx.dump(handle2);
|
|
33
32
|
mockNotify(arg1, arg2);
|
|
34
33
|
});
|
|
35
34
|
disposables.push(notify);
|
|
36
35
|
|
|
37
36
|
const notifier = fn(
|
|
38
|
-
|
|
39
|
-
`(notify, promise) => { promise.then(d => notify("resolved", d), d => notify("rejected", d)); }
|
|
37
|
+
ctx,
|
|
38
|
+
`(notify, promise) => { promise.then(d => notify("resolved", d), d => notify("rejected", d)); }`,
|
|
40
39
|
);
|
|
41
40
|
disposables.push(notifier);
|
|
42
41
|
|
|
@@ -44,7 +43,7 @@ const testPromise = (reject: boolean) => async () => {
|
|
|
44
43
|
if (reject) {
|
|
45
44
|
deferred.promise.catch(() => {});
|
|
46
45
|
}
|
|
47
|
-
const handle = marshalPromise(
|
|
46
|
+
const handle = marshalPromise(ctx, deferred.promise, marshal, preMarshal);
|
|
48
47
|
if (!handle) throw new Error("handle is undefined");
|
|
49
48
|
|
|
50
49
|
expect(marshal).toBeCalledTimes(0);
|
|
@@ -56,7 +55,7 @@ const testPromise = (reject: boolean) => async () => {
|
|
|
56
55
|
|
|
57
56
|
expect(mockNotify).toBeCalledTimes(0);
|
|
58
57
|
expect(deferred.resolve).not.toBeUndefined();
|
|
59
|
-
expect(
|
|
58
|
+
expect(ctx.runtime.hasPendingJob()).toBe(false);
|
|
60
59
|
|
|
61
60
|
if (reject) {
|
|
62
61
|
deferred.reject("hoge");
|
|
@@ -64,22 +63,22 @@ const testPromise = (reject: boolean) => async () => {
|
|
|
64
63
|
deferred.resolve("hoge");
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
expect(
|
|
66
|
+
expect(ctx.runtime.hasPendingJob()).toBe(false);
|
|
68
67
|
if (reject) {
|
|
69
68
|
await expect(deferred.promise).rejects.toBe("hoge");
|
|
70
69
|
} else {
|
|
71
70
|
await expect(deferred.promise).resolves.toBe("hoge");
|
|
72
71
|
}
|
|
73
|
-
expect(
|
|
74
|
-
const executed =
|
|
72
|
+
expect(ctx.runtime.hasPendingJob()).toBe(true);
|
|
73
|
+
const executed = ctx.unwrapResult(ctx.runtime.executePendingJobs());
|
|
75
74
|
expect(executed).toBe(1);
|
|
76
75
|
expect(mockNotify).toBeCalledTimes(1);
|
|
77
76
|
expect(mockNotify).toBeCalledWith(reject ? "rejected" : "resolved", "hoge");
|
|
78
77
|
expect(marshal).toBeCalledTimes(1);
|
|
79
78
|
expect(marshal.mock.calls).toEqual([["hoge"]]);
|
|
80
79
|
|
|
81
|
-
disposables.forEach(
|
|
82
|
-
|
|
80
|
+
disposables.forEach(h => h.dispose());
|
|
81
|
+
ctx.dispose();
|
|
83
82
|
};
|
|
84
83
|
|
|
85
84
|
test("resolve", testPromise(false));
|
package/src/marshal/promise.ts
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
QuickJSDeferredPromise,
|
|
3
|
-
QuickJSHandle,
|
|
4
|
-
QuickJSVm,
|
|
5
|
-
} from "quickjs-emscripten";
|
|
1
|
+
import type { QuickJSDeferredPromise, QuickJSHandle, QuickJSContext } from "quickjs-emscripten";
|
|
6
2
|
|
|
7
3
|
export default function marshalPromise(
|
|
8
|
-
|
|
4
|
+
ctx: QuickJSContext,
|
|
9
5
|
target: unknown,
|
|
10
6
|
marshal: (target: unknown) => QuickJSHandle,
|
|
11
|
-
preMarshal: (
|
|
12
|
-
target: unknown,
|
|
13
|
-
handle: QuickJSDeferredPromise
|
|
14
|
-
) => QuickJSHandle | undefined
|
|
7
|
+
preMarshal: (target: unknown, handle: QuickJSDeferredPromise) => QuickJSHandle | undefined,
|
|
15
8
|
) {
|
|
16
9
|
if (!(target instanceof Promise)) return;
|
|
17
10
|
|
|
18
|
-
const promise =
|
|
11
|
+
const promise = ctx.newPromise();
|
|
19
12
|
|
|
20
13
|
target.then(
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
d => promise.resolve(marshal(d)),
|
|
15
|
+
d => promise.reject(marshal(d)),
|
|
23
16
|
);
|
|
24
17
|
|
|
25
18
|
return preMarshal(target, promise) ?? promise.handle;
|
|
@@ -2,12 +2,13 @@ import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
|
2
2
|
import { expect, test, vi } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { json } from "../vmutil";
|
|
5
|
+
|
|
5
6
|
import marshalProperties from "./properties";
|
|
6
7
|
|
|
7
8
|
test("works", async () => {
|
|
8
|
-
const
|
|
9
|
-
const descTester =
|
|
10
|
-
|
|
9
|
+
const ctx = (await getQuickJS()).newContext();
|
|
10
|
+
const descTester = ctx.unwrapResult(
|
|
11
|
+
ctx.evalCode(`(obj, expected) => {
|
|
11
12
|
const descs = Object.getOwnPropertyDescriptors(obj);
|
|
12
13
|
for (const [k, v] of Object.entries(expected)) {
|
|
13
14
|
const d = descs[k];
|
|
@@ -18,18 +19,18 @@ test("works", async () => {
|
|
|
18
19
|
if (typeof v.configurable === "boolean" && d.configurable !== v.configurable) throw new Error(k + " configurable invalid: " + d.configurable);
|
|
19
20
|
if (typeof v.writable === "boolean" && d.writable !== v.writable) throw new Error(k + " writable invalid: " + d.writable);
|
|
20
21
|
}
|
|
21
|
-
}`)
|
|
22
|
+
}`),
|
|
22
23
|
);
|
|
23
24
|
|
|
24
25
|
const disposables: QuickJSHandle[] = [];
|
|
25
|
-
const marshal = vi.fn(
|
|
26
|
-
if (typeof t !== "function") return json(
|
|
27
|
-
const fn =
|
|
26
|
+
const marshal = vi.fn(t => {
|
|
27
|
+
if (typeof t !== "function") return json(ctx, t);
|
|
28
|
+
const fn = ctx.newFunction("", () => {});
|
|
28
29
|
disposables.push(fn);
|
|
29
30
|
return fn;
|
|
30
31
|
});
|
|
31
32
|
|
|
32
|
-
const handle =
|
|
33
|
+
const handle = ctx.newObject();
|
|
33
34
|
const obj = {};
|
|
34
35
|
const bar = () => {};
|
|
35
36
|
const fooGet = () => {};
|
|
@@ -49,39 +50,33 @@ test("works", async () => {
|
|
|
49
50
|
},
|
|
50
51
|
});
|
|
51
52
|
|
|
52
|
-
marshalProperties(
|
|
53
|
-
expect(marshal.mock.calls).toEqual([
|
|
54
|
-
["bar"],
|
|
55
|
-
[bar],
|
|
56
|
-
["foo"],
|
|
57
|
-
[fooGet],
|
|
58
|
-
[fooSet],
|
|
59
|
-
]);
|
|
53
|
+
marshalProperties(ctx, obj, handle, marshal);
|
|
54
|
+
expect(marshal.mock.calls).toEqual([["bar"], [bar], ["foo"], [fooGet], [fooSet]]);
|
|
60
55
|
|
|
61
|
-
const expected =
|
|
62
|
-
|
|
56
|
+
const expected = ctx.unwrapResult(
|
|
57
|
+
ctx.evalCode(`({
|
|
63
58
|
bar: { valueType: "function", getType: "undefined", setType: "undefined", enumerable: true, configurable: true, writable: true },
|
|
64
59
|
foo: { valueType: "undefined", getType: "function", setType: "function", enumerable: false, configurable: true }
|
|
65
|
-
})`)
|
|
60
|
+
})`),
|
|
66
61
|
);
|
|
67
|
-
|
|
62
|
+
ctx.unwrapResult(ctx.callFunction(descTester, ctx.undefined, handle, expected));
|
|
68
63
|
|
|
69
64
|
expected.dispose();
|
|
70
|
-
disposables.forEach(
|
|
65
|
+
disposables.forEach(d => d.dispose());
|
|
71
66
|
handle.dispose();
|
|
72
67
|
descTester.dispose();
|
|
73
|
-
|
|
68
|
+
ctx.dispose();
|
|
74
69
|
});
|
|
75
70
|
|
|
76
71
|
test("empty", async () => {
|
|
77
|
-
const
|
|
72
|
+
const ctx = (await getQuickJS()).newContext();
|
|
78
73
|
const marshal = vi.fn();
|
|
79
|
-
const handle =
|
|
74
|
+
const handle = ctx.newObject();
|
|
80
75
|
const obj = {};
|
|
81
76
|
|
|
82
|
-
marshalProperties(
|
|
77
|
+
marshalProperties(ctx, obj, handle, marshal);
|
|
83
78
|
expect(marshal).toHaveBeenCalledTimes(0);
|
|
84
79
|
|
|
85
80
|
handle.dispose();
|
|
86
|
-
|
|
81
|
+
ctx.dispose();
|
|
87
82
|
});
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import { call } from "../vmutil";
|
|
3
4
|
|
|
4
5
|
export default function marshalProperties(
|
|
5
|
-
|
|
6
|
+
ctx: QuickJSContext,
|
|
6
7
|
target: object | Function,
|
|
7
8
|
handle: QuickJSHandle,
|
|
8
|
-
marshal: (target: unknown) => QuickJSHandle
|
|
9
|
+
marshal: (target: unknown) => QuickJSHandle,
|
|
9
10
|
): void {
|
|
10
|
-
const descs =
|
|
11
|
+
const descs = ctx.newObject();
|
|
11
12
|
const cb = (key: string | number | symbol, desc: PropertyDescriptor) => {
|
|
12
13
|
const keyHandle = marshal(key);
|
|
13
|
-
const valueHandle =
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
typeof desc.get === "undefined" ? undefined : marshal(desc.get);
|
|
17
|
-
const setHandle =
|
|
18
|
-
typeof desc.set === "undefined" ? undefined : marshal(desc.set);
|
|
14
|
+
const valueHandle = typeof desc.value === "undefined" ? undefined : marshal(desc.value);
|
|
15
|
+
const getHandle = typeof desc.get === "undefined" ? undefined : marshal(desc.get);
|
|
16
|
+
const setHandle = typeof desc.set === "undefined" ? undefined : marshal(desc.set);
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
ctx.newObject().consume(descObj => {
|
|
21
19
|
Object.entries(desc).forEach(([k, v]) => {
|
|
22
20
|
const v2 =
|
|
23
21
|
k === "value"
|
|
@@ -27,21 +25,21 @@ export default function marshalProperties(
|
|
|
27
25
|
: k === "set"
|
|
28
26
|
? setHandle
|
|
29
27
|
: v
|
|
30
|
-
?
|
|
31
|
-
:
|
|
28
|
+
? ctx.true
|
|
29
|
+
: ctx.false;
|
|
32
30
|
if (v2) {
|
|
33
|
-
|
|
31
|
+
ctx.setProp(descObj, k, v2);
|
|
34
32
|
}
|
|
35
33
|
});
|
|
36
|
-
|
|
34
|
+
ctx.setProp(descs, keyHandle, descObj);
|
|
37
35
|
});
|
|
38
36
|
};
|
|
39
37
|
|
|
40
38
|
const desc = Object.getOwnPropertyDescriptors(target);
|
|
41
39
|
Object.entries(desc).forEach(([k, v]) => cb(k, v));
|
|
42
|
-
Object.getOwnPropertySymbols(desc).forEach(
|
|
40
|
+
Object.getOwnPropertySymbols(desc).forEach(k => cb(k, (desc as any)[k]));
|
|
43
41
|
|
|
44
|
-
call(
|
|
42
|
+
call(ctx, `Object.defineProperties`, undefined, handle, descs).dispose();
|
|
45
43
|
|
|
46
44
|
descs.dispose();
|
|
47
45
|
}
|