quickjs-emscripten-sync 1.1.0 → 1.4.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 +59 -49
- package/dist/index.d.ts +121 -26
- package/dist/quickjs-emscripten-sync.es.js +962 -0
- package/dist/quickjs-emscripten-sync.umd.js +64 -0
- package/package.json +28 -40
- package/src/default.ts +2 -2
- package/src/index.test.ts +371 -69
- package/src/index.ts +135 -72
- package/src/marshal/function.test.ts +70 -61
- package/src/marshal/function.ts +10 -9
- package/src/marshal/index.test.ts +135 -62
- package/src/marshal/index.ts +33 -16
- package/src/marshal/json.test.ts +94 -0
- package/src/marshal/json.ts +16 -0
- package/src/marshal/object.test.ts +65 -58
- package/src/marshal/object.ts +6 -5
- package/src/marshal/primitive.test.ts +23 -17
- package/src/marshal/primitive.ts +10 -9
- package/src/marshal/promise.test.ts +86 -0
- package/src/marshal/promise.ts +26 -0
- package/src/marshal/properties.test.ts +23 -19
- package/src/marshal/properties.ts +11 -10
- package/src/marshal/symbol.test.ts +9 -7
- package/src/marshal/symbol.ts +5 -4
- package/src/unmarshal/function.test.ts +70 -61
- package/src/unmarshal/function.ts +39 -30
- package/src/unmarshal/index.test.ts +101 -100
- package/src/unmarshal/index.ts +13 -9
- package/src/unmarshal/object.test.ts +45 -41
- package/src/unmarshal/object.ts +14 -13
- package/src/unmarshal/primitive.test.ts +20 -15
- package/src/unmarshal/primitive.ts +10 -10
- package/src/unmarshal/promise.test.ts +44 -0
- package/src/unmarshal/promise.ts +38 -0
- package/src/unmarshal/properties.test.ts +10 -8
- package/src/unmarshal/properties.ts +47 -42
- package/src/unmarshal/symbol.test.ts +9 -7
- package/src/unmarshal/symbol.ts +4 -4
- package/src/util.test.ts +23 -5
- package/src/util.ts +15 -0
- package/src/vmmap.test.ts +88 -82
- package/src/vmmap.ts +21 -17
- package/src/vmutil.test.ts +159 -53
- package/src/vmutil.ts +91 -19
- package/src/wrapper.test.ts +151 -115
- package/src/wrapper.ts +69 -48
- package/dist/default.d.ts +0 -4
- package/dist/index.js +0 -8
- package/dist/marshal/function.d.ts +0 -2
- package/dist/marshal/index.d.ts +0 -11
- 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.development.js +0 -1289
- package/dist/quickjs-emscripten-sync.cjs.development.js.map +0 -1
- package/dist/quickjs-emscripten-sync.cjs.production.min.js +0 -2
- package/dist/quickjs-emscripten-sync.cjs.production.min.js.map +0 -1
- package/dist/quickjs-emscripten-sync.esm.js +0 -1272
- package/dist/quickjs-emscripten-sync.esm.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 -7
- package/dist/wrapper.d.ts +0 -11
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
-
import {
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { json } from "../vmutil";
|
|
3
5
|
import unmarshalFunction from "./function";
|
|
4
6
|
|
|
5
7
|
test("arrow function", async () => {
|
|
6
|
-
const
|
|
7
|
-
const marshal =
|
|
8
|
-
const unmarshal =
|
|
9
|
-
|
|
8
|
+
const ctx = (await getQuickJS()).newContext();
|
|
9
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [json(ctx, v), false]);
|
|
10
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
11
|
+
ctx.dump(v),
|
|
10
12
|
false,
|
|
11
13
|
]);
|
|
12
|
-
const preUnmarshal =
|
|
14
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
13
15
|
|
|
14
|
-
const handle =
|
|
15
|
-
const func = unmarshalFunction(
|
|
16
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`(a, b) => a + b`));
|
|
17
|
+
const func = unmarshalFunction(ctx, handle, marshal, unmarshal, preUnmarshal);
|
|
16
18
|
if (!func) throw new Error("func is undefined");
|
|
17
19
|
|
|
18
20
|
expect(func(1, 2)).toBe(3);
|
|
@@ -32,27 +34,30 @@ test("arrow function", async () => {
|
|
|
32
34
|
handle.dispose();
|
|
33
35
|
expect(() => func(1, 2)).toThrow("Lifetime not alive");
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
ctx.dispose();
|
|
36
38
|
});
|
|
37
39
|
|
|
38
40
|
test("function", async () => {
|
|
39
|
-
const
|
|
41
|
+
const ctx = (await getQuickJS()).newContext();
|
|
40
42
|
const that = { a: 1 };
|
|
41
|
-
const thatHandle =
|
|
42
|
-
const marshal =
|
|
43
|
+
const thatHandle = ctx.unwrapResult(ctx.evalCode(`({ a: 1 })`));
|
|
44
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
45
|
+
v === that ? thatHandle : json(ctx, v),
|
|
46
|
+
false,
|
|
47
|
+
]);
|
|
43
48
|
const disposables: QuickJSHandle[] = [];
|
|
44
|
-
const unmarshal =
|
|
45
|
-
const ty =
|
|
49
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
50
|
+
const ty = ctx.typeof(v);
|
|
46
51
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
47
|
-
return [
|
|
52
|
+
return [ctx.dump(v), false];
|
|
48
53
|
});
|
|
49
|
-
const preUnmarshal =
|
|
54
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
50
55
|
|
|
51
|
-
const handle =
|
|
52
|
-
|
|
56
|
+
const handle = ctx.unwrapResult(
|
|
57
|
+
ctx.evalCode(`(function (a) { return this.a + a; })`)
|
|
53
58
|
);
|
|
54
59
|
|
|
55
|
-
const func = unmarshalFunction(
|
|
60
|
+
const func = unmarshalFunction(ctx, handle, marshal, unmarshal, preUnmarshal);
|
|
56
61
|
if (!func) throw new Error("func is undefined");
|
|
57
62
|
|
|
58
63
|
expect(func.call(that, 2)).toBe(3);
|
|
@@ -70,31 +75,32 @@ test("function", async () => {
|
|
|
70
75
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
71
76
|
expect(preUnmarshal).toBeCalledWith(func, handle);
|
|
72
77
|
|
|
73
|
-
disposables.forEach(d => d.dispose());
|
|
78
|
+
disposables.forEach((d) => d.dispose());
|
|
74
79
|
thatHandle.dispose();
|
|
75
80
|
handle.dispose();
|
|
76
|
-
|
|
81
|
+
ctx.dispose();
|
|
77
82
|
});
|
|
78
83
|
|
|
79
84
|
test("constructor", async () => {
|
|
80
|
-
const
|
|
85
|
+
const ctx = (await getQuickJS()).newContext();
|
|
81
86
|
const disposables: QuickJSHandle[] = [];
|
|
82
|
-
const marshal =
|
|
83
|
-
typeof v === "object" ?
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
88
|
+
typeof v === "object" ? ctx.undefined : json(ctx, v),
|
|
89
|
+
false,
|
|
90
|
+
]);
|
|
91
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
92
|
+
const ty = ctx.typeof(v);
|
|
87
93
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
88
|
-
return [
|
|
94
|
+
return [ctx.dump(v), false];
|
|
89
95
|
});
|
|
90
|
-
const preUnmarshal =
|
|
96
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
91
97
|
|
|
92
|
-
const handle =
|
|
93
|
-
|
|
98
|
+
const handle = ctx.unwrapResult(
|
|
99
|
+
ctx.evalCode(`(function (b) { this.a = b + 2; })`)
|
|
94
100
|
);
|
|
95
101
|
|
|
96
102
|
const Cls = unmarshalFunction(
|
|
97
|
-
|
|
103
|
+
ctx,
|
|
98
104
|
handle,
|
|
99
105
|
marshal,
|
|
100
106
|
unmarshal,
|
|
@@ -119,30 +125,31 @@ test("constructor", async () => {
|
|
|
119
125
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
120
126
|
expect(preUnmarshal).toBeCalledWith(Cls, handle);
|
|
121
127
|
|
|
122
|
-
disposables.forEach(d => d.dispose());
|
|
128
|
+
disposables.forEach((d) => d.dispose());
|
|
123
129
|
handle.dispose();
|
|
124
|
-
|
|
130
|
+
ctx.dispose();
|
|
125
131
|
});
|
|
126
132
|
|
|
127
133
|
test("class", async () => {
|
|
128
|
-
const
|
|
129
|
-
const marshal =
|
|
130
|
-
typeof v === "object" ?
|
|
131
|
-
|
|
134
|
+
const ctx = (await getQuickJS()).newContext();
|
|
135
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
136
|
+
typeof v === "object" ? ctx.undefined : json(ctx, v),
|
|
137
|
+
false,
|
|
138
|
+
]);
|
|
132
139
|
const disposables: QuickJSHandle[] = [];
|
|
133
|
-
const unmarshal =
|
|
134
|
-
const ty =
|
|
140
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
141
|
+
const ty = ctx.typeof(v);
|
|
135
142
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
136
|
-
return [
|
|
143
|
+
return [ctx.dump(v), false];
|
|
137
144
|
});
|
|
138
|
-
const preUnmarshal =
|
|
145
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
139
146
|
|
|
140
|
-
const handle =
|
|
141
|
-
|
|
147
|
+
const handle = ctx.unwrapResult(
|
|
148
|
+
ctx.evalCode(`(class A { constructor(a) { this.a = a + 1; } })`)
|
|
142
149
|
);
|
|
143
150
|
|
|
144
151
|
const Cls = unmarshalFunction(
|
|
145
|
-
|
|
152
|
+
ctx,
|
|
146
153
|
handle,
|
|
147
154
|
marshal,
|
|
148
155
|
unmarshal,
|
|
@@ -167,32 +174,34 @@ test("class", async () => {
|
|
|
167
174
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
168
175
|
expect(preUnmarshal).toBeCalledWith(Cls, handle);
|
|
169
176
|
|
|
170
|
-
disposables.forEach(d => d.dispose());
|
|
177
|
+
disposables.forEach((d) => d.dispose());
|
|
171
178
|
handle.dispose();
|
|
172
|
-
|
|
179
|
+
ctx.dispose();
|
|
173
180
|
});
|
|
174
181
|
|
|
175
182
|
test("undefined", async () => {
|
|
176
|
-
const
|
|
177
|
-
const f =
|
|
178
|
-
|
|
179
|
-
expect(unmarshalFunction(
|
|
180
|
-
expect(unmarshalFunction(
|
|
181
|
-
expect(unmarshalFunction(
|
|
182
|
-
expect(unmarshalFunction(
|
|
183
|
-
expect(unmarshalFunction(
|
|
183
|
+
const ctx = (await getQuickJS()).newContext();
|
|
184
|
+
const f = vi.fn();
|
|
185
|
+
|
|
186
|
+
expect(unmarshalFunction(ctx, ctx.undefined, f, f, f)).toEqual(undefined);
|
|
187
|
+
expect(unmarshalFunction(ctx, ctx.true, f, f, f)).toEqual(undefined);
|
|
188
|
+
expect(unmarshalFunction(ctx, ctx.false, f, f, f)).toEqual(undefined);
|
|
189
|
+
expect(unmarshalFunction(ctx, ctx.null, f, f, f)).toEqual(undefined);
|
|
190
|
+
expect(unmarshalFunction(ctx, ctx.newString("hoge"), f, f, f)).toEqual(
|
|
191
|
+
undefined
|
|
192
|
+
);
|
|
193
|
+
expect(unmarshalFunction(ctx, ctx.newNumber(-10), f, f, f)).toEqual(
|
|
184
194
|
undefined
|
|
185
195
|
);
|
|
186
|
-
expect(unmarshalFunction(vm, vm.newNumber(-10), f, f, f)).toEqual(undefined);
|
|
187
196
|
|
|
188
|
-
const obj =
|
|
189
|
-
expect(unmarshalFunction(
|
|
190
|
-
const array =
|
|
191
|
-
expect(unmarshalFunction(
|
|
197
|
+
const obj = ctx.newObject();
|
|
198
|
+
expect(unmarshalFunction(ctx, obj, f, f, f)).toEqual(undefined);
|
|
199
|
+
const array = ctx.newArray();
|
|
200
|
+
expect(unmarshalFunction(ctx, array, f, f, f)).toEqual(undefined);
|
|
192
201
|
|
|
193
202
|
expect(f).toBeCalledTimes(0);
|
|
194
203
|
|
|
195
204
|
obj.dispose();
|
|
196
205
|
array.dispose();
|
|
197
|
-
|
|
206
|
+
ctx.dispose();
|
|
198
207
|
});
|
|
@@ -1,44 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
3
|
+
import { call, mayConsumeAll } from "../vmutil";
|
|
3
4
|
import unmarshalProperties from "./properties";
|
|
4
5
|
|
|
5
6
|
export default function unmarshalFunction(
|
|
6
|
-
|
|
7
|
+
ctx: QuickJSContext,
|
|
7
8
|
handle: QuickJSHandle,
|
|
8
|
-
marshal
|
|
9
|
+
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
10
|
+
marshal: (value: unknown) => [QuickJSHandle, boolean],
|
|
9
11
|
unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
|
|
10
12
|
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
11
13
|
): Function | undefined {
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
const raw = function(this: any, ...args: any[]) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
14
|
+
if (ctx.typeof(handle) !== "function") return;
|
|
15
|
+
|
|
16
|
+
const raw = function (this: any, ...args: any[]) {
|
|
17
|
+
return mayConsumeAll(
|
|
18
|
+
[marshal(this), ...args.map((a) => marshal(a))],
|
|
19
|
+
(thisHandle, ...argHandles) => {
|
|
20
|
+
if (new.target) {
|
|
21
|
+
const [instance] = unmarshal(
|
|
22
|
+
call(
|
|
23
|
+
ctx,
|
|
24
|
+
`(Cls, ...args) => new Cls(...args)`,
|
|
25
|
+
thisHandle,
|
|
26
|
+
handle,
|
|
27
|
+
...argHandles
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
Object.defineProperties(
|
|
31
|
+
this,
|
|
32
|
+
Object.getOwnPropertyDescriptors(instance)
|
|
33
|
+
);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const resultHandle = ctx.unwrapResult(
|
|
38
|
+
ctx.callFunction(handle, thisHandle, ...argHandles)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const [result, alreadyExists] = unmarshal(resultHandle);
|
|
42
|
+
if (alreadyExists) resultHandle.dispose();
|
|
43
|
+
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
34
46
|
);
|
|
35
|
-
const [result, alreadyExists] = unmarshal(resultHandle);
|
|
36
|
-
if (alreadyExists) resultHandle.dispose();
|
|
37
|
-
return result;
|
|
38
47
|
};
|
|
39
48
|
|
|
40
49
|
const func = preUnmarshal(raw, handle) ?? raw;
|
|
41
|
-
unmarshalProperties(
|
|
50
|
+
unmarshalProperties(ctx, handle, raw, unmarshal);
|
|
42
51
|
|
|
43
52
|
return func;
|
|
44
53
|
}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { 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
|
|
7
|
-
const marshal = jest.fn(() => vm.undefined);
|
|
8
|
-
const map = new VMMap(vm);
|
|
9
|
-
const find = jest.fn(h => map.getByHandle(h));
|
|
10
|
-
const pre = jest.fn((t: any, h: QuickJSHandle) => {
|
|
11
|
-
map.set(t, h);
|
|
12
|
-
return t;
|
|
13
|
-
});
|
|
9
|
+
const { ctx, unmarshal, marshal, map, dispose } = await setup();
|
|
14
10
|
|
|
15
|
-
const handle =
|
|
16
|
-
|
|
11
|
+
const handle = ctx.unwrapResult(
|
|
12
|
+
ctx.evalCode(`({
|
|
17
13
|
hoge: "foo",
|
|
18
14
|
foo: 1,
|
|
19
15
|
aaa: [1, true, {}],
|
|
@@ -21,7 +17,7 @@ test("primitive, array, object", async () => {
|
|
|
21
17
|
bbb: () => "bar"
|
|
22
18
|
})`)
|
|
23
19
|
);
|
|
24
|
-
const target = unmarshal(handle
|
|
20
|
+
const target = unmarshal(handle);
|
|
25
21
|
|
|
26
22
|
expect(target).toEqual({
|
|
27
23
|
hoge: "foo",
|
|
@@ -32,119 +28,91 @@ test("primitive, array, object", async () => {
|
|
|
32
28
|
});
|
|
33
29
|
expect(map.size).toBe(5);
|
|
34
30
|
expect(map.getByHandle(handle)).toBe(target);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.
|
|
40
|
-
.consume(h =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
31
|
+
ctx
|
|
32
|
+
.getProp(handle, "aaa")
|
|
33
|
+
.consume((h) => expect(map.getByHandle(h)).toBe(target.aaa));
|
|
34
|
+
ctx
|
|
35
|
+
.getProp(handle, "aaa")
|
|
36
|
+
.consume((h) => ctx.getProp(h, 2))
|
|
37
|
+
.consume((h) => expect(map.getByHandle(h)).toBe(target.aaa[2]));
|
|
38
|
+
ctx
|
|
39
|
+
.getProp(handle, "nested")
|
|
40
|
+
.consume((h) => expect(map.getByHandle(h)).toBe(target.nested));
|
|
41
|
+
ctx
|
|
42
|
+
.getProp(handle, "bbb")
|
|
43
|
+
.consume((h) => expect(map.getByHandle(h)).toBe(target.bbb));
|
|
47
44
|
|
|
48
45
|
expect(marshal).toBeCalledTimes(0);
|
|
49
46
|
expect(target.bbb()).toBe("bar");
|
|
50
47
|
expect(marshal).toBeCalledTimes(1);
|
|
51
48
|
expect(marshal).toBeCalledWith(target); // thisArg of target.bbb()
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
map.dispose();
|
|
55
|
-
vm.dispose();
|
|
50
|
+
dispose();
|
|
56
51
|
});
|
|
57
52
|
|
|
58
53
|
test("object with symbol key", async () => {
|
|
59
|
-
const
|
|
60
|
-
const map = new VMMap(vm);
|
|
61
|
-
const pre = (t: any, h: QuickJSHandle) => {
|
|
62
|
-
map.set(t, h);
|
|
63
|
-
return t;
|
|
64
|
-
};
|
|
54
|
+
const { ctx, unmarshal, dispose } = await setup();
|
|
65
55
|
|
|
66
|
-
const handle =
|
|
67
|
-
|
|
56
|
+
const handle = ctx.unwrapResult(
|
|
57
|
+
ctx.evalCode(`({
|
|
68
58
|
hoge: "foo",
|
|
69
59
|
[Symbol("a")]: "bar"
|
|
70
60
|
})`)
|
|
71
61
|
);
|
|
72
|
-
const target = unmarshal(handle
|
|
73
|
-
vm,
|
|
74
|
-
pre,
|
|
75
|
-
find: () => undefined,
|
|
76
|
-
marshal: () => vm.undefined,
|
|
77
|
-
});
|
|
62
|
+
const target = unmarshal(handle);
|
|
78
63
|
|
|
79
64
|
expect(target.hoge).toBe("foo");
|
|
80
65
|
expect(target[Object.getOwnPropertySymbols(target)[0]]).toBe("bar");
|
|
81
66
|
|
|
82
|
-
|
|
83
|
-
map.dispose();
|
|
84
|
-
vm.dispose();
|
|
67
|
+
dispose();
|
|
85
68
|
});
|
|
86
69
|
|
|
87
|
-
test("
|
|
88
|
-
const
|
|
89
|
-
const jsonParse = vm.unwrapResult(vm.evalCode(`JSON.parse`));
|
|
90
|
-
const disposables: QuickJSHandle[] = [];
|
|
91
|
-
const marshal = jest.fn((t: unknown) => {
|
|
92
|
-
const h =
|
|
93
|
-
t === undefined
|
|
94
|
-
? vm.undefined
|
|
95
|
-
: vm.unwrapResult(
|
|
96
|
-
vm.callFunction(
|
|
97
|
-
jsonParse,
|
|
98
|
-
vm.undefined,
|
|
99
|
-
vm.newString(JSON.stringify(t))
|
|
100
|
-
)
|
|
101
|
-
);
|
|
102
|
-
const ty = vm.typeof(h);
|
|
103
|
-
if (ty === "object" || ty === "function") disposables.push(h);
|
|
104
|
-
return h;
|
|
105
|
-
});
|
|
70
|
+
test("function", async () => {
|
|
71
|
+
const { ctx, unmarshal, marshal, map, dispose } = await setup();
|
|
106
72
|
|
|
107
|
-
const handle =
|
|
108
|
-
|
|
73
|
+
const handle = ctx.unwrapResult(
|
|
74
|
+
ctx.evalCode(`(function(a) { return a.a + "!"; })`)
|
|
109
75
|
);
|
|
110
|
-
const
|
|
111
|
-
const find = jest.fn(h => map.getByHandle(h));
|
|
112
|
-
const pre = jest.fn((t: any, h: QuickJSHandle) => {
|
|
113
|
-
map.set(t, h);
|
|
114
|
-
return t;
|
|
115
|
-
});
|
|
116
|
-
const func = unmarshal(handle, { vm, find, pre, marshal });
|
|
76
|
+
const func = unmarshal(handle);
|
|
117
77
|
const arg = { a: "hoge" };
|
|
118
78
|
expect(func(arg)).toBe("hoge!");
|
|
119
79
|
expect(marshal).toBeCalledTimes(2);
|
|
120
80
|
expect(marshal).toBeCalledWith(undefined); // this
|
|
121
81
|
expect(marshal).toBeCalledWith(arg); // arg
|
|
122
|
-
expect(map.size).toBe(
|
|
82
|
+
expect(map.size).toBe(3);
|
|
123
83
|
expect(map.getByHandle(handle)).toBe(func);
|
|
84
|
+
expect(map.has(func)).toBe(true);
|
|
124
85
|
expect(map.has(func.prototype)).toBe(true);
|
|
86
|
+
expect(map.has(arg)).toBe(true);
|
|
125
87
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
88
|
+
dispose();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("promise", async () => {
|
|
92
|
+
const { ctx, unmarshal, dispose } = await setup();
|
|
93
|
+
|
|
94
|
+
const deferred = ctx.newPromise();
|
|
95
|
+
const promise = unmarshal(deferred.handle);
|
|
96
|
+
deferred.resolve(ctx.newString("resolved!"));
|
|
97
|
+
ctx.runtime.executePendingJobs();
|
|
98
|
+
await expect(promise).resolves.toBe("resolved!");
|
|
99
|
+
|
|
100
|
+
const deferred2 = ctx.newPromise();
|
|
101
|
+
const promise2 = unmarshal(deferred2.handle);
|
|
102
|
+
deferred2.reject(ctx.newString("rejected!"));
|
|
103
|
+
ctx.runtime.executePendingJobs();
|
|
104
|
+
await expect(promise2).rejects.toBe("rejected!");
|
|
105
|
+
|
|
106
|
+
deferred.dispose();
|
|
107
|
+
deferred2.dispose();
|
|
108
|
+
dispose();
|
|
130
109
|
});
|
|
131
110
|
|
|
132
111
|
test("class", async () => {
|
|
133
|
-
const
|
|
134
|
-
const jsonParse = vm.unwrapResult(vm.evalCode(`JSON.parse`));
|
|
135
|
-
const disposables: QuickJSHandle[] = [];
|
|
136
|
-
const map = new VMMap(vm);
|
|
137
|
-
const marshal = jest.fn((t: unknown) => {
|
|
138
|
-
const h = vm.unwrapResult(
|
|
139
|
-
vm.callFunction(jsonParse, vm.undefined, vm.newString(JSON.stringify(t)))
|
|
140
|
-
);
|
|
141
|
-
const ty = vm.typeof(h);
|
|
142
|
-
if (ty === "object" || ty === "function") disposables.push(h);
|
|
143
|
-
return h;
|
|
144
|
-
});
|
|
112
|
+
const { ctx, unmarshal, dispose } = await setup();
|
|
145
113
|
|
|
146
|
-
const handle =
|
|
147
|
-
|
|
114
|
+
const handle = ctx.unwrapResult(
|
|
115
|
+
ctx.evalCode(`{
|
|
148
116
|
class Cls {
|
|
149
117
|
static hoge = "foo";
|
|
150
118
|
|
|
@@ -157,12 +125,7 @@ test("class", async () => {
|
|
|
157
125
|
Cls
|
|
158
126
|
}`)
|
|
159
127
|
);
|
|
160
|
-
const
|
|
161
|
-
const pre = jest.fn((t: any, h: QuickJSHandle) => {
|
|
162
|
-
map.set(t, h);
|
|
163
|
-
return t;
|
|
164
|
-
});
|
|
165
|
-
const Cls = unmarshal(handle, { vm, find, pre, marshal });
|
|
128
|
+
const Cls = unmarshal(handle);
|
|
166
129
|
|
|
167
130
|
expect(Cls.hoge).toBe("foo");
|
|
168
131
|
expect(Cls.foo instanceof Cls).toBe(true);
|
|
@@ -172,8 +135,46 @@ test("class", async () => {
|
|
|
172
135
|
expect(cls.foo).toBe(4);
|
|
173
136
|
|
|
174
137
|
handle.dispose();
|
|
175
|
-
|
|
176
|
-
disposables.forEach(d => d.dispose());
|
|
177
|
-
jsonParse.dispose();
|
|
178
|
-
vm.dispose();
|
|
138
|
+
dispose();
|
|
179
139
|
});
|
|
140
|
+
|
|
141
|
+
const setup = async () => {
|
|
142
|
+
const ctx = (await getQuickJS()).newContext();
|
|
143
|
+
const map = new VMMap(ctx);
|
|
144
|
+
const disposables: QuickJSHandle[] = [];
|
|
145
|
+
const marshal = vi.fn((target: unknown): [QuickJSHandle, boolean] => {
|
|
146
|
+
const handle = map.get(target);
|
|
147
|
+
if (handle) return [handle, false];
|
|
148
|
+
|
|
149
|
+
const handle2 =
|
|
150
|
+
typeof target === "function"
|
|
151
|
+
? ctx.newFunction(target.name, (...handles) => {
|
|
152
|
+
target(...handles.map((h) => ctx.dump(h)));
|
|
153
|
+
})
|
|
154
|
+
: json(ctx, target);
|
|
155
|
+
const ty = ctx.typeof(handle2);
|
|
156
|
+
if (ty === "object" || ty === "function") map.set(target, handle2);
|
|
157
|
+
return [handle2, false];
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
ctx,
|
|
162
|
+
map,
|
|
163
|
+
unmarshal: (handle: QuickJSHandle) =>
|
|
164
|
+
unmarshal(handle, {
|
|
165
|
+
find: (h) => map.getByHandle(h),
|
|
166
|
+
marshal,
|
|
167
|
+
pre: (t, h) => {
|
|
168
|
+
map.set(t, h);
|
|
169
|
+
return t;
|
|
170
|
+
},
|
|
171
|
+
ctx: ctx,
|
|
172
|
+
}),
|
|
173
|
+
marshal,
|
|
174
|
+
dispose: () => {
|
|
175
|
+
disposables.forEach((d) => d.dispose());
|
|
176
|
+
map.dispose();
|
|
177
|
+
ctx.dispose();
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
};
|
package/src/unmarshal/index.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import unmarshalFunction from "./function";
|
|
3
4
|
import unmarshalObject from "./object";
|
|
4
5
|
import unmarshalPrimitive from "./primitive";
|
|
6
|
+
import unmarshalPromise from "./promise";
|
|
5
7
|
import unmarshalSymbol from "./symbol";
|
|
6
8
|
|
|
7
9
|
export type Options = {
|
|
8
|
-
|
|
9
|
-
marshal
|
|
10
|
+
ctx: QuickJSContext;
|
|
11
|
+
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
12
|
+
marshal: (target: unknown) => [QuickJSHandle, boolean];
|
|
10
13
|
find: (handle: QuickJSHandle) => unknown | undefined;
|
|
11
|
-
pre: <T>(target: T, handle: QuickJSHandle) => T | undefined;
|
|
14
|
+
pre: <T = unknown>(target: T, handle: QuickJSHandle) => T | undefined;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
export function unmarshal(handle: QuickJSHandle, options: Options): any {
|
|
@@ -20,10 +23,10 @@ function unmarshalInner(
|
|
|
20
23
|
handle: QuickJSHandle,
|
|
21
24
|
options: Options
|
|
22
25
|
): [any, boolean] {
|
|
23
|
-
const {
|
|
26
|
+
const { ctx, marshal, find, pre } = options;
|
|
24
27
|
|
|
25
28
|
{
|
|
26
|
-
const [target, ok] = unmarshalPrimitive(
|
|
29
|
+
const [target, ok] = unmarshalPrimitive(ctx, handle);
|
|
27
30
|
if (ok) return [target, false];
|
|
28
31
|
}
|
|
29
32
|
|
|
@@ -37,9 +40,10 @@ function unmarshalInner(
|
|
|
37
40
|
const unmarshal2 = (h: QuickJSHandle) => unmarshalInner(h, options);
|
|
38
41
|
|
|
39
42
|
const result =
|
|
40
|
-
unmarshalSymbol(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
unmarshalSymbol(ctx, handle, pre) ??
|
|
44
|
+
unmarshalPromise(ctx, handle, marshal, pre) ??
|
|
45
|
+
unmarshalFunction(ctx, handle, marshal, unmarshal2, pre) ??
|
|
46
|
+
unmarshalObject(ctx, handle, unmarshal2, pre);
|
|
43
47
|
|
|
44
48
|
return [result, false];
|
|
45
49
|
}
|