quickjs-emscripten-sync 1.3.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/README.md +36 -34
- package/dist/index.d.ts +17 -15
- package/dist/quickjs-emscripten-sync.es.js +146 -135
- package/dist/quickjs-emscripten-sync.umd.js +6 -6
- package/package.json +3 -3
- package/src/index.test.ts +146 -60
- package/src/index.ts +40 -26
- package/src/marshal/function.test.ts +61 -53
- package/src/marshal/function.ts +7 -6
- package/src/marshal/index.test.ts +73 -65
- package/src/marshal/index.ts +12 -11
- package/src/marshal/json.test.ts +30 -30
- package/src/marshal/json.ts +4 -3
- package/src/marshal/object.test.ts +55 -50
- package/src/marshal/object.ts +6 -5
- package/src/marshal/primitive.test.ts +21 -17
- package/src/marshal/primitive.ts +10 -9
- package/src/marshal/promise.test.ts +14 -14
- package/src/marshal/promise.ts +3 -3
- package/src/marshal/properties.test.ts +17 -15
- package/src/marshal/properties.ts +10 -9
- package/src/marshal/symbol.test.ts +6 -6
- package/src/marshal/symbol.ts +5 -4
- package/src/unmarshal/function.test.ts +45 -43
- package/src/unmarshal/function.ts +9 -8
- package/src/unmarshal/index.test.ts +41 -40
- package/src/unmarshal/index.ts +9 -8
- package/src/unmarshal/object.test.ts +33 -31
- package/src/unmarshal/object.ts +12 -11
- package/src/unmarshal/primitive.test.ts +18 -15
- package/src/unmarshal/primitive.ts +9 -9
- package/src/unmarshal/promise.test.ts +11 -11
- package/src/unmarshal/promise.ts +9 -11
- package/src/unmarshal/properties.test.ts +6 -6
- package/src/unmarshal/properties.ts +47 -44
- package/src/unmarshal/symbol.test.ts +6 -6
- package/src/unmarshal/symbol.ts +4 -4
- package/src/util.test.ts +1 -0
- package/src/vmmap.test.ts +72 -88
- package/src/vmmap.ts +16 -16
- package/src/vmutil.test.ts +71 -73
- package/src/vmutil.ts +22 -18
- package/src/wrapper.test.ts +111 -88
- package/src/wrapper.ts +31 -27
|
@@ -7,7 +7,7 @@ import marshal from ".";
|
|
|
7
7
|
import { newDeferred } from "../util";
|
|
8
8
|
|
|
9
9
|
test("primitive, array, object", async () => {
|
|
10
|
-
const {
|
|
10
|
+
const { ctx, map, marshal, dispose } = await setup();
|
|
11
11
|
|
|
12
12
|
const target = {
|
|
13
13
|
hoge: "foo",
|
|
@@ -17,7 +17,7 @@ test("primitive, array, object", async () => {
|
|
|
17
17
|
};
|
|
18
18
|
const handle = marshal(target);
|
|
19
19
|
|
|
20
|
-
expect(
|
|
20
|
+
expect(ctx.dump(handle)).toEqual(target);
|
|
21
21
|
expect(map.size).toBe(4);
|
|
22
22
|
expect(map.get(target)).toBe(handle);
|
|
23
23
|
expect(map.has(target.aaa)).toBe(true);
|
|
@@ -28,17 +28,17 @@ test("primitive, array, object", async () => {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test("object with symbol key", async () => {
|
|
31
|
-
const {
|
|
31
|
+
const { ctx, marshal, dispose } = await setup();
|
|
32
32
|
|
|
33
33
|
const target = {
|
|
34
34
|
foo: "hoge",
|
|
35
35
|
[Symbol("a")]: 1,
|
|
36
36
|
};
|
|
37
37
|
const handle = marshal(target);
|
|
38
|
-
expect(
|
|
38
|
+
expect(ctx.dump(call(ctx, `a => a.foo`, undefined, handle))).toBe("hoge");
|
|
39
39
|
expect(
|
|
40
|
-
|
|
41
|
-
call(
|
|
40
|
+
ctx.dump(
|
|
41
|
+
call(ctx, `a => a[Object.getOwnPropertySymbols(a)[0]]`, undefined, handle)
|
|
42
42
|
)
|
|
43
43
|
).toBe(1);
|
|
44
44
|
|
|
@@ -46,19 +46,19 @@ test("object with symbol key", async () => {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
test("arrow function", async () => {
|
|
49
|
-
const {
|
|
49
|
+
const { ctx, map, marshal, dispose } = await setup();
|
|
50
50
|
const hoge = () => "foo";
|
|
51
51
|
hoge.foo = { bar: 1 };
|
|
52
52
|
const handle = marshal(hoge);
|
|
53
53
|
|
|
54
|
-
expect(
|
|
55
|
-
expect(
|
|
56
|
-
expect(
|
|
57
|
-
const foo =
|
|
58
|
-
expect(
|
|
59
|
-
expect(
|
|
60
|
-
|
|
61
|
-
);
|
|
54
|
+
expect(ctx.typeof(handle)).toBe("function");
|
|
55
|
+
expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(0);
|
|
56
|
+
expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("hoge");
|
|
57
|
+
const foo = ctx.getProp(handle, "foo");
|
|
58
|
+
expect(ctx.dump(foo)).toEqual({ bar: 1 });
|
|
59
|
+
expect(
|
|
60
|
+
ctx.dump(ctx.unwrapResult(ctx.callFunction(handle, ctx.undefined)))
|
|
61
|
+
).toBe("foo");
|
|
62
62
|
expect(map.size).toBe(2);
|
|
63
63
|
expect(map.get(hoge)).toBe(handle);
|
|
64
64
|
expect(map.has(hoge.foo)).toBe(true);
|
|
@@ -68,24 +68,26 @@ test("arrow function", async () => {
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
test("function", async () => {
|
|
71
|
-
const {
|
|
71
|
+
const { ctx, map, marshal, dispose } = await setup();
|
|
72
72
|
|
|
73
73
|
const bar = function (a: number, b: { hoge: number }) {
|
|
74
74
|
return a + b.hoge;
|
|
75
75
|
};
|
|
76
76
|
const handle = marshal(bar);
|
|
77
77
|
|
|
78
|
-
expect(
|
|
79
|
-
expect(
|
|
80
|
-
expect(
|
|
78
|
+
expect(ctx.typeof(handle)).toBe("function");
|
|
79
|
+
expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(2);
|
|
80
|
+
expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("bar");
|
|
81
81
|
expect(map.size).toBe(2);
|
|
82
82
|
expect(map.get(bar)).toBe(handle);
|
|
83
83
|
expect(map.has(bar.prototype)).toBe(true);
|
|
84
84
|
|
|
85
|
-
const b =
|
|
85
|
+
const b = ctx.unwrapResult(ctx.evalCode(`({ hoge: 2 })`));
|
|
86
86
|
expect(
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
ctx.dump(
|
|
88
|
+
ctx.unwrapResult(
|
|
89
|
+
ctx.callFunction(handle, ctx.undefined, ctx.newNumber(1), b)
|
|
90
|
+
)
|
|
89
91
|
)
|
|
90
92
|
).toBe(3);
|
|
91
93
|
|
|
@@ -94,18 +96,20 @@ test("function", async () => {
|
|
|
94
96
|
});
|
|
95
97
|
|
|
96
98
|
test("promise", async () => {
|
|
97
|
-
const {
|
|
99
|
+
const { ctx, marshal, dispose } = await setup();
|
|
98
100
|
const register = fn(
|
|
99
|
-
|
|
101
|
+
ctx,
|
|
100
102
|
`promise => { promise.then(d => notify("resolve", d), d => notify("reject", d)); }`
|
|
101
103
|
);
|
|
102
104
|
|
|
103
105
|
let notified: any;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
ctx
|
|
107
|
+
.newFunction("notify", (...handles) => {
|
|
108
|
+
notified = handles.map((h) => ctx.dump(h));
|
|
109
|
+
})
|
|
110
|
+
.consume((h) => {
|
|
111
|
+
ctx.setProp(ctx.global, "notify", h);
|
|
112
|
+
});
|
|
109
113
|
|
|
110
114
|
const deferred = newDeferred();
|
|
111
115
|
const handle = marshal(deferred.promise);
|
|
@@ -113,7 +117,7 @@ test("promise", async () => {
|
|
|
113
117
|
|
|
114
118
|
deferred.resolve("foo");
|
|
115
119
|
await deferred.promise;
|
|
116
|
-
expect(
|
|
120
|
+
expect(ctx.unwrapResult(ctx.runtime.executePendingJobs())).toBe(1);
|
|
117
121
|
expect(notified).toEqual(["resolve", "foo"]);
|
|
118
122
|
|
|
119
123
|
const deferred2 = newDeferred();
|
|
@@ -122,7 +126,7 @@ test("promise", async () => {
|
|
|
122
126
|
|
|
123
127
|
deferred2.reject("bar");
|
|
124
128
|
await expect(deferred2.promise).rejects.toBe("bar");
|
|
125
|
-
expect(
|
|
129
|
+
expect(ctx.unwrapResult(ctx.runtime.executePendingJobs())).toBe(1);
|
|
126
130
|
expect(notified).toEqual(["reject", "bar"]);
|
|
127
131
|
|
|
128
132
|
register.dispose();
|
|
@@ -130,7 +134,7 @@ test("promise", async () => {
|
|
|
130
134
|
});
|
|
131
135
|
|
|
132
136
|
test("class", async () => {
|
|
133
|
-
const {
|
|
137
|
+
const { ctx, map, marshal, dispose } = await setup();
|
|
134
138
|
|
|
135
139
|
class A {
|
|
136
140
|
a: number;
|
|
@@ -172,34 +176,38 @@ test("class", async () => {
|
|
|
172
176
|
map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.set)
|
|
173
177
|
).toBe(true);
|
|
174
178
|
|
|
175
|
-
expect(
|
|
176
|
-
expect(
|
|
177
|
-
expect(
|
|
178
|
-
const staticA =
|
|
179
|
-
expect(instanceOf(
|
|
180
|
-
expect(
|
|
181
|
-
expect(
|
|
182
|
-
|
|
183
|
-
const newA =
|
|
184
|
-
const instance =
|
|
185
|
-
|
|
186
|
-
expect(vm.dump(vm.getProp(instance, "a"))).toBe(100);
|
|
187
|
-
expect(vm.dump(vm.getProp(instance, "b"))).toBe("foo!");
|
|
188
|
-
const methodHoge = vm.getProp(instance, "hoge");
|
|
189
|
-
expect(vm.dump(vm.unwrapResult(vm.callFunction(methodHoge, instance)))).toBe(
|
|
190
|
-
101
|
|
179
|
+
expect(ctx.typeof(handle)).toBe("function");
|
|
180
|
+
expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(1);
|
|
181
|
+
expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("_A");
|
|
182
|
+
const staticA = ctx.getProp(handle, "a");
|
|
183
|
+
expect(instanceOf(ctx, staticA, handle)).toBe(true);
|
|
184
|
+
expect(ctx.dump(ctx.getProp(staticA, "a"))).toBe(100);
|
|
185
|
+
expect(ctx.dump(ctx.getProp(staticA, "b"))).toBe("a!");
|
|
186
|
+
|
|
187
|
+
const newA = ctx.unwrapResult(ctx.evalCode(`A => new A("foo")`));
|
|
188
|
+
const instance = ctx.unwrapResult(
|
|
189
|
+
ctx.callFunction(newA, ctx.undefined, handle)
|
|
191
190
|
);
|
|
192
|
-
expect(
|
|
191
|
+
expect(instanceOf(ctx, instance, handle)).toBe(true);
|
|
192
|
+
expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100);
|
|
193
|
+
expect(ctx.dump(ctx.getProp(instance, "b"))).toBe("foo!");
|
|
194
|
+
const methodHoge = ctx.getProp(instance, "hoge");
|
|
195
|
+
expect(
|
|
196
|
+
ctx.dump(ctx.unwrapResult(ctx.callFunction(methodHoge, instance)))
|
|
197
|
+
).toBe(101);
|
|
198
|
+
expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100); // not synced
|
|
193
199
|
|
|
194
|
-
const getter =
|
|
195
|
-
const setter =
|
|
200
|
+
const getter = ctx.unwrapResult(ctx.evalCode(`a => a.foo`));
|
|
201
|
+
const setter = ctx.unwrapResult(ctx.evalCode(`(a, b) => a.foo = b`));
|
|
196
202
|
expect(
|
|
197
|
-
|
|
203
|
+
ctx.dump(
|
|
204
|
+
ctx.unwrapResult(ctx.callFunction(getter, ctx.undefined, instance))
|
|
205
|
+
)
|
|
198
206
|
).toBe("foo!");
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
ctx.unwrapResult(
|
|
208
|
+
ctx.callFunction(setter, ctx.undefined, instance, ctx.newString("b"))
|
|
201
209
|
);
|
|
202
|
-
expect(
|
|
210
|
+
expect(ctx.dump(ctx.getProp(instance, "b"))).toBe("foo!"); // not synced
|
|
203
211
|
|
|
204
212
|
staticA.dispose();
|
|
205
213
|
newA.dispose();
|
|
@@ -213,13 +221,13 @@ test("class", async () => {
|
|
|
213
221
|
|
|
214
222
|
test("marshalable", async () => {
|
|
215
223
|
const isMarshalable = vi.fn((a: any) => a !== globalThis);
|
|
216
|
-
const {
|
|
224
|
+
const { ctx, marshal, dispose } = await setup({
|
|
217
225
|
isMarshalable,
|
|
218
226
|
});
|
|
219
227
|
|
|
220
228
|
const handle = marshal({ a: globalThis, b: 1 });
|
|
221
229
|
|
|
222
|
-
expect(
|
|
230
|
+
expect(ctx.dump(handle)).toEqual({ a: undefined, b: 1 });
|
|
223
231
|
expect(isMarshalable).toBeCalledWith(globalThis);
|
|
224
232
|
expect(isMarshalable).toReturnWith(false);
|
|
225
233
|
|
|
@@ -228,7 +236,7 @@ test("marshalable", async () => {
|
|
|
228
236
|
|
|
229
237
|
test("marshalable json", async () => {
|
|
230
238
|
const isMarshalable = vi.fn(() => "json" as const);
|
|
231
|
-
const {
|
|
239
|
+
const { ctx, marshal, dispose } = await setup({
|
|
232
240
|
isMarshalable,
|
|
233
241
|
});
|
|
234
242
|
|
|
@@ -239,7 +247,7 @@ test("marshalable json", async () => {
|
|
|
239
247
|
};
|
|
240
248
|
const handle = marshal(target);
|
|
241
249
|
|
|
242
|
-
expect(
|
|
250
|
+
expect(ctx.dump(handle)).toEqual({
|
|
243
251
|
a: { d: target.a.d.toISOString(), e: [null, 1, {}] },
|
|
244
252
|
b: 1,
|
|
245
253
|
});
|
|
@@ -255,15 +263,15 @@ const setup = async ({
|
|
|
255
263
|
}: {
|
|
256
264
|
isMarshalable?: (target: any) => boolean | "json";
|
|
257
265
|
} = {}) => {
|
|
258
|
-
const
|
|
259
|
-
const map = new VMMap(
|
|
266
|
+
const ctx = (await getQuickJS()).newContext();
|
|
267
|
+
const map = new VMMap(ctx);
|
|
260
268
|
return {
|
|
261
|
-
|
|
269
|
+
ctx,
|
|
262
270
|
map,
|
|
263
271
|
marshal: (v: any) =>
|
|
264
272
|
marshal(v, {
|
|
265
|
-
|
|
266
|
-
unmarshal: (h) => map.getByHandle(h) ??
|
|
273
|
+
ctx: ctx,
|
|
274
|
+
unmarshal: (h) => map.getByHandle(h) ?? ctx.dump(h),
|
|
267
275
|
isMarshalable,
|
|
268
276
|
pre: (t, d) => {
|
|
269
277
|
const h = handleFrom(d);
|
|
@@ -274,7 +282,7 @@ const setup = async ({
|
|
|
274
282
|
}),
|
|
275
283
|
dispose: () => {
|
|
276
284
|
map.dispose();
|
|
277
|
-
|
|
285
|
+
ctx.dispose();
|
|
278
286
|
},
|
|
279
287
|
};
|
|
280
288
|
};
|
package/src/marshal/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
QuickJSDeferredPromise,
|
|
3
3
|
QuickJSHandle,
|
|
4
|
-
|
|
4
|
+
QuickJSContext,
|
|
5
5
|
} from "quickjs-emscripten";
|
|
6
|
+
|
|
6
7
|
import marshalFunction from "./function";
|
|
7
8
|
import marshalObject from "./object";
|
|
8
9
|
import marshalPrimitive from "./primitive";
|
|
@@ -11,7 +12,7 @@ import marshalJSON from "./json";
|
|
|
11
12
|
import marshalPromise from "./promise";
|
|
12
13
|
|
|
13
14
|
export type Options = {
|
|
14
|
-
|
|
15
|
+
ctx: QuickJSContext;
|
|
15
16
|
unmarshal: (handle: QuickJSHandle) => unknown;
|
|
16
17
|
isMarshalable?: (target: unknown) => boolean | "json";
|
|
17
18
|
find: (target: unknown) => QuickJSHandle | undefined;
|
|
@@ -24,10 +25,10 @@ export type Options = {
|
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
export function marshal(target: unknown, options: Options): QuickJSHandle {
|
|
27
|
-
const {
|
|
28
|
+
const { ctx, unmarshal, isMarshalable, find, pre } = options;
|
|
28
29
|
|
|
29
30
|
{
|
|
30
|
-
const primitive = marshalPrimitive(
|
|
31
|
+
const primitive = marshalPrimitive(ctx, target);
|
|
31
32
|
if (primitive) {
|
|
32
33
|
return primitive;
|
|
33
34
|
}
|
|
@@ -40,22 +41,22 @@ export function marshal(target: unknown, options: Options): QuickJSHandle {
|
|
|
40
41
|
|
|
41
42
|
const marshalable = isMarshalable?.(target);
|
|
42
43
|
if (marshalable === false) {
|
|
43
|
-
return
|
|
44
|
+
return ctx.undefined;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
const pre2 = (target: any, handle: QuickJSHandle | QuickJSDeferredPromise) =>
|
|
47
48
|
pre(target, handle, marshalable);
|
|
48
49
|
if (marshalable === "json") {
|
|
49
|
-
return marshalJSON(
|
|
50
|
+
return marshalJSON(ctx, target, pre2);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
const marshal2 = (t: unknown) => marshal(t, options);
|
|
53
54
|
return (
|
|
54
|
-
marshalSymbol(
|
|
55
|
-
marshalPromise(
|
|
56
|
-
marshalFunction(
|
|
57
|
-
marshalObject(
|
|
58
|
-
|
|
55
|
+
marshalSymbol(ctx, target, pre2) ??
|
|
56
|
+
marshalPromise(ctx, target, marshal2, pre2) ??
|
|
57
|
+
marshalFunction(ctx, target, marshal2, unmarshal, pre2, options.preApply) ??
|
|
58
|
+
marshalObject(ctx, target, marshal2, pre2) ??
|
|
59
|
+
ctx.undefined
|
|
59
60
|
);
|
|
60
61
|
}
|
|
61
62
|
|
package/src/marshal/json.test.ts
CHANGED
|
@@ -4,58 +4,58 @@ import { expect, test, vi } from "vitest";
|
|
|
4
4
|
import marshalJSON from "./json";
|
|
5
5
|
|
|
6
6
|
test("empty object", async () => {
|
|
7
|
-
const
|
|
8
|
-
const prototypeCheck =
|
|
9
|
-
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
|
+
const prototypeCheck = ctx.unwrapResult(
|
|
9
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
const obj = {};
|
|
13
13
|
const preMarshal = vi.fn((_, a) => a);
|
|
14
14
|
|
|
15
|
-
const handle = marshalJSON(
|
|
15
|
+
const handle = marshalJSON(ctx, obj, preMarshal);
|
|
16
16
|
if (!handle) throw new Error("handle is undefined");
|
|
17
17
|
|
|
18
|
-
expect(
|
|
18
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
19
19
|
expect(preMarshal).toBeCalledTimes(1);
|
|
20
20
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
21
21
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
22
22
|
expect(
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
ctx.dump(
|
|
24
|
+
ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle))
|
|
25
25
|
)
|
|
26
26
|
).toBe(true);
|
|
27
27
|
|
|
28
28
|
handle.dispose();
|
|
29
29
|
prototypeCheck.dispose();
|
|
30
|
-
|
|
30
|
+
ctx.dispose();
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
test("normal object", async () => {
|
|
34
|
-
const
|
|
35
|
-
const prototypeCheck =
|
|
36
|
-
|
|
34
|
+
const ctx = (await getQuickJS()).newContext();
|
|
35
|
+
const prototypeCheck = ctx.unwrapResult(
|
|
36
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
37
37
|
);
|
|
38
|
-
const entries =
|
|
38
|
+
const entries = ctx.unwrapResult(ctx.evalCode(`Object.entries`));
|
|
39
39
|
|
|
40
40
|
const obj = { a: 100, b: "hoge" };
|
|
41
41
|
const preMarshal = vi.fn((_, a) => a);
|
|
42
42
|
|
|
43
|
-
const handle = marshalJSON(
|
|
43
|
+
const handle = marshalJSON(ctx, obj, preMarshal);
|
|
44
44
|
if (!handle) throw new Error("handle is undefined");
|
|
45
45
|
|
|
46
|
-
expect(
|
|
47
|
-
expect(
|
|
48
|
-
expect(
|
|
46
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
47
|
+
expect(ctx.getNumber(ctx.getProp(handle, "a"))).toBe(100);
|
|
48
|
+
expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
|
|
49
49
|
expect(preMarshal).toBeCalledTimes(1);
|
|
50
50
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
51
51
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
52
52
|
expect(
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
ctx.dump(
|
|
54
|
+
ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle))
|
|
55
55
|
)
|
|
56
56
|
).toBe(true);
|
|
57
|
-
const e =
|
|
58
|
-
expect(
|
|
57
|
+
const e = ctx.unwrapResult(ctx.callFunction(entries, ctx.undefined, handle));
|
|
58
|
+
expect(ctx.dump(e)).toEqual([
|
|
59
59
|
["a", 100],
|
|
60
60
|
["b", "hoge"],
|
|
61
61
|
]);
|
|
@@ -64,31 +64,31 @@ test("normal object", async () => {
|
|
|
64
64
|
handle.dispose();
|
|
65
65
|
prototypeCheck.dispose();
|
|
66
66
|
entries.dispose();
|
|
67
|
-
|
|
67
|
+
ctx.dispose();
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
test("array", async () => {
|
|
71
|
-
const
|
|
72
|
-
const isArray =
|
|
71
|
+
const ctx = (await getQuickJS()).newContext();
|
|
72
|
+
const isArray = ctx.unwrapResult(ctx.evalCode(`Array.isArray`));
|
|
73
73
|
|
|
74
74
|
const array = [1, "aa"];
|
|
75
75
|
const preMarshal = vi.fn((_, a) => a);
|
|
76
76
|
|
|
77
|
-
const handle = marshalJSON(
|
|
77
|
+
const handle = marshalJSON(ctx, array, preMarshal);
|
|
78
78
|
if (!handle) throw new Error("handle is undefined");
|
|
79
79
|
|
|
80
|
-
expect(
|
|
81
|
-
expect(
|
|
82
|
-
expect(
|
|
83
|
-
expect(
|
|
80
|
+
expect(ctx.typeof(handle)).toBe("object");
|
|
81
|
+
expect(ctx.getNumber(ctx.getProp(handle, 0))).toBe(1);
|
|
82
|
+
expect(ctx.getString(ctx.getProp(handle, 1))).toBe("aa");
|
|
83
|
+
expect(ctx.getNumber(ctx.getProp(handle, "length"))).toBe(2);
|
|
84
84
|
expect(preMarshal).toBeCalledTimes(1);
|
|
85
85
|
expect(preMarshal.mock.calls[0][0]).toBe(array);
|
|
86
86
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
87
87
|
expect(
|
|
88
|
-
|
|
88
|
+
ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))
|
|
89
89
|
).toBe(true);
|
|
90
90
|
|
|
91
91
|
handle.dispose();
|
|
92
92
|
isArray.dispose();
|
|
93
|
-
|
|
93
|
+
ctx.dispose();
|
|
94
94
|
});
|
package/src/marshal/json.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import { json } from "../vmutil";
|
|
3
4
|
|
|
4
5
|
export default function marshalJSON(
|
|
5
|
-
|
|
6
|
+
ctx: QuickJSContext,
|
|
6
7
|
target: unknown,
|
|
7
8
|
preMarshal: (
|
|
8
9
|
target: unknown,
|
|
9
10
|
handle: QuickJSHandle
|
|
10
11
|
) => QuickJSHandle | undefined
|
|
11
12
|
): QuickJSHandle {
|
|
12
|
-
const raw = json(
|
|
13
|
+
const raw = json(ctx, target);
|
|
13
14
|
const handle = preMarshal(target, raw) ?? raw;
|
|
14
15
|
return handle;
|
|
15
16
|
}
|