quickjs-emscripten-sync 1.2.0 → 1.3.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 +13 -9
- package/dist/index.d.ts +106 -20
- package/dist/quickjs-emscripten-sync.es.js +951 -0
- package/dist/quickjs-emscripten-sync.umd.js +64 -2
- package/package.json +24 -46
- package/src/index.test.ts +70 -0
- package/src/index.ts +9 -4
- package/src/marshal/function.test.ts +8 -7
- package/src/marshal/index.test.ts +46 -5
- package/src/marshal/index.ts +9 -3
- package/src/marshal/json.test.ts +5 -3
- package/src/marshal/object.test.ts +9 -7
- package/src/marshal/primitive.test.ts +2 -0
- package/src/marshal/promise.test.ts +86 -0
- package/src/marshal/promise.ts +26 -0
- package/src/marshal/properties.test.ts +4 -2
- package/src/marshal/symbol.test.ts +3 -1
- package/src/unmarshal/function.test.ts +15 -16
- package/src/unmarshal/index.test.ts +81 -84
- package/src/unmarshal/index.ts +4 -2
- package/src/unmarshal/object.test.ts +11 -9
- package/src/unmarshal/primitive.test.ts +2 -0
- package/src/unmarshal/promise.test.ts +44 -0
- package/src/unmarshal/promise.ts +40 -0
- package/src/unmarshal/properties.test.ts +3 -1
- package/src/unmarshal/symbol.test.ts +3 -1
- package/src/util.test.ts +19 -2
- package/src/util.ts +15 -0
- package/src/vmmap.test.ts +22 -0
- package/src/vmmap.ts +4 -0
- package/src/vmutil.test.ts +44 -3
- package/src/vmutil.ts +47 -7
- package/src/wrapper.test.ts +24 -22
- 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
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
import { newDeferred } from "../util";
|
|
9
|
+
|
|
10
|
+
import { fn, json } from "../vmutil";
|
|
11
|
+
import marshalPromise from "./promise";
|
|
12
|
+
|
|
13
|
+
const testPromise = (reject: boolean) => async () => {
|
|
14
|
+
const vm = (await getQuickJS()).createVm();
|
|
15
|
+
|
|
16
|
+
const disposables: Disposable[] = [];
|
|
17
|
+
const marshal = vi.fn((v) => {
|
|
18
|
+
const handle = json(vm, v);
|
|
19
|
+
disposables.push(handle);
|
|
20
|
+
return handle;
|
|
21
|
+
});
|
|
22
|
+
const preMarshal = vi.fn(
|
|
23
|
+
(_: any, a: QuickJSDeferredPromise): QuickJSHandle => {
|
|
24
|
+
disposables.push(a);
|
|
25
|
+
return a.handle;
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const mockNotify = vi.fn();
|
|
30
|
+
const notify = vm.newFunction("notify", (handle1, handle2) => {
|
|
31
|
+
const arg1 = vm.dump(handle1);
|
|
32
|
+
const arg2 = vm.dump(handle2);
|
|
33
|
+
mockNotify(arg1, arg2);
|
|
34
|
+
});
|
|
35
|
+
disposables.push(notify);
|
|
36
|
+
|
|
37
|
+
const notifier = fn(
|
|
38
|
+
vm,
|
|
39
|
+
`(notify, promise) => { promise.then(d => notify("resolved", d), d => notify("rejected", d)); }`
|
|
40
|
+
);
|
|
41
|
+
disposables.push(notifier);
|
|
42
|
+
|
|
43
|
+
const deferred = newDeferred();
|
|
44
|
+
if (reject) {
|
|
45
|
+
deferred.promise.catch(() => {});
|
|
46
|
+
}
|
|
47
|
+
const handle = marshalPromise(vm, deferred.promise, marshal, preMarshal);
|
|
48
|
+
if (!handle) throw new Error("handle is undefined");
|
|
49
|
+
|
|
50
|
+
expect(marshal).toBeCalledTimes(0);
|
|
51
|
+
expect(preMarshal).toBeCalledTimes(1);
|
|
52
|
+
expect(preMarshal.mock.calls[0][0]).toBe(deferred.promise);
|
|
53
|
+
expect(preMarshal.mock.calls[0][1].handle).toBe(handle);
|
|
54
|
+
|
|
55
|
+
notifier(undefined, notify, handle);
|
|
56
|
+
|
|
57
|
+
expect(mockNotify).toBeCalledTimes(0);
|
|
58
|
+
expect(deferred.resolve).not.toBeUndefined();
|
|
59
|
+
expect(vm.hasPendingJob()).toBe(false);
|
|
60
|
+
|
|
61
|
+
if (reject) {
|
|
62
|
+
deferred.reject("hoge");
|
|
63
|
+
} else {
|
|
64
|
+
deferred.resolve("hoge");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
expect(vm.hasPendingJob()).toBe(false);
|
|
68
|
+
if (reject) {
|
|
69
|
+
await expect(deferred.promise).rejects.toBe("hoge");
|
|
70
|
+
} else {
|
|
71
|
+
await expect(deferred.promise).resolves.toBe("hoge");
|
|
72
|
+
}
|
|
73
|
+
expect(vm.hasPendingJob()).toBe(true);
|
|
74
|
+
const executed = vm.unwrapResult(vm.executePendingJobs());
|
|
75
|
+
expect(executed).toBe(1);
|
|
76
|
+
expect(mockNotify).toBeCalledTimes(1);
|
|
77
|
+
expect(mockNotify).toBeCalledWith(reject ? "rejected" : "resolved", "hoge");
|
|
78
|
+
expect(marshal).toBeCalledTimes(1);
|
|
79
|
+
expect(marshal.mock.calls).toEqual([["hoge"]]);
|
|
80
|
+
|
|
81
|
+
disposables.forEach((h) => h.dispose());
|
|
82
|
+
vm.dispose();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
test("resolve", testPromise(false));
|
|
86
|
+
test("reject", testPromise(true));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
QuickJSDeferredPromise,
|
|
3
|
+
QuickJSHandle,
|
|
4
|
+
QuickJSVm,
|
|
5
|
+
} from "quickjs-emscripten";
|
|
6
|
+
|
|
7
|
+
export default function marshalPromise(
|
|
8
|
+
vm: QuickJSVm,
|
|
9
|
+
target: unknown,
|
|
10
|
+
marshal: (target: unknown) => QuickJSHandle,
|
|
11
|
+
preMarshal: (
|
|
12
|
+
target: unknown,
|
|
13
|
+
handle: QuickJSDeferredPromise
|
|
14
|
+
) => QuickJSHandle | undefined
|
|
15
|
+
) {
|
|
16
|
+
if (!(target instanceof Promise)) return;
|
|
17
|
+
|
|
18
|
+
const promise = vm.newPromise();
|
|
19
|
+
|
|
20
|
+
target.then(
|
|
21
|
+
(d) => promise.resolve(marshal(d)),
|
|
22
|
+
(d) => promise.reject(marshal(d))
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return preMarshal(target, promise) ?? promise.handle;
|
|
26
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import { json } from "../vmutil";
|
|
3
5
|
import marshalProperties from "./properties";
|
|
4
6
|
|
|
@@ -20,7 +22,7 @@ test("works", async () => {
|
|
|
20
22
|
);
|
|
21
23
|
|
|
22
24
|
const disposables: QuickJSHandle[] = [];
|
|
23
|
-
const marshal =
|
|
25
|
+
const marshal = vi.fn((t) => {
|
|
24
26
|
if (typeof t !== "function") return json(vm, t);
|
|
25
27
|
const fn = vm.newFunction("", () => {});
|
|
26
28
|
disposables.push(fn);
|
|
@@ -73,7 +75,7 @@ test("works", async () => {
|
|
|
73
75
|
|
|
74
76
|
test("empty", async () => {
|
|
75
77
|
const vm = (await getQuickJS()).createVm();
|
|
76
|
-
const marshal =
|
|
78
|
+
const marshal = vi.fn();
|
|
77
79
|
const handle = vm.newObject();
|
|
78
80
|
const obj = {};
|
|
79
81
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import marshalSymbol from "./symbol";
|
|
3
5
|
|
|
4
6
|
test("works", async () => {
|
|
5
7
|
const vm = (await getQuickJS()).createVm();
|
|
6
|
-
const pre =
|
|
8
|
+
const pre = vi.fn();
|
|
7
9
|
const sym = Symbol("foobar");
|
|
8
10
|
|
|
9
11
|
expect(marshalSymbol(vm, {}, pre)).toBe(undefined);
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import { json } from "../vmutil";
|
|
3
5
|
import unmarshalFunction from "./function";
|
|
4
6
|
|
|
5
7
|
test("arrow function", async () => {
|
|
6
8
|
const vm = (await getQuickJS()).createVm();
|
|
7
|
-
const marshal =
|
|
8
|
-
|
|
9
|
-
false,
|
|
10
|
-
]);
|
|
11
|
-
const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
9
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [json(vm, v), false]);
|
|
10
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
12
11
|
vm.dump(v),
|
|
13
12
|
false,
|
|
14
13
|
]);
|
|
15
|
-
const preUnmarshal =
|
|
14
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
16
15
|
|
|
17
16
|
const handle = vm.unwrapResult(vm.evalCode(`(a, b) => a + b`));
|
|
18
17
|
const func = unmarshalFunction(vm, handle, marshal, unmarshal, preUnmarshal);
|
|
@@ -42,17 +41,17 @@ test("function", async () => {
|
|
|
42
41
|
const vm = (await getQuickJS()).createVm();
|
|
43
42
|
const that = { a: 1 };
|
|
44
43
|
const thatHandle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
|
|
45
|
-
const marshal =
|
|
44
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
46
45
|
v === that ? thatHandle : json(vm, v),
|
|
47
46
|
false,
|
|
48
47
|
]);
|
|
49
48
|
const disposables: QuickJSHandle[] = [];
|
|
50
|
-
const unmarshal =
|
|
49
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
51
50
|
const ty = vm.typeof(v);
|
|
52
51
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
53
52
|
return [vm.dump(v), false];
|
|
54
53
|
});
|
|
55
|
-
const preUnmarshal =
|
|
54
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
56
55
|
|
|
57
56
|
const handle = vm.unwrapResult(
|
|
58
57
|
vm.evalCode(`(function (a) { return this.a + a; })`)
|
|
@@ -85,16 +84,16 @@ test("function", async () => {
|
|
|
85
84
|
test("constructor", async () => {
|
|
86
85
|
const vm = (await getQuickJS()).createVm();
|
|
87
86
|
const disposables: QuickJSHandle[] = [];
|
|
88
|
-
const marshal =
|
|
87
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
89
88
|
typeof v === "object" ? vm.undefined : json(vm, v),
|
|
90
89
|
false,
|
|
91
90
|
]);
|
|
92
|
-
const unmarshal =
|
|
91
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
93
92
|
const ty = vm.typeof(v);
|
|
94
93
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
95
94
|
return [vm.dump(v), false];
|
|
96
95
|
});
|
|
97
|
-
const preUnmarshal =
|
|
96
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
98
97
|
|
|
99
98
|
const handle = vm.unwrapResult(
|
|
100
99
|
vm.evalCode(`(function (b) { this.a = b + 2; })`)
|
|
@@ -133,17 +132,17 @@ test("constructor", async () => {
|
|
|
133
132
|
|
|
134
133
|
test("class", async () => {
|
|
135
134
|
const vm = (await getQuickJS()).createVm();
|
|
136
|
-
const marshal =
|
|
135
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
137
136
|
typeof v === "object" ? vm.undefined : json(vm, v),
|
|
138
137
|
false,
|
|
139
138
|
]);
|
|
140
139
|
const disposables: QuickJSHandle[] = [];
|
|
141
|
-
const unmarshal =
|
|
140
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
142
141
|
const ty = vm.typeof(v);
|
|
143
142
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
144
143
|
return [vm.dump(v), false];
|
|
145
144
|
});
|
|
146
|
-
const preUnmarshal =
|
|
145
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
147
146
|
|
|
148
147
|
const handle = vm.unwrapResult(
|
|
149
148
|
vm.evalCode(`(class A { constructor(a) { this.a = a + 1; } })`)
|
|
@@ -182,7 +181,7 @@ test("class", async () => {
|
|
|
182
181
|
|
|
183
182
|
test("undefined", async () => {
|
|
184
183
|
const vm = (await getQuickJS()).createVm();
|
|
185
|
-
const f =
|
|
184
|
+
const f = vi.fn();
|
|
186
185
|
|
|
187
186
|
expect(unmarshalFunction(vm, vm.undefined, f, f, f)).toEqual(undefined);
|
|
188
187
|
expect(unmarshalFunction(vm, vm.true, f, f, f)).toEqual(undefined);
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
1
|
+
import { Disposable, getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import VMMap from "../vmmap";
|
|
3
5
|
import unmarshal from ".";
|
|
6
|
+
import { json } from "../vmutil";
|
|
4
7
|
|
|
5
8
|
test("primitive, array, object", async () => {
|
|
6
|
-
const vm =
|
|
7
|
-
const marshal = jest.fn((): [QuickJSHandle, boolean] => [
|
|
8
|
-
vm.undefined,
|
|
9
|
-
false,
|
|
10
|
-
]);
|
|
11
|
-
const map = new VMMap(vm);
|
|
12
|
-
const find = jest.fn((h) => map.getByHandle(h));
|
|
13
|
-
const pre = jest.fn((t: any, h: QuickJSHandle) => {
|
|
14
|
-
map.set(t, h);
|
|
15
|
-
return t;
|
|
16
|
-
});
|
|
9
|
+
const { vm, unmarshal, marshal, map, dispose } = await setup();
|
|
17
10
|
|
|
18
11
|
const handle = vm.unwrapResult(
|
|
19
12
|
vm.evalCode(`({
|
|
@@ -24,7 +17,7 @@ test("primitive, array, object", async () => {
|
|
|
24
17
|
bbb: () => "bar"
|
|
25
18
|
})`)
|
|
26
19
|
);
|
|
27
|
-
const target = unmarshal(handle
|
|
20
|
+
const target = unmarshal(handle);
|
|
28
21
|
|
|
29
22
|
expect(target).toEqual({
|
|
30
23
|
hoge: "foo",
|
|
@@ -53,18 +46,11 @@ test("primitive, array, object", async () => {
|
|
|
53
46
|
expect(marshal).toBeCalledTimes(1);
|
|
54
47
|
expect(marshal).toBeCalledWith(target); // thisArg of target.bbb()
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
map.dispose();
|
|
58
|
-
vm.dispose();
|
|
49
|
+
dispose();
|
|
59
50
|
});
|
|
60
51
|
|
|
61
52
|
test("object with symbol key", async () => {
|
|
62
|
-
const vm =
|
|
63
|
-
const map = new VMMap(vm);
|
|
64
|
-
const pre = (t: any, h: QuickJSHandle) => {
|
|
65
|
-
map.set(t, h);
|
|
66
|
-
return t;
|
|
67
|
-
};
|
|
53
|
+
const { vm, unmarshal, dispose } = await setup();
|
|
68
54
|
|
|
69
55
|
const handle = vm.unwrapResult(
|
|
70
56
|
vm.evalCode(`({
|
|
@@ -72,79 +58,57 @@ test("object with symbol key", async () => {
|
|
|
72
58
|
[Symbol("a")]: "bar"
|
|
73
59
|
})`)
|
|
74
60
|
);
|
|
75
|
-
const target = unmarshal(handle
|
|
76
|
-
vm,
|
|
77
|
-
pre,
|
|
78
|
-
find: () => undefined,
|
|
79
|
-
marshal: () => [vm.undefined, false],
|
|
80
|
-
});
|
|
61
|
+
const target = unmarshal(handle);
|
|
81
62
|
|
|
82
63
|
expect(target.hoge).toBe("foo");
|
|
83
64
|
expect(target[Object.getOwnPropertySymbols(target)[0]]).toBe("bar");
|
|
84
65
|
|
|
85
|
-
|
|
86
|
-
map.dispose();
|
|
87
|
-
vm.dispose();
|
|
66
|
+
dispose();
|
|
88
67
|
});
|
|
89
68
|
|
|
90
|
-
test("
|
|
91
|
-
const vm =
|
|
92
|
-
const jsonParse = vm.unwrapResult(vm.evalCode(`JSON.parse`));
|
|
93
|
-
const disposables: QuickJSHandle[] = [];
|
|
94
|
-
const marshal = jest.fn((t: unknown): [QuickJSHandle, boolean] => {
|
|
95
|
-
const h =
|
|
96
|
-
t === undefined
|
|
97
|
-
? vm.undefined
|
|
98
|
-
: vm.unwrapResult(
|
|
99
|
-
vm.callFunction(
|
|
100
|
-
jsonParse,
|
|
101
|
-
vm.undefined,
|
|
102
|
-
vm.newString(JSON.stringify(t))
|
|
103
|
-
)
|
|
104
|
-
);
|
|
105
|
-
const ty = vm.typeof(h);
|
|
106
|
-
if (ty === "object" || ty === "function") disposables.push(h);
|
|
107
|
-
return [h, false];
|
|
108
|
-
});
|
|
69
|
+
test("function", async () => {
|
|
70
|
+
const { vm, unmarshal, marshal, map, dispose } = await setup();
|
|
109
71
|
|
|
110
72
|
const handle = vm.unwrapResult(
|
|
111
73
|
vm.evalCode(`(function(a) { return a.a + "!"; })`)
|
|
112
74
|
);
|
|
113
|
-
const
|
|
114
|
-
const find = jest.fn((h) => map.getByHandle(h));
|
|
115
|
-
const pre = jest.fn((t: any, h: QuickJSHandle) => {
|
|
116
|
-
map.set(t, h);
|
|
117
|
-
return t;
|
|
118
|
-
});
|
|
119
|
-
const func = unmarshal(handle, { vm, find, pre, marshal });
|
|
75
|
+
const func = unmarshal(handle);
|
|
120
76
|
const arg = { a: "hoge" };
|
|
121
77
|
expect(func(arg)).toBe("hoge!");
|
|
122
78
|
expect(marshal).toBeCalledTimes(2);
|
|
123
79
|
expect(marshal).toBeCalledWith(undefined); // this
|
|
124
80
|
expect(marshal).toBeCalledWith(arg); // arg
|
|
125
|
-
expect(map.size).toBe(
|
|
81
|
+
expect(map.size).toBe(3);
|
|
126
82
|
expect(map.getByHandle(handle)).toBe(func);
|
|
83
|
+
expect(map.has(func)).toBe(true);
|
|
127
84
|
expect(map.has(func.prototype)).toBe(true);
|
|
85
|
+
expect(map.has(arg)).toBe(true);
|
|
86
|
+
|
|
87
|
+
dispose();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("promise", async () => {
|
|
91
|
+
const { vm, unmarshal, dispose } = await setup();
|
|
92
|
+
|
|
93
|
+
const deferred = vm.newPromise();
|
|
94
|
+
const promise = unmarshal(deferred.handle);
|
|
95
|
+
deferred.resolve(vm.newString("resolved!"));
|
|
96
|
+
vm.executePendingJobs();
|
|
97
|
+
await expect(promise).resolves.toBe("resolved!");
|
|
128
98
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
vm.
|
|
99
|
+
const deferred2 = vm.newPromise();
|
|
100
|
+
const promise2 = unmarshal(deferred2.handle);
|
|
101
|
+
deferred2.reject(vm.newString("rejected!"));
|
|
102
|
+
vm.executePendingJobs();
|
|
103
|
+
await expect(promise2).rejects.toBe("rejected!");
|
|
104
|
+
|
|
105
|
+
deferred.dispose();
|
|
106
|
+
deferred2.dispose();
|
|
107
|
+
dispose();
|
|
133
108
|
});
|
|
134
109
|
|
|
135
110
|
test("class", async () => {
|
|
136
|
-
const vm =
|
|
137
|
-
const jsonParse = vm.unwrapResult(vm.evalCode(`JSON.parse`));
|
|
138
|
-
const disposables: QuickJSHandle[] = [];
|
|
139
|
-
const map = new VMMap(vm);
|
|
140
|
-
const marshal = jest.fn((t: unknown): [QuickJSHandle, boolean] => {
|
|
141
|
-
const h = vm.unwrapResult(
|
|
142
|
-
vm.callFunction(jsonParse, vm.undefined, vm.newString(JSON.stringify(t)))
|
|
143
|
-
);
|
|
144
|
-
const ty = vm.typeof(h);
|
|
145
|
-
if (ty === "object" || ty === "function") disposables.push(h);
|
|
146
|
-
return [h, false];
|
|
147
|
-
});
|
|
111
|
+
const { vm, unmarshal, dispose } = await setup();
|
|
148
112
|
|
|
149
113
|
const handle = vm.unwrapResult(
|
|
150
114
|
vm.evalCode(`{
|
|
@@ -160,12 +124,7 @@ test("class", async () => {
|
|
|
160
124
|
Cls
|
|
161
125
|
}`)
|
|
162
126
|
);
|
|
163
|
-
const
|
|
164
|
-
const pre = jest.fn((t: any, h: QuickJSHandle) => {
|
|
165
|
-
map.set(t, h);
|
|
166
|
-
return t;
|
|
167
|
-
});
|
|
168
|
-
const Cls = unmarshal(handle, { vm, find, pre, marshal });
|
|
127
|
+
const Cls = unmarshal(handle);
|
|
169
128
|
|
|
170
129
|
expect(Cls.hoge).toBe("foo");
|
|
171
130
|
expect(Cls.foo instanceof Cls).toBe(true);
|
|
@@ -175,8 +134,46 @@ test("class", async () => {
|
|
|
175
134
|
expect(cls.foo).toBe(4);
|
|
176
135
|
|
|
177
136
|
handle.dispose();
|
|
178
|
-
|
|
179
|
-
disposables.forEach((d) => d.dispose());
|
|
180
|
-
jsonParse.dispose();
|
|
181
|
-
vm.dispose();
|
|
137
|
+
dispose();
|
|
182
138
|
});
|
|
139
|
+
|
|
140
|
+
const setup = async () => {
|
|
141
|
+
const vm = (await getQuickJS()).createVm();
|
|
142
|
+
const map = new VMMap(vm);
|
|
143
|
+
const disposables: QuickJSHandle[] = [];
|
|
144
|
+
const marshal = vi.fn((target: unknown): [QuickJSHandle, boolean] => {
|
|
145
|
+
const handle = map.get(target);
|
|
146
|
+
if (handle) return [handle, false];
|
|
147
|
+
|
|
148
|
+
const handle2 =
|
|
149
|
+
typeof target === "function"
|
|
150
|
+
? vm.newFunction(target.name, (...handles) => {
|
|
151
|
+
target(...handles.map((h) => vm.dump(h)));
|
|
152
|
+
})
|
|
153
|
+
: json(vm, target);
|
|
154
|
+
const ty = vm.typeof(handle2);
|
|
155
|
+
if (ty === "object" || ty === "function") map.set(target, handle2);
|
|
156
|
+
return [handle2, false];
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
vm,
|
|
161
|
+
map,
|
|
162
|
+
unmarshal: (handle: QuickJSHandle) =>
|
|
163
|
+
unmarshal(handle, {
|
|
164
|
+
find: (h) => map.getByHandle(h),
|
|
165
|
+
marshal,
|
|
166
|
+
pre: (t, h) => {
|
|
167
|
+
map.set(t, h);
|
|
168
|
+
return t;
|
|
169
|
+
},
|
|
170
|
+
vm,
|
|
171
|
+
}),
|
|
172
|
+
marshal,
|
|
173
|
+
dispose: () => {
|
|
174
|
+
disposables.forEach((d) => d.dispose());
|
|
175
|
+
map.dispose();
|
|
176
|
+
vm.dispose();
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
};
|
package/src/unmarshal/index.ts
CHANGED
|
@@ -2,14 +2,15 @@ import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
|
|
|
2
2
|
import unmarshalFunction from "./function";
|
|
3
3
|
import unmarshalObject from "./object";
|
|
4
4
|
import unmarshalPrimitive from "./primitive";
|
|
5
|
+
import unmarshalPromise from "./promise";
|
|
5
6
|
import unmarshalSymbol from "./symbol";
|
|
6
7
|
|
|
7
8
|
export type Options = {
|
|
8
9
|
vm: QuickJSVm;
|
|
9
|
-
|
|
10
|
+
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
10
11
|
marshal: (target: unknown) => [QuickJSHandle, boolean];
|
|
11
12
|
find: (handle: QuickJSHandle) => unknown | undefined;
|
|
12
|
-
pre: <T>(target: T, handle: QuickJSHandle) => T | undefined;
|
|
13
|
+
pre: <T = unknown>(target: T, handle: QuickJSHandle) => T | undefined;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export function unmarshal(handle: QuickJSHandle, options: Options): any {
|
|
@@ -39,6 +40,7 @@ function unmarshalInner(
|
|
|
39
40
|
|
|
40
41
|
const result =
|
|
41
42
|
unmarshalSymbol(vm, handle, pre) ??
|
|
43
|
+
unmarshalPromise(vm, handle, marshal, pre) ??
|
|
42
44
|
unmarshalFunction(vm, handle, marshal, unmarshal2, pre) ??
|
|
43
45
|
unmarshalObject(vm, handle, unmarshal2, pre);
|
|
44
46
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import unmarshalObject from "./object";
|
|
3
5
|
|
|
4
6
|
test("normal object", async () => {
|
|
5
7
|
const vm = (await getQuickJS()).createVm();
|
|
6
|
-
const unmarshal =
|
|
8
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
7
9
|
vm.dump(v),
|
|
8
10
|
false,
|
|
9
11
|
]);
|
|
10
|
-
const preUnmarshal =
|
|
12
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
11
13
|
|
|
12
14
|
const handle = vm.unwrapResult(vm.evalCode(`({ a: 1, b: true })`));
|
|
13
15
|
const obj = unmarshalObject(vm, handle, unmarshal, preUnmarshal);
|
|
@@ -28,11 +30,11 @@ test("normal object", async () => {
|
|
|
28
30
|
test("properties", async () => {
|
|
29
31
|
const vm = (await getQuickJS()).createVm();
|
|
30
32
|
const disposables: QuickJSHandle[] = [];
|
|
31
|
-
const unmarshal =
|
|
33
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
32
34
|
disposables.push(v);
|
|
33
35
|
return [vm.typeof(v) === "function" ? () => {} : vm.dump(v), false];
|
|
34
36
|
});
|
|
35
|
-
const preUnmarshal =
|
|
37
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
36
38
|
|
|
37
39
|
const handle = vm.unwrapResult(
|
|
38
40
|
vm.evalCode(`{
|
|
@@ -77,11 +79,11 @@ test("properties", async () => {
|
|
|
77
79
|
|
|
78
80
|
test("array", async () => {
|
|
79
81
|
const vm = (await getQuickJS()).createVm();
|
|
80
|
-
const unmarshal =
|
|
82
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
81
83
|
vm.dump(v),
|
|
82
84
|
false,
|
|
83
85
|
]);
|
|
84
|
-
const preUnmarshal =
|
|
86
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
85
87
|
|
|
86
88
|
const handle = vm.unwrapResult(vm.evalCode(`[1, true, "a"]`));
|
|
87
89
|
const array = unmarshalObject(vm, handle, unmarshal, preUnmarshal);
|
|
@@ -103,11 +105,11 @@ test("array", async () => {
|
|
|
103
105
|
|
|
104
106
|
test("prototype", async () => {
|
|
105
107
|
const vm = (await getQuickJS()).createVm();
|
|
106
|
-
const unmarshal =
|
|
108
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
107
109
|
vm.typeof(v) === "object" ? { a: () => 1 } : vm.dump(v),
|
|
108
110
|
false,
|
|
109
111
|
]);
|
|
110
|
-
const preUnmarshal =
|
|
112
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
111
113
|
|
|
112
114
|
const handle = vm.unwrapResult(vm.evalCode(`Object.create({ a: () => 1 })`));
|
|
113
115
|
const obj = unmarshalObject(vm, handle, unmarshal, preUnmarshal) as any;
|
|
@@ -125,7 +127,7 @@ test("prototype", async () => {
|
|
|
125
127
|
|
|
126
128
|
test("undefined", async () => {
|
|
127
129
|
const vm = (await getQuickJS()).createVm();
|
|
128
|
-
const f =
|
|
130
|
+
const f = vi.fn();
|
|
129
131
|
|
|
130
132
|
expect(unmarshalObject(vm, vm.undefined, f, f)).toEqual(undefined);
|
|
131
133
|
expect(unmarshalObject(vm, vm.true, f, f)).toEqual(undefined);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Disposable, getQuickJS, type QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import unmarshalPromise from "./promise";
|
|
5
|
+
|
|
6
|
+
const testPromise = (reject: boolean) => async () => {
|
|
7
|
+
const vm = (await getQuickJS()).createVm();
|
|
8
|
+
const disposables: Disposable[] = [];
|
|
9
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => {
|
|
10
|
+
const f = vm.newFunction(v.name, (h) => {
|
|
11
|
+
v(vm.dump(h));
|
|
12
|
+
});
|
|
13
|
+
disposables.push(f);
|
|
14
|
+
return [f, false];
|
|
15
|
+
});
|
|
16
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
17
|
+
|
|
18
|
+
const deferred = vm.newPromise();
|
|
19
|
+
disposables.push(deferred);
|
|
20
|
+
const promise = unmarshalPromise(vm, deferred.handle, marshal, preUnmarshal);
|
|
21
|
+
|
|
22
|
+
expect(marshal).toBeCalledTimes(2);
|
|
23
|
+
expect(preUnmarshal).toBeCalledTimes(1);
|
|
24
|
+
expect(vm.hasPendingJob()).toBe(false);
|
|
25
|
+
|
|
26
|
+
if (reject) {
|
|
27
|
+
deferred.reject(vm.newString("hoge"));
|
|
28
|
+
} else {
|
|
29
|
+
deferred.resolve(vm.newString("hoge"));
|
|
30
|
+
}
|
|
31
|
+
expect(vm.hasPendingJob()).toBe(true);
|
|
32
|
+
expect(vm.unwrapResult(vm.executePendingJobs())).toBe(1);
|
|
33
|
+
if (reject) {
|
|
34
|
+
expect(promise).rejects.toThrow("hoge");
|
|
35
|
+
} else {
|
|
36
|
+
expect(promise).resolves.toBe("hoge");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
disposables.forEach((d) => d.dispose());
|
|
40
|
+
vm.dispose();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
test("resolve", testPromise(false));
|
|
44
|
+
test("reject", testPromise(true));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
3
|
+
import { newDeferred } from "../util";
|
|
4
|
+
import { call, instanceOf } from "../vmutil";
|
|
5
|
+
|
|
6
|
+
export default function unmarshalPromise<T = unknown>(
|
|
7
|
+
vm: QuickJSVm,
|
|
8
|
+
handle: QuickJSHandle,
|
|
9
|
+
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
10
|
+
marshal: (value: unknown) => [QuickJSHandle, boolean],
|
|
11
|
+
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
12
|
+
): Promise<T> | undefined {
|
|
13
|
+
if (!isPromiseHandle(handle)) return;
|
|
14
|
+
|
|
15
|
+
const deferred = newDeferred<T>();
|
|
16
|
+
const [resHandle, resShouldBeDisposed] = marshal(deferred.resolve);
|
|
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
|
+
);
|
|
26
|
+
if (resShouldBeDisposed) resHandle.dispose();
|
|
27
|
+
if (rejShouldBeDisposed) rejHandle.dispose();
|
|
28
|
+
|
|
29
|
+
return preUnmarshal(deferred.promise, handle) ?? deferred.promise;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isPromiseHandle(handle: QuickJSHandle): boolean {
|
|
33
|
+
if (!handle.owner) return false;
|
|
34
|
+
return handle.owner
|
|
35
|
+
.unwrapResult(handle.owner.evalCode("Promise"))
|
|
36
|
+
.consume((promise) => {
|
|
37
|
+
if (!handle.owner) return false;
|
|
38
|
+
return instanceOf(handle.owner, handle, promise);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import unmarshalProperties from "./properties";
|
|
3
5
|
|
|
4
6
|
test("works", async () => {
|
|
5
7
|
const vm = (await getQuickJS()).createVm();
|
|
6
8
|
const disposables: QuickJSHandle[] = [];
|
|
7
|
-
const unmarshal =
|
|
9
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
8
10
|
disposables.push(v);
|
|
9
11
|
return [vm.typeof(v) === "function" ? () => {} : vm.dump(v), false];
|
|
10
12
|
});
|