quickjs-emscripten-sync 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -7
- package/dist/index.d.ts +12 -7
- package/dist/quickjs-emscripten-sync.mjs +842 -0
- package/dist/quickjs-emscripten-sync.umd.js +15 -15
- package/package.json +9 -18
- package/src/default.ts +2 -2
- package/src/index.test.ts +21 -13
- package/src/index.ts +30 -43
- package/src/marshal/custom.test.ts +50 -0
- package/src/marshal/custom.ts +36 -0
- package/src/marshal/function.test.ts +17 -37
- package/src/marshal/function.ts +8 -12
- package/src/marshal/index.test.ts +35 -39
- package/src/marshal/index.ts +6 -9
- package/src/marshal/json.test.ts +9 -15
- package/src/marshal/json.ts +1 -4
- package/src/marshal/object.test.ts +19 -51
- package/src/marshal/object.ts +3 -11
- package/src/marshal/primitive.test.ts +4 -13
- package/src/marshal/primitive.ts +1 -1
- package/src/marshal/promise.test.ts +9 -10
- package/src/marshal/promise.ts +4 -11
- package/src/marshal/properties.test.ts +7 -14
- package/src/marshal/properties.ts +6 -9
- package/src/unmarshal/custom.test.ts +50 -0
- package/src/unmarshal/custom.ts +31 -0
- package/src/unmarshal/function.test.ts +20 -44
- package/src/unmarshal/function.ts +7 -17
- package/src/unmarshal/index.test.ts +30 -23
- package/src/unmarshal/index.ts +4 -6
- package/src/unmarshal/object.test.ts +9 -17
- package/src/unmarshal/object.ts +7 -12
- package/src/unmarshal/primitive.test.ts +1 -4
- package/src/unmarshal/primitive.ts +3 -10
- package/src/unmarshal/promise.test.ts +3 -3
- package/src/unmarshal/promise.ts +3 -10
- package/src/unmarshal/properties.test.ts +2 -2
- package/src/unmarshal/properties.ts +4 -8
- package/src/util.test.ts +1 -7
- package/src/util.ts +3 -8
- package/src/vmmap.ts +13 -31
- package/src/vmutil.test.ts +15 -29
- package/src/vmutil.ts +12 -39
- package/src/wrapper.test.ts +27 -90
- package/src/wrapper.ts +43 -50
- package/dist/quickjs-emscripten-sync.es.js +0 -962
- package/src/marshal/symbol.test.ts +0 -24
- package/src/marshal/symbol.ts +0 -21
- package/src/unmarshal/symbol.test.ts +0 -25
- package/src/unmarshal/symbol.ts +0 -12
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
2
3
|
|
|
3
4
|
import { json, eq, call } from "../vmutil";
|
|
5
|
+
|
|
4
6
|
import marshalFunction from "./function";
|
|
5
|
-
import { expect, test, vi } from "vitest";
|
|
6
7
|
|
|
7
8
|
test("normal func", async () => {
|
|
8
9
|
const ctx = (await getQuickJS()).newContext();
|
|
9
10
|
|
|
10
|
-
const marshal = vi.fn(
|
|
11
|
-
const unmarshal = vi.fn((v)
|
|
12
|
-
eq(ctx, v, ctx.global) ? undefined : ctx.dump(v)
|
|
13
|
-
);
|
|
11
|
+
const marshal = vi.fn(v => json(ctx, v));
|
|
12
|
+
const unmarshal = vi.fn(v => (eq(ctx, v, ctx.global) ? undefined : ctx.dump(v)));
|
|
14
13
|
const preMarshal = vi.fn((_, a) => a);
|
|
15
14
|
const innerfn = vi.fn((..._args: any[]) => "hoge");
|
|
16
15
|
const fn = (...args: any[]) => innerfn(...args);
|
|
@@ -25,7 +24,7 @@ test("normal func", async () => {
|
|
|
25
24
|
expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("fn");
|
|
26
25
|
|
|
27
26
|
const result = ctx.unwrapResult(
|
|
28
|
-
ctx.callFunction(handle, ctx.undefined, ctx.newNumber(1), ctx.true)
|
|
27
|
+
ctx.callFunction(handle, ctx.undefined, ctx.newNumber(1), ctx.true),
|
|
29
28
|
);
|
|
30
29
|
|
|
31
30
|
expect(ctx.dump(result)).toBe("hoge");
|
|
@@ -42,7 +41,7 @@ test("normal func", async () => {
|
|
|
42
41
|
|
|
43
42
|
test("func which has properties", async () => {
|
|
44
43
|
const ctx = (await getQuickJS()).newContext();
|
|
45
|
-
const marshal = vi.fn(
|
|
44
|
+
const marshal = vi.fn(v => json(ctx, v));
|
|
46
45
|
|
|
47
46
|
const fn = () => {};
|
|
48
47
|
fn.hoge = "foo";
|
|
@@ -51,8 +50,8 @@ test("func which has properties", async () => {
|
|
|
51
50
|
ctx,
|
|
52
51
|
fn,
|
|
53
52
|
marshal,
|
|
54
|
-
|
|
55
|
-
(_, a) => a
|
|
53
|
+
v => ctx.dump(v),
|
|
54
|
+
(_, a) => a,
|
|
56
55
|
);
|
|
57
56
|
if (!handle) throw new Error("handle is undefined");
|
|
58
57
|
|
|
@@ -92,20 +91,16 @@ test("class", async () => {
|
|
|
92
91
|
if (!handle) throw new Error("handle is undefined");
|
|
93
92
|
|
|
94
93
|
const newA = ctx.unwrapResult(ctx.evalCode(`A => new A(100)`));
|
|
95
|
-
const instance = ctx.unwrapResult(
|
|
96
|
-
ctx.callFunction(newA, ctx.undefined, handle)
|
|
97
|
-
);
|
|
94
|
+
const instance = ctx.unwrapResult(ctx.callFunction(newA, ctx.undefined, handle));
|
|
98
95
|
|
|
99
96
|
expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("A");
|
|
100
97
|
expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(1);
|
|
101
|
-
expect(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
105
|
-
).toBe(true);
|
|
98
|
+
expect(ctx.dump(call(ctx, "(cls, i) => i instanceof cls", undefined, handle, instance))).toBe(
|
|
99
|
+
true,
|
|
100
|
+
);
|
|
106
101
|
expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100);
|
|
107
102
|
|
|
108
|
-
disposables.forEach(
|
|
103
|
+
disposables.forEach(d => d.dispose());
|
|
109
104
|
instance.dispose();
|
|
110
105
|
newA.dispose();
|
|
111
106
|
handle.dispose();
|
|
@@ -120,34 +115,19 @@ test("preApply", async () => {
|
|
|
120
115
|
if (typeof v === "number") return ctx.newNumber(v);
|
|
121
116
|
return ctx.null;
|
|
122
117
|
};
|
|
123
|
-
const unmarshal = (v: QuickJSHandle) =>
|
|
124
|
-
|
|
125
|
-
const preApply = vi.fn(
|
|
126
|
-
(a: Function, b: any, c: any[]) => a.apply(b, c) + "!"
|
|
127
|
-
);
|
|
118
|
+
const unmarshal = (v: QuickJSHandle) => (ctx.typeof(v) === "object" ? that : ctx.dump(v));
|
|
119
|
+
const preApply = vi.fn((a: Function, b: any, c: any[]) => a.apply(b, c) + "!");
|
|
128
120
|
const that = {};
|
|
129
121
|
const thatHandle = ctx.newObject();
|
|
130
122
|
|
|
131
123
|
const fn = () => "foo";
|
|
132
|
-
const handle = marshalFunction(
|
|
133
|
-
ctx,
|
|
134
|
-
fn,
|
|
135
|
-
marshal,
|
|
136
|
-
unmarshal,
|
|
137
|
-
(_, a) => a,
|
|
138
|
-
preApply
|
|
139
|
-
);
|
|
124
|
+
const handle = marshalFunction(ctx, fn, marshal, unmarshal, (_, a) => a, preApply);
|
|
140
125
|
if (!handle) throw new Error("handle is undefined");
|
|
141
126
|
|
|
142
127
|
expect(preApply).toBeCalledTimes(0);
|
|
143
128
|
|
|
144
129
|
const res = ctx.unwrapResult(
|
|
145
|
-
ctx.callFunction(
|
|
146
|
-
handle,
|
|
147
|
-
thatHandle,
|
|
148
|
-
ctx.newNumber(100),
|
|
149
|
-
ctx.newString("hoge")
|
|
150
|
-
)
|
|
130
|
+
ctx.callFunction(handle, thatHandle, ctx.newNumber(100), ctx.newString("hoge")),
|
|
151
131
|
);
|
|
152
132
|
|
|
153
133
|
expect(preApply).toBeCalledTimes(1);
|
package/src/marshal/function.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
|
2
2
|
|
|
3
3
|
import { isES2015Class, isObject } from "../util";
|
|
4
4
|
import { call } from "../vmutil";
|
|
5
|
+
|
|
5
6
|
import marshalProperties from "./properties";
|
|
6
7
|
|
|
7
8
|
export default function marshalFunction(
|
|
@@ -9,18 +10,15 @@ export default function marshalFunction(
|
|
|
9
10
|
target: unknown,
|
|
10
11
|
marshal: (target: unknown) => QuickJSHandle,
|
|
11
12
|
unmarshal: (handle: QuickJSHandle) => unknown,
|
|
12
|
-
preMarshal: (
|
|
13
|
-
|
|
14
|
-
handle: QuickJSHandle
|
|
15
|
-
) => QuickJSHandle | undefined,
|
|
16
|
-
preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any
|
|
13
|
+
preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
|
|
14
|
+
preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any,
|
|
17
15
|
): QuickJSHandle | undefined {
|
|
18
16
|
if (typeof target !== "function") return;
|
|
19
17
|
|
|
20
18
|
const raw = ctx
|
|
21
19
|
.newFunction(target.name, function (...argHandles) {
|
|
22
20
|
const that = unmarshal(this);
|
|
23
|
-
const args = argHandles.map(
|
|
21
|
+
const args = argHandles.map(a => unmarshal(a));
|
|
24
22
|
|
|
25
23
|
if (isES2015Class(target) && isObject(that)) {
|
|
26
24
|
// Class constructors cannot be invoked without new expression, and new.target is not changed
|
|
@@ -31,11 +29,9 @@ export default function marshalFunction(
|
|
|
31
29
|
return this;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
return marshal(
|
|
35
|
-
preApply ? preApply(target, that, args) : target.apply(that, args)
|
|
36
|
-
);
|
|
32
|
+
return marshal(preApply ? preApply(target, that, args) : target.apply(that, args));
|
|
37
33
|
})
|
|
38
|
-
.consume(
|
|
34
|
+
.consume(handle2 =>
|
|
39
35
|
// fucntions created by vm.newFunction are not callable as a class constrcutor
|
|
40
36
|
call(
|
|
41
37
|
ctx,
|
|
@@ -46,8 +42,8 @@ export default function marshalFunction(
|
|
|
46
42
|
return fn;
|
|
47
43
|
}`,
|
|
48
44
|
undefined,
|
|
49
|
-
handle2
|
|
50
|
-
)
|
|
45
|
+
handle2,
|
|
46
|
+
),
|
|
51
47
|
);
|
|
52
48
|
|
|
53
49
|
const handle = preMarshal(target, raw) ?? raw;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { getQuickJS } from "quickjs-emscripten";
|
|
2
2
|
import { expect, test, vi } from "vitest";
|
|
3
3
|
|
|
4
|
+
import { newDeferred } from "../util";
|
|
4
5
|
import VMMap from "../vmmap";
|
|
5
6
|
import { instanceOf, call, handleFrom, fn } from "../vmutil";
|
|
7
|
+
|
|
6
8
|
import marshal from ".";
|
|
7
|
-
import { newDeferred } from "../util";
|
|
8
9
|
|
|
9
10
|
test("primitive, array, object", async () => {
|
|
10
11
|
const { ctx, map, marshal, dispose } = await setup();
|
|
@@ -36,11 +37,9 @@ test("object with symbol key", async () => {
|
|
|
36
37
|
};
|
|
37
38
|
const handle = marshal(target);
|
|
38
39
|
expect(ctx.dump(call(ctx, `a => a.foo`, undefined, handle))).toBe("hoge");
|
|
39
|
-
expect(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
).toBe(1);
|
|
40
|
+
expect(ctx.dump(call(ctx, `a => a[Object.getOwnPropertySymbols(a)[0]]`, undefined, handle))).toBe(
|
|
41
|
+
1,
|
|
42
|
+
);
|
|
44
43
|
|
|
45
44
|
dispose();
|
|
46
45
|
});
|
|
@@ -56,9 +55,7 @@ test("arrow function", async () => {
|
|
|
56
55
|
expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("hoge");
|
|
57
56
|
const foo = ctx.getProp(handle, "foo");
|
|
58
57
|
expect(ctx.dump(foo)).toEqual({ bar: 1 });
|
|
59
|
-
expect(
|
|
60
|
-
ctx.dump(ctx.unwrapResult(ctx.callFunction(handle, ctx.undefined)))
|
|
61
|
-
).toBe("foo");
|
|
58
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(handle, ctx.undefined)))).toBe("foo");
|
|
62
59
|
expect(map.size).toBe(2);
|
|
63
60
|
expect(map.get(hoge)).toBe(handle);
|
|
64
61
|
expect(map.has(hoge.foo)).toBe(true);
|
|
@@ -84,11 +81,7 @@ test("function", async () => {
|
|
|
84
81
|
|
|
85
82
|
const b = ctx.unwrapResult(ctx.evalCode(`({ hoge: 2 })`));
|
|
86
83
|
expect(
|
|
87
|
-
ctx.dump(
|
|
88
|
-
ctx.unwrapResult(
|
|
89
|
-
ctx.callFunction(handle, ctx.undefined, ctx.newNumber(1), b)
|
|
90
|
-
)
|
|
91
|
-
)
|
|
84
|
+
ctx.dump(ctx.unwrapResult(ctx.callFunction(handle, ctx.undefined, ctx.newNumber(1), b))),
|
|
92
85
|
).toBe(3);
|
|
93
86
|
|
|
94
87
|
b.dispose();
|
|
@@ -99,15 +92,15 @@ test("promise", async () => {
|
|
|
99
92
|
const { ctx, marshal, dispose } = await setup();
|
|
100
93
|
const register = fn(
|
|
101
94
|
ctx,
|
|
102
|
-
`promise => { promise.then(d => notify("resolve", d), d => notify("reject", d)); }
|
|
95
|
+
`promise => { promise.then(d => notify("resolve", d), d => notify("reject", d)); }`,
|
|
103
96
|
);
|
|
104
97
|
|
|
105
98
|
let notified: any;
|
|
106
99
|
ctx
|
|
107
100
|
.newFunction("notify", (...handles) => {
|
|
108
|
-
notified = handles.map(
|
|
101
|
+
notified = handles.map(h => ctx.dump(h));
|
|
109
102
|
})
|
|
110
|
-
.consume(
|
|
103
|
+
.consume(h => {
|
|
111
104
|
ctx.setProp(ctx.global, "notify", h);
|
|
112
105
|
});
|
|
113
106
|
|
|
@@ -169,12 +162,8 @@ test("class", async () => {
|
|
|
169
162
|
expect(map.has(A.prototype)).toBe(true);
|
|
170
163
|
expect(map.has(A.a)).toBe(true);
|
|
171
164
|
expect(map.has(A.prototype.hoge)).toBe(true);
|
|
172
|
-
expect(
|
|
173
|
-
|
|
174
|
-
).toBe(true);
|
|
175
|
-
expect(
|
|
176
|
-
map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.set)
|
|
177
|
-
).toBe(true);
|
|
165
|
+
expect(map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.get)).toBe(true);
|
|
166
|
+
expect(map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.set)).toBe(true);
|
|
178
167
|
|
|
179
168
|
expect(ctx.typeof(handle)).toBe("function");
|
|
180
169
|
expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(1);
|
|
@@ -185,28 +174,20 @@ test("class", async () => {
|
|
|
185
174
|
expect(ctx.dump(ctx.getProp(staticA, "b"))).toBe("a!");
|
|
186
175
|
|
|
187
176
|
const newA = ctx.unwrapResult(ctx.evalCode(`A => new A("foo")`));
|
|
188
|
-
const instance = ctx.unwrapResult(
|
|
189
|
-
ctx.callFunction(newA, ctx.undefined, handle)
|
|
190
|
-
);
|
|
177
|
+
const instance = ctx.unwrapResult(ctx.callFunction(newA, ctx.undefined, handle));
|
|
191
178
|
expect(instanceOf(ctx, instance, handle)).toBe(true);
|
|
192
179
|
expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100);
|
|
193
180
|
expect(ctx.dump(ctx.getProp(instance, "b"))).toBe("foo!");
|
|
194
181
|
const methodHoge = ctx.getProp(instance, "hoge");
|
|
195
|
-
expect(
|
|
196
|
-
ctx.dump(ctx.unwrapResult(ctx.callFunction(methodHoge, instance)))
|
|
197
|
-
).toBe(101);
|
|
182
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(methodHoge, instance)))).toBe(101);
|
|
198
183
|
expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100); // not synced
|
|
199
184
|
|
|
200
185
|
const getter = ctx.unwrapResult(ctx.evalCode(`a => a.foo`));
|
|
201
186
|
const setter = ctx.unwrapResult(ctx.evalCode(`(a, b) => a.foo = b`));
|
|
202
|
-
expect(
|
|
203
|
-
|
|
204
|
-
ctx.unwrapResult(ctx.callFunction(getter, ctx.undefined, instance))
|
|
205
|
-
)
|
|
206
|
-
).toBe("foo!");
|
|
207
|
-
ctx.unwrapResult(
|
|
208
|
-
ctx.callFunction(setter, ctx.undefined, instance, ctx.newString("b"))
|
|
187
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(getter, ctx.undefined, instance)))).toBe(
|
|
188
|
+
"foo!",
|
|
209
189
|
);
|
|
190
|
+
ctx.unwrapResult(ctx.callFunction(setter, ctx.undefined, instance, ctx.newString("b")));
|
|
210
191
|
expect(ctx.dump(ctx.getProp(instance, "b"))).toBe("foo!"); // not synced
|
|
211
192
|
|
|
212
193
|
staticA.dispose();
|
|
@@ -215,7 +196,22 @@ test("class", async () => {
|
|
|
215
196
|
methodHoge.dispose();
|
|
216
197
|
getter.dispose();
|
|
217
198
|
setter.dispose();
|
|
218
|
-
|
|
199
|
+
dispose();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("date", async () => {
|
|
203
|
+
const { ctx, map, marshal, dispose } = await setup();
|
|
204
|
+
|
|
205
|
+
const date = new Date(2022, 7, 26);
|
|
206
|
+
const handle = marshal(date);
|
|
207
|
+
if (!map) throw new Error("map is undefined");
|
|
208
|
+
|
|
209
|
+
expect(map.size).toBe(1);
|
|
210
|
+
expect(map.get(date)).toBe(handle);
|
|
211
|
+
|
|
212
|
+
expect(ctx.dump(call(ctx, "d => d instanceof Date", undefined, handle))).toBe(true);
|
|
213
|
+
expect(ctx.dump(call(ctx, "d => d.getTime()", undefined, handle))).toBe(date.getTime());
|
|
214
|
+
|
|
219
215
|
dispose();
|
|
220
216
|
});
|
|
221
217
|
|
|
@@ -271,14 +267,14 @@ const setup = async ({
|
|
|
271
267
|
marshal: (v: any) =>
|
|
272
268
|
marshal(v, {
|
|
273
269
|
ctx: ctx,
|
|
274
|
-
unmarshal:
|
|
270
|
+
unmarshal: h => map.getByHandle(h) ?? ctx.dump(h),
|
|
275
271
|
isMarshalable,
|
|
276
272
|
pre: (t, d) => {
|
|
277
273
|
const h = handleFrom(d);
|
|
278
274
|
map.set(t, h);
|
|
279
275
|
return h;
|
|
280
276
|
},
|
|
281
|
-
find:
|
|
277
|
+
find: t => map.get(t),
|
|
282
278
|
}),
|
|
283
279
|
dispose: () => {
|
|
284
280
|
map.dispose();
|
package/src/marshal/index.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
QuickJSDeferredPromise,
|
|
3
|
-
QuickJSHandle,
|
|
4
|
-
QuickJSContext,
|
|
5
|
-
} from "quickjs-emscripten";
|
|
1
|
+
import type { QuickJSDeferredPromise, QuickJSHandle, QuickJSContext } from "quickjs-emscripten";
|
|
6
2
|
|
|
3
|
+
import marshalCustom, { defaultCustom } from "./custom";
|
|
7
4
|
import marshalFunction from "./function";
|
|
5
|
+
import marshalJSON from "./json";
|
|
8
6
|
import marshalObject from "./object";
|
|
9
7
|
import marshalPrimitive from "./primitive";
|
|
10
|
-
import marshalSymbol from "./symbol";
|
|
11
|
-
import marshalJSON from "./json";
|
|
12
8
|
import marshalPromise from "./promise";
|
|
13
9
|
|
|
14
10
|
export type Options = {
|
|
@@ -19,9 +15,10 @@ export type Options = {
|
|
|
19
15
|
pre: (
|
|
20
16
|
target: unknown,
|
|
21
17
|
handle: QuickJSHandle | QuickJSDeferredPromise,
|
|
22
|
-
mode: true | "json" | undefined
|
|
18
|
+
mode: true | "json" | undefined,
|
|
23
19
|
) => QuickJSHandle | undefined;
|
|
24
20
|
preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any;
|
|
21
|
+
custom?: Iterable<(obj: unknown, ctx: QuickJSContext) => QuickJSHandle | undefined>;
|
|
25
22
|
};
|
|
26
23
|
|
|
27
24
|
export function marshal(target: unknown, options: Options): QuickJSHandle {
|
|
@@ -52,7 +49,7 @@ export function marshal(target: unknown, options: Options): QuickJSHandle {
|
|
|
52
49
|
|
|
53
50
|
const marshal2 = (t: unknown) => marshal(t, options);
|
|
54
51
|
return (
|
|
55
|
-
|
|
52
|
+
marshalCustom(ctx, target, pre2, [...defaultCustom, ...(options.custom ?? [])]) ??
|
|
56
53
|
marshalPromise(ctx, target, marshal2, pre2) ??
|
|
57
54
|
marshalFunction(ctx, target, marshal2, unmarshal, pre2, options.preApply) ??
|
|
58
55
|
marshalObject(ctx, target, marshal2, pre2) ??
|
package/src/marshal/json.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ import marshalJSON from "./json";
|
|
|
6
6
|
test("empty object", async () => {
|
|
7
7
|
const ctx = (await getQuickJS()).newContext();
|
|
8
8
|
const prototypeCheck = ctx.unwrapResult(
|
|
9
|
-
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
9
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
const obj = {};
|
|
@@ -19,11 +19,9 @@ test("empty object", async () => {
|
|
|
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
|
-
expect(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
).toBe(true);
|
|
22
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
|
|
23
|
+
true,
|
|
24
|
+
);
|
|
27
25
|
|
|
28
26
|
handle.dispose();
|
|
29
27
|
prototypeCheck.dispose();
|
|
@@ -33,7 +31,7 @@ test("empty object", async () => {
|
|
|
33
31
|
test("normal object", async () => {
|
|
34
32
|
const ctx = (await getQuickJS()).newContext();
|
|
35
33
|
const prototypeCheck = ctx.unwrapResult(
|
|
36
|
-
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
34
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
|
|
37
35
|
);
|
|
38
36
|
const entries = ctx.unwrapResult(ctx.evalCode(`Object.entries`));
|
|
39
37
|
|
|
@@ -49,11 +47,9 @@ test("normal object", async () => {
|
|
|
49
47
|
expect(preMarshal).toBeCalledTimes(1);
|
|
50
48
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
51
49
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
52
|
-
expect(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
56
|
-
).toBe(true);
|
|
50
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
|
|
51
|
+
true,
|
|
52
|
+
);
|
|
57
53
|
const e = ctx.unwrapResult(ctx.callFunction(entries, ctx.undefined, handle));
|
|
58
54
|
expect(ctx.dump(e)).toEqual([
|
|
59
55
|
["a", 100],
|
|
@@ -84,9 +80,7 @@ test("array", async () => {
|
|
|
84
80
|
expect(preMarshal).toBeCalledTimes(1);
|
|
85
81
|
expect(preMarshal.mock.calls[0][0]).toBe(array);
|
|
86
82
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
87
|
-
expect(
|
|
88
|
-
ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))
|
|
89
|
-
).toBe(true);
|
|
83
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))).toBe(true);
|
|
90
84
|
|
|
91
85
|
handle.dispose();
|
|
92
86
|
isArray.dispose();
|
package/src/marshal/json.ts
CHANGED
|
@@ -5,10 +5,7 @@ import { json } from "../vmutil";
|
|
|
5
5
|
export default function marshalJSON(
|
|
6
6
|
ctx: QuickJSContext,
|
|
7
7
|
target: unknown,
|
|
8
|
-
preMarshal: (
|
|
9
|
-
target: unknown,
|
|
10
|
-
handle: QuickJSHandle
|
|
11
|
-
) => QuickJSHandle | undefined
|
|
8
|
+
preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
|
|
12
9
|
): QuickJSHandle {
|
|
13
10
|
const raw = json(ctx, target);
|
|
14
11
|
const handle = preMarshal(target, raw) ?? raw;
|
|
@@ -2,12 +2,13 @@ import { getQuickJS } from "quickjs-emscripten";
|
|
|
2
2
|
import { expect, test, vi } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { call } from "../vmutil";
|
|
5
|
+
|
|
5
6
|
import marshalObject from "./object";
|
|
6
7
|
|
|
7
8
|
test("empty object", async () => {
|
|
8
9
|
const ctx = (await getQuickJS()).newContext();
|
|
9
10
|
const prototypeCheck = ctx.unwrapResult(
|
|
10
|
-
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
11
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
|
|
11
12
|
);
|
|
12
13
|
|
|
13
14
|
const obj = {};
|
|
@@ -22,11 +23,9 @@ test("empty object", async () => {
|
|
|
22
23
|
expect(preMarshal).toBeCalledTimes(1);
|
|
23
24
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
24
25
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
25
|
-
expect(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
).toBe(true);
|
|
26
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
|
|
27
|
+
true,
|
|
28
|
+
);
|
|
30
29
|
|
|
31
30
|
handle.dispose();
|
|
32
31
|
prototypeCheck.dispose();
|
|
@@ -36,17 +35,13 @@ test("empty object", async () => {
|
|
|
36
35
|
test("normal object", async () => {
|
|
37
36
|
const ctx = (await getQuickJS()).newContext();
|
|
38
37
|
const prototypeCheck = ctx.unwrapResult(
|
|
39
|
-
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
38
|
+
ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
|
|
40
39
|
);
|
|
41
40
|
const entries = ctx.unwrapResult(ctx.evalCode(`Object.entries`));
|
|
42
41
|
|
|
43
42
|
const obj = { a: 100, b: "hoge" };
|
|
44
|
-
const marshal = vi.fn(
|
|
45
|
-
typeof v === "number"
|
|
46
|
-
? ctx.newNumber(v)
|
|
47
|
-
: typeof v === "string"
|
|
48
|
-
? ctx.newString(v)
|
|
49
|
-
: ctx.null
|
|
43
|
+
const marshal = vi.fn(v =>
|
|
44
|
+
typeof v === "number" ? ctx.newNumber(v) : typeof v === "string" ? ctx.newString(v) : ctx.null,
|
|
50
45
|
);
|
|
51
46
|
const preMarshal = vi.fn((_, a) => a);
|
|
52
47
|
|
|
@@ -60,11 +55,9 @@ test("normal object", async () => {
|
|
|
60
55
|
expect(preMarshal).toBeCalledTimes(1);
|
|
61
56
|
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
62
57
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
63
|
-
expect(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
).toBe(true);
|
|
58
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
|
|
59
|
+
true,
|
|
60
|
+
);
|
|
68
61
|
const e = ctx.unwrapResult(ctx.callFunction(entries, ctx.undefined, handle));
|
|
69
62
|
expect(ctx.dump(e)).toEqual([
|
|
70
63
|
["a", 100],
|
|
@@ -83,12 +76,8 @@ test("array", async () => {
|
|
|
83
76
|
const isArray = ctx.unwrapResult(ctx.evalCode(`Array.isArray`));
|
|
84
77
|
|
|
85
78
|
const array = [1, "aa"];
|
|
86
|
-
const marshal = vi.fn(
|
|
87
|
-
typeof v === "number"
|
|
88
|
-
? ctx.newNumber(v)
|
|
89
|
-
: typeof v === "string"
|
|
90
|
-
? ctx.newString(v)
|
|
91
|
-
: ctx.null
|
|
79
|
+
const marshal = vi.fn(v =>
|
|
80
|
+
typeof v === "number" ? ctx.newNumber(v) : typeof v === "string" ? ctx.newString(v) : ctx.null,
|
|
92
81
|
);
|
|
93
82
|
const preMarshal = vi.fn((_, a) => a);
|
|
94
83
|
|
|
@@ -99,20 +88,11 @@ test("array", async () => {
|
|
|
99
88
|
expect(ctx.getNumber(ctx.getProp(handle, 0))).toBe(1);
|
|
100
89
|
expect(ctx.getString(ctx.getProp(handle, 1))).toBe("aa");
|
|
101
90
|
expect(ctx.getNumber(ctx.getProp(handle, "length"))).toBe(2);
|
|
102
|
-
expect(marshal.mock.calls).toEqual([
|
|
103
|
-
["0"],
|
|
104
|
-
[1],
|
|
105
|
-
["1"],
|
|
106
|
-
["aa"],
|
|
107
|
-
["length"],
|
|
108
|
-
[2],
|
|
109
|
-
]);
|
|
91
|
+
expect(marshal.mock.calls).toEqual([["0"], [1], ["1"], ["aa"], ["length"], [2]]);
|
|
110
92
|
expect(preMarshal).toBeCalledTimes(1);
|
|
111
93
|
expect(preMarshal.mock.calls[0][0]).toBe(array);
|
|
112
94
|
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
113
|
-
expect(
|
|
114
|
-
ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))
|
|
115
|
-
).toBe(true);
|
|
95
|
+
expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))).toBe(true);
|
|
116
96
|
|
|
117
97
|
handle.dispose();
|
|
118
98
|
isArray.dispose();
|
|
@@ -132,13 +112,8 @@ test("prototype", async () => {
|
|
|
132
112
|
const handle = marshalObject(
|
|
133
113
|
ctx,
|
|
134
114
|
obj,
|
|
135
|
-
(v)
|
|
136
|
-
|
|
137
|
-
? protoHandle
|
|
138
|
-
: typeof v === "string"
|
|
139
|
-
? ctx.newString(v)
|
|
140
|
-
: ctx.null,
|
|
141
|
-
preMarshal
|
|
115
|
+
v => (v === proto ? protoHandle : typeof v === "string" ? ctx.newString(v) : ctx.null),
|
|
116
|
+
preMarshal,
|
|
142
117
|
);
|
|
143
118
|
if (!handle) throw new Error("handle is undefined");
|
|
144
119
|
|
|
@@ -150,15 +125,8 @@ test("prototype", async () => {
|
|
|
150
125
|
expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
|
|
151
126
|
const e = call(ctx, "Object.entries", undefined, handle);
|
|
152
127
|
expect(ctx.dump(e)).toEqual([["b", "hoge"]]);
|
|
153
|
-
const protoHandle2 = call(
|
|
154
|
-
|
|
155
|
-
"Object.getPrototypeOf",
|
|
156
|
-
ctx.undefined,
|
|
157
|
-
handle
|
|
158
|
-
);
|
|
159
|
-
expect(
|
|
160
|
-
ctx.dump(call(ctx, `Object.is`, undefined, protoHandle, protoHandle2))
|
|
161
|
-
).toBe(true);
|
|
128
|
+
const protoHandle2 = call(ctx, "Object.getPrototypeOf", ctx.undefined, handle);
|
|
129
|
+
expect(ctx.dump(call(ctx, `Object.is`, undefined, protoHandle, protoHandle2))).toBe(true);
|
|
162
130
|
|
|
163
131
|
protoHandle2.dispose();
|
|
164
132
|
e.dispose();
|
package/src/marshal/object.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
2
|
|
|
3
3
|
import { call } from "../vmutil";
|
|
4
|
+
|
|
4
5
|
import marshalProperties from "./properties";
|
|
5
6
|
|
|
6
7
|
export default function marshalObject(
|
|
7
8
|
ctx: QuickJSContext,
|
|
8
9
|
target: unknown,
|
|
9
10
|
marshal: (target: unknown) => QuickJSHandle,
|
|
10
|
-
preMarshal: (
|
|
11
|
-
target: unknown,
|
|
12
|
-
handle: QuickJSHandle
|
|
13
|
-
) => QuickJSHandle | undefined
|
|
11
|
+
preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
|
|
14
12
|
): QuickJSHandle | undefined {
|
|
15
13
|
if (typeof target !== "object" || target === null) return;
|
|
16
14
|
|
|
@@ -24,13 +22,7 @@ export default function marshalObject(
|
|
|
24
22
|
? marshal(prototype)
|
|
25
23
|
: undefined;
|
|
26
24
|
if (prototypeHandle) {
|
|
27
|
-
call(
|
|
28
|
-
ctx,
|
|
29
|
-
"Object.setPrototypeOf",
|
|
30
|
-
undefined,
|
|
31
|
-
handle,
|
|
32
|
-
prototypeHandle
|
|
33
|
-
).dispose();
|
|
25
|
+
call(ctx, "Object.setPrototypeOf", undefined, handle, prototypeHandle).dispose();
|
|
34
26
|
}
|
|
35
27
|
|
|
36
28
|
marshalProperties(ctx, target, raw, marshal);
|
|
@@ -2,6 +2,7 @@ import { getQuickJS } from "quickjs-emscripten";
|
|
|
2
2
|
import { expect, test } from "vitest";
|
|
3
3
|
|
|
4
4
|
import { eq } from "../vmutil";
|
|
5
|
+
|
|
5
6
|
import marshalPrimitive from "./primitive";
|
|
6
7
|
|
|
7
8
|
test("works", async () => {
|
|
@@ -11,19 +12,9 @@ test("works", async () => {
|
|
|
11
12
|
expect(marshalPrimitive(ctx, null)).toBe(ctx.null);
|
|
12
13
|
expect(marshalPrimitive(ctx, false)).toBe(ctx.false);
|
|
13
14
|
expect(marshalPrimitive(ctx, true)).toBe(ctx.true);
|
|
14
|
-
expect(
|
|
15
|
-
|
|
16
|
-
).toBe(true);
|
|
17
|
-
expect(
|
|
18
|
-
eq(ctx, marshalPrimitive(ctx, -100) ?? ctx.undefined, ctx.newNumber(-100))
|
|
19
|
-
).toBe(true);
|
|
20
|
-
expect(
|
|
21
|
-
eq(
|
|
22
|
-
ctx,
|
|
23
|
-
marshalPrimitive(ctx, "hoge") ?? ctx.undefined,
|
|
24
|
-
ctx.newString("hoge")
|
|
25
|
-
)
|
|
26
|
-
).toBe(true);
|
|
15
|
+
expect(eq(ctx, marshalPrimitive(ctx, 1) ?? ctx.undefined, ctx.newNumber(1))).toBe(true);
|
|
16
|
+
expect(eq(ctx, marshalPrimitive(ctx, -100) ?? ctx.undefined, ctx.newNumber(-100))).toBe(true);
|
|
17
|
+
expect(eq(ctx, marshalPrimitive(ctx, "hoge") ?? ctx.undefined, ctx.newString("hoge"))).toBe(true);
|
|
27
18
|
// expect(
|
|
28
19
|
// eq(
|
|
29
20
|
// ctx,
|
package/src/marshal/primitive.ts
CHANGED