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