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