quickjs-emscripten-sync 1.0.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -2
- package/README.md +303 -0
- package/dist/index.d.ts +129 -29
- package/dist/quickjs-emscripten-sync.es.js +951 -0
- package/dist/quickjs-emscripten-sync.umd.js +64 -0
- package/package.json +28 -40
- package/src/default.ts +6 -2
- package/src/index.test.ts +266 -51
- package/src/index.ts +123 -66
- package/src/marshal/function.test.ts +11 -10
- package/src/marshal/function.ts +3 -3
- package/src/marshal/index.test.ts +75 -10
- package/src/marshal/index.ts +28 -14
- package/src/marshal/json.test.ts +94 -0
- package/src/marshal/json.ts +15 -0
- package/src/marshal/object.test.ts +49 -6
- package/src/marshal/object.ts +2 -2
- package/src/marshal/primitive.test.ts +2 -0
- package/src/marshal/primitive.ts +8 -2
- package/src/marshal/promise.test.ts +86 -0
- package/src/marshal/promise.ts +26 -0
- package/src/marshal/properties.test.ts +7 -5
- package/src/marshal/properties.ts +2 -2
- package/src/marshal/symbol.test.ts +3 -1
- package/src/unmarshal/function.test.ts +28 -21
- package/src/unmarshal/function.ts +31 -23
- package/src/unmarshal/index.test.ts +86 -86
- package/src/unmarshal/index.ts +5 -4
- package/src/unmarshal/object.test.ts +36 -8
- package/src/unmarshal/object.ts +8 -4
- package/src/unmarshal/primitive.test.ts +2 -0
- package/src/unmarshal/primitive.ts +1 -2
- package/src/unmarshal/promise.test.ts +44 -0
- package/src/unmarshal/promise.ts +40 -0
- package/src/unmarshal/properties.test.ts +4 -2
- package/src/unmarshal/properties.ts +11 -9
- package/src/unmarshal/symbol.test.ts +3 -1
- package/src/util.test.ts +22 -5
- package/src/util.ts +15 -0
- package/src/vmmap.test.ts +22 -0
- package/src/vmmap.ts +6 -2
- package/src/vmutil.test.ts +116 -8
- package/src/vmutil.ts +76 -8
- package/src/wrapper.test.ts +44 -31
- package/src/wrapper.ts +47 -30
- package/dist/default.d.ts +0 -4
- package/dist/index.js +0 -8
- package/dist/marshal/array.d.ts +0 -2
- 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 -1302
- 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 -1285
- package/dist/quickjs-emscripten-sync.esm.js.map +0 -1
- package/dist/unmarshal/array.d.ts +0 -2
- 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
- package/src/marshal/array.test.ts +0 -40
- package/src/marshal/array.ts +0 -24
- package/src/unmarshal/array.test.ts +0 -45
- package/src/unmarshal/array.ts +0 -32
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
1
|
+
import { Disposable, getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import VMMap from "../vmmap";
|
|
3
5
|
import unmarshal from ".";
|
|
6
|
+
import { json } from "../vmutil";
|
|
4
7
|
|
|
5
8
|
test("primitive, array, object", async () => {
|
|
6
|
-
const vm =
|
|
7
|
-
const marshal = jest.fn(() => 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 { vm, unmarshal, marshal, map, dispose } = await setup();
|
|
14
10
|
|
|
15
11
|
const handle = vm.unwrapResult(
|
|
16
12
|
vm.evalCode(`({
|
|
@@ -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,16 +28,16 @@ test("primitive, array, object", async () => {
|
|
|
32
28
|
});
|
|
33
29
|
expect(map.size).toBe(5);
|
|
34
30
|
expect(map.getByHandle(handle)).toBe(target);
|
|
35
|
-
vm.getProp(handle, "aaa").consume(h =>
|
|
31
|
+
vm.getProp(handle, "aaa").consume((h) =>
|
|
36
32
|
expect(map.getByHandle(h)).toBe(target.aaa)
|
|
37
33
|
);
|
|
38
34
|
vm.getProp(handle, "aaa")
|
|
39
|
-
.consume(h => vm.getProp(h, 2))
|
|
40
|
-
.consume(h => expect(map.getByHandle(h)).toBe(target.aaa[2]));
|
|
41
|
-
vm.getProp(handle, "nested").consume(h =>
|
|
35
|
+
.consume((h) => vm.getProp(h, 2))
|
|
36
|
+
.consume((h) => expect(map.getByHandle(h)).toBe(target.aaa[2]));
|
|
37
|
+
vm.getProp(handle, "nested").consume((h) =>
|
|
42
38
|
expect(map.getByHandle(h)).toBe(target.nested)
|
|
43
39
|
);
|
|
44
|
-
vm.getProp(handle, "bbb").consume(h =>
|
|
40
|
+
vm.getProp(handle, "bbb").consume((h) =>
|
|
45
41
|
expect(map.getByHandle(h)).toBe(target.bbb)
|
|
46
42
|
);
|
|
47
43
|
|
|
@@ -50,18 +46,11 @@ test("primitive, array, object", async () => {
|
|
|
50
46
|
expect(marshal).toBeCalledTimes(1);
|
|
51
47
|
expect(marshal).toBeCalledWith(target); // thisArg of target.bbb()
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
map.dispose();
|
|
55
|
-
vm.dispose();
|
|
49
|
+
dispose();
|
|
56
50
|
});
|
|
57
51
|
|
|
58
52
|
test("object with symbol key", async () => {
|
|
59
|
-
const vm =
|
|
60
|
-
const map = new VMMap(vm);
|
|
61
|
-
const pre = (t: any, h: QuickJSHandle) => {
|
|
62
|
-
map.set(t, h);
|
|
63
|
-
return t;
|
|
64
|
-
};
|
|
53
|
+
const { vm, unmarshal, dispose } = await setup();
|
|
65
54
|
|
|
66
55
|
const handle = vm.unwrapResult(
|
|
67
56
|
vm.evalCode(`({
|
|
@@ -69,79 +58,57 @@ test("object with symbol key", async () => {
|
|
|
69
58
|
[Symbol("a")]: "bar"
|
|
70
59
|
})`)
|
|
71
60
|
);
|
|
72
|
-
const target = unmarshal(handle
|
|
73
|
-
vm,
|
|
74
|
-
pre,
|
|
75
|
-
find: () => undefined,
|
|
76
|
-
marshal: () => vm.undefined,
|
|
77
|
-
});
|
|
61
|
+
const target = unmarshal(handle);
|
|
78
62
|
|
|
79
63
|
expect(target.hoge).toBe("foo");
|
|
80
64
|
expect(target[Object.getOwnPropertySymbols(target)[0]]).toBe("bar");
|
|
81
65
|
|
|
82
|
-
|
|
83
|
-
map.dispose();
|
|
84
|
-
vm.dispose();
|
|
66
|
+
dispose();
|
|
85
67
|
});
|
|
86
68
|
|
|
87
|
-
test("
|
|
88
|
-
const vm =
|
|
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
|
-
});
|
|
69
|
+
test("function", async () => {
|
|
70
|
+
const { vm, unmarshal, marshal, map, dispose } = await setup();
|
|
106
71
|
|
|
107
72
|
const handle = vm.unwrapResult(
|
|
108
73
|
vm.evalCode(`(function(a) { return a.a + "!"; })`)
|
|
109
74
|
);
|
|
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 });
|
|
75
|
+
const func = unmarshal(handle);
|
|
117
76
|
const arg = { a: "hoge" };
|
|
118
77
|
expect(func(arg)).toBe("hoge!");
|
|
119
78
|
expect(marshal).toBeCalledTimes(2);
|
|
120
79
|
expect(marshal).toBeCalledWith(undefined); // this
|
|
121
80
|
expect(marshal).toBeCalledWith(arg); // arg
|
|
122
|
-
expect(map.size).toBe(
|
|
81
|
+
expect(map.size).toBe(3);
|
|
123
82
|
expect(map.getByHandle(handle)).toBe(func);
|
|
83
|
+
expect(map.has(func)).toBe(true);
|
|
124
84
|
expect(map.has(func.prototype)).toBe(true);
|
|
85
|
+
expect(map.has(arg)).toBe(true);
|
|
86
|
+
|
|
87
|
+
dispose();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("promise", async () => {
|
|
91
|
+
const { vm, unmarshal, dispose } = await setup();
|
|
92
|
+
|
|
93
|
+
const deferred = vm.newPromise();
|
|
94
|
+
const promise = unmarshal(deferred.handle);
|
|
95
|
+
deferred.resolve(vm.newString("resolved!"));
|
|
96
|
+
vm.executePendingJobs();
|
|
97
|
+
await expect(promise).resolves.toBe("resolved!");
|
|
125
98
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
vm.
|
|
99
|
+
const deferred2 = vm.newPromise();
|
|
100
|
+
const promise2 = unmarshal(deferred2.handle);
|
|
101
|
+
deferred2.reject(vm.newString("rejected!"));
|
|
102
|
+
vm.executePendingJobs();
|
|
103
|
+
await expect(promise2).rejects.toBe("rejected!");
|
|
104
|
+
|
|
105
|
+
deferred.dispose();
|
|
106
|
+
deferred2.dispose();
|
|
107
|
+
dispose();
|
|
130
108
|
});
|
|
131
109
|
|
|
132
110
|
test("class", async () => {
|
|
133
|
-
const vm =
|
|
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
|
-
});
|
|
111
|
+
const { vm, unmarshal, dispose } = await setup();
|
|
145
112
|
|
|
146
113
|
const handle = vm.unwrapResult(
|
|
147
114
|
vm.evalCode(`{
|
|
@@ -157,12 +124,7 @@ test("class", async () => {
|
|
|
157
124
|
Cls
|
|
158
125
|
}`)
|
|
159
126
|
);
|
|
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 });
|
|
127
|
+
const Cls = unmarshal(handle);
|
|
166
128
|
|
|
167
129
|
expect(Cls.hoge).toBe("foo");
|
|
168
130
|
expect(Cls.foo instanceof Cls).toBe(true);
|
|
@@ -172,8 +134,46 @@ test("class", async () => {
|
|
|
172
134
|
expect(cls.foo).toBe(4);
|
|
173
135
|
|
|
174
136
|
handle.dispose();
|
|
175
|
-
|
|
176
|
-
disposables.forEach(d => d.dispose());
|
|
177
|
-
jsonParse.dispose();
|
|
178
|
-
vm.dispose();
|
|
137
|
+
dispose();
|
|
179
138
|
});
|
|
139
|
+
|
|
140
|
+
const setup = async () => {
|
|
141
|
+
const vm = (await getQuickJS()).createVm();
|
|
142
|
+
const map = new VMMap(vm);
|
|
143
|
+
const disposables: QuickJSHandle[] = [];
|
|
144
|
+
const marshal = vi.fn((target: unknown): [QuickJSHandle, boolean] => {
|
|
145
|
+
const handle = map.get(target);
|
|
146
|
+
if (handle) return [handle, false];
|
|
147
|
+
|
|
148
|
+
const handle2 =
|
|
149
|
+
typeof target === "function"
|
|
150
|
+
? vm.newFunction(target.name, (...handles) => {
|
|
151
|
+
target(...handles.map((h) => vm.dump(h)));
|
|
152
|
+
})
|
|
153
|
+
: json(vm, target);
|
|
154
|
+
const ty = vm.typeof(handle2);
|
|
155
|
+
if (ty === "object" || ty === "function") map.set(target, handle2);
|
|
156
|
+
return [handle2, false];
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
vm,
|
|
161
|
+
map,
|
|
162
|
+
unmarshal: (handle: QuickJSHandle) =>
|
|
163
|
+
unmarshal(handle, {
|
|
164
|
+
find: (h) => map.getByHandle(h),
|
|
165
|
+
marshal,
|
|
166
|
+
pre: (t, h) => {
|
|
167
|
+
map.set(t, h);
|
|
168
|
+
return t;
|
|
169
|
+
},
|
|
170
|
+
vm,
|
|
171
|
+
}),
|
|
172
|
+
marshal,
|
|
173
|
+
dispose: () => {
|
|
174
|
+
disposables.forEach((d) => d.dispose());
|
|
175
|
+
map.dispose();
|
|
176
|
+
vm.dispose();
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
};
|
package/src/unmarshal/index.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
-
import unmarshalArray from "./array";
|
|
3
2
|
import unmarshalFunction from "./function";
|
|
4
3
|
import unmarshalObject from "./object";
|
|
5
4
|
import unmarshalPrimitive from "./primitive";
|
|
5
|
+
import unmarshalPromise from "./promise";
|
|
6
6
|
import unmarshalSymbol from "./symbol";
|
|
7
7
|
|
|
8
8
|
export type Options = {
|
|
9
9
|
vm: QuickJSVm;
|
|
10
|
-
marshal
|
|
10
|
+
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
11
|
+
marshal: (target: unknown) => [QuickJSHandle, boolean];
|
|
11
12
|
find: (handle: QuickJSHandle) => unknown | undefined;
|
|
12
|
-
pre: <T>(target: T, handle: QuickJSHandle) => T | undefined;
|
|
13
|
+
pre: <T = unknown>(target: T, handle: QuickJSHandle) => T | undefined;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export function unmarshal(handle: QuickJSHandle, options: Options): any {
|
|
@@ -39,7 +40,7 @@ function unmarshalInner(
|
|
|
39
40
|
|
|
40
41
|
const result =
|
|
41
42
|
unmarshalSymbol(vm, handle, pre) ??
|
|
42
|
-
|
|
43
|
+
unmarshalPromise(vm, handle, marshal, pre) ??
|
|
43
44
|
unmarshalFunction(vm, handle, marshal, unmarshal2, pre) ??
|
|
44
45
|
unmarshalObject(vm, handle, unmarshal2, pre);
|
|
45
46
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import unmarshalObject from "./object";
|
|
3
5
|
|
|
4
6
|
test("normal object", async () => {
|
|
5
7
|
const vm = (await getQuickJS()).createVm();
|
|
6
|
-
const unmarshal =
|
|
8
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
7
9
|
vm.dump(v),
|
|
8
10
|
false,
|
|
9
11
|
]);
|
|
10
|
-
const preUnmarshal =
|
|
12
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
11
13
|
|
|
12
14
|
const handle = vm.unwrapResult(vm.evalCode(`({ a: 1, b: true })`));
|
|
13
15
|
const obj = unmarshalObject(vm, handle, unmarshal, preUnmarshal);
|
|
@@ -28,11 +30,11 @@ test("normal object", async () => {
|
|
|
28
30
|
test("properties", async () => {
|
|
29
31
|
const vm = (await getQuickJS()).createVm();
|
|
30
32
|
const disposables: QuickJSHandle[] = [];
|
|
31
|
-
const unmarshal =
|
|
33
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
32
34
|
disposables.push(v);
|
|
33
35
|
return [vm.typeof(v) === "function" ? () => {} : vm.dump(v), false];
|
|
34
36
|
});
|
|
35
|
-
const preUnmarshal =
|
|
37
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
36
38
|
|
|
37
39
|
const handle = vm.unwrapResult(
|
|
38
40
|
vm.evalCode(`{
|
|
@@ -70,18 +72,44 @@ test("properties", async () => {
|
|
|
70
72
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
71
73
|
expect(preUnmarshal).toBeCalledWith(obj, handle);
|
|
72
74
|
|
|
73
|
-
disposables.forEach(d => d.dispose());
|
|
75
|
+
disposables.forEach((d) => d.dispose());
|
|
76
|
+
handle.dispose();
|
|
77
|
+
vm.dispose();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("array", async () => {
|
|
81
|
+
const vm = (await getQuickJS()).createVm();
|
|
82
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
83
|
+
vm.dump(v),
|
|
84
|
+
false,
|
|
85
|
+
]);
|
|
86
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
87
|
+
|
|
88
|
+
const handle = vm.unwrapResult(vm.evalCode(`[1, true, "a"]`));
|
|
89
|
+
const array = unmarshalObject(vm, handle, unmarshal, preUnmarshal);
|
|
90
|
+
expect((array as any)[0]).toEqual(1);
|
|
91
|
+
expect(Array.isArray(array)).toBe(true);
|
|
92
|
+
expect(unmarshal.mock.results[0].value).toEqual(["0", false]);
|
|
93
|
+
expect(unmarshal.mock.results[1].value).toEqual([1, false]);
|
|
94
|
+
expect(unmarshal.mock.results[2].value).toEqual(["1", false]);
|
|
95
|
+
expect(unmarshal.mock.results[3].value).toEqual([true, false]);
|
|
96
|
+
expect(unmarshal.mock.results[4].value).toEqual(["2", false]);
|
|
97
|
+
expect(unmarshal.mock.results[5].value).toEqual(["a", false]);
|
|
98
|
+
expect(unmarshal.mock.results[6].value).toEqual(["length", false]);
|
|
99
|
+
expect(unmarshal.mock.results[7].value).toEqual([3, false]);
|
|
100
|
+
expect(preUnmarshal).toBeCalledWith(array, handle);
|
|
101
|
+
|
|
74
102
|
handle.dispose();
|
|
75
103
|
vm.dispose();
|
|
76
104
|
});
|
|
77
105
|
|
|
78
106
|
test("prototype", async () => {
|
|
79
107
|
const vm = (await getQuickJS()).createVm();
|
|
80
|
-
const unmarshal =
|
|
108
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
81
109
|
vm.typeof(v) === "object" ? { a: () => 1 } : vm.dump(v),
|
|
82
110
|
false,
|
|
83
111
|
]);
|
|
84
|
-
const preUnmarshal =
|
|
112
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
85
113
|
|
|
86
114
|
const handle = vm.unwrapResult(vm.evalCode(`Object.create({ a: () => 1 })`));
|
|
87
115
|
const obj = unmarshalObject(vm, handle, unmarshal, preUnmarshal) as any;
|
|
@@ -99,7 +127,7 @@ test("prototype", async () => {
|
|
|
99
127
|
|
|
100
128
|
test("undefined", async () => {
|
|
101
129
|
const vm = (await getQuickJS()).createVm();
|
|
102
|
-
const f =
|
|
130
|
+
const f = vi.fn();
|
|
103
131
|
|
|
104
132
|
expect(unmarshalObject(vm, vm.undefined, f, f)).toEqual(undefined);
|
|
105
133
|
expect(unmarshalObject(vm, vm.true, f, f)).toEqual(undefined);
|
package/src/unmarshal/object.ts
CHANGED
|
@@ -13,24 +13,28 @@ export default function unmarshalObject(
|
|
|
13
13
|
// null check
|
|
14
14
|
vm
|
|
15
15
|
.unwrapResult(vm.evalCode("o => o === null"))
|
|
16
|
-
.consume(n =>
|
|
16
|
+
.consume((n) =>
|
|
17
17
|
vm.dump(vm.unwrapResult(vm.callFunction(n, vm.undefined, handle)))
|
|
18
18
|
)
|
|
19
19
|
)
|
|
20
20
|
return;
|
|
21
21
|
|
|
22
|
-
const raw =
|
|
22
|
+
const raw = call(vm, "Array.isArray", undefined, handle).consume((r) =>
|
|
23
|
+
vm.dump(r)
|
|
24
|
+
)
|
|
25
|
+
? []
|
|
26
|
+
: {};
|
|
23
27
|
const obj = preUnmarshal(raw, handle) ?? raw;
|
|
24
28
|
|
|
25
29
|
const prototype = call(
|
|
26
30
|
vm,
|
|
27
31
|
`o => {
|
|
28
32
|
const p = Object.getPrototypeOf(o);
|
|
29
|
-
return !p || p === Object.prototype ? undefined : p;
|
|
33
|
+
return !p || p === Object.prototype || p === Array.prototype ? undefined : p;
|
|
30
34
|
}`,
|
|
31
35
|
undefined,
|
|
32
36
|
handle
|
|
33
|
-
).consume(prototype => {
|
|
37
|
+
).consume((prototype) => {
|
|
34
38
|
if (vm.typeof(prototype) === "undefined") return;
|
|
35
39
|
const [proto] = unmarshal(prototype);
|
|
36
40
|
return proto;
|
|
@@ -15,7 +15,7 @@ export default function unmarshalPrimitive(
|
|
|
15
15
|
} else if (ty === "object") {
|
|
16
16
|
const isNull = vm
|
|
17
17
|
.unwrapResult(vm.evalCode("a => a === null"))
|
|
18
|
-
.consume(n =>
|
|
18
|
+
.consume((n) =>
|
|
19
19
|
vm.dump(vm.unwrapResult(vm.callFunction(n, vm.undefined, handle)))
|
|
20
20
|
);
|
|
21
21
|
if (isNull) {
|
|
@@ -33,6 +33,5 @@ export default function unmarshalPrimitive(
|
|
|
33
33
|
// return [bi, true];
|
|
34
34
|
// }
|
|
35
35
|
|
|
36
|
-
// symbol is not supported yet
|
|
37
36
|
return [undefined, false];
|
|
38
37
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Disposable, getQuickJS, type QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import unmarshalPromise from "./promise";
|
|
5
|
+
|
|
6
|
+
const testPromise = (reject: boolean) => async () => {
|
|
7
|
+
const vm = (await getQuickJS()).createVm();
|
|
8
|
+
const disposables: Disposable[] = [];
|
|
9
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => {
|
|
10
|
+
const f = vm.newFunction(v.name, (h) => {
|
|
11
|
+
v(vm.dump(h));
|
|
12
|
+
});
|
|
13
|
+
disposables.push(f);
|
|
14
|
+
return [f, false];
|
|
15
|
+
});
|
|
16
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
17
|
+
|
|
18
|
+
const deferred = vm.newPromise();
|
|
19
|
+
disposables.push(deferred);
|
|
20
|
+
const promise = unmarshalPromise(vm, deferred.handle, marshal, preUnmarshal);
|
|
21
|
+
|
|
22
|
+
expect(marshal).toBeCalledTimes(2);
|
|
23
|
+
expect(preUnmarshal).toBeCalledTimes(1);
|
|
24
|
+
expect(vm.hasPendingJob()).toBe(false);
|
|
25
|
+
|
|
26
|
+
if (reject) {
|
|
27
|
+
deferred.reject(vm.newString("hoge"));
|
|
28
|
+
} else {
|
|
29
|
+
deferred.resolve(vm.newString("hoge"));
|
|
30
|
+
}
|
|
31
|
+
expect(vm.hasPendingJob()).toBe(true);
|
|
32
|
+
expect(vm.unwrapResult(vm.executePendingJobs())).toBe(1);
|
|
33
|
+
if (reject) {
|
|
34
|
+
expect(promise).rejects.toThrow("hoge");
|
|
35
|
+
} else {
|
|
36
|
+
expect(promise).resolves.toBe("hoge");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
disposables.forEach((d) => d.dispose());
|
|
40
|
+
vm.dispose();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
test("resolve", testPromise(false));
|
|
44
|
+
test("reject", testPromise(true));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
3
|
+
import { newDeferred } from "../util";
|
|
4
|
+
import { call, instanceOf } from "../vmutil";
|
|
5
|
+
|
|
6
|
+
export default function unmarshalPromise<T = unknown>(
|
|
7
|
+
vm: QuickJSVm,
|
|
8
|
+
handle: QuickJSHandle,
|
|
9
|
+
/** marshal returns handle and boolean indicates that the handle should be disposed after use */
|
|
10
|
+
marshal: (value: unknown) => [QuickJSHandle, boolean],
|
|
11
|
+
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
12
|
+
): Promise<T> | undefined {
|
|
13
|
+
if (!isPromiseHandle(handle)) return;
|
|
14
|
+
|
|
15
|
+
const deferred = newDeferred<T>();
|
|
16
|
+
const [resHandle, resShouldBeDisposed] = marshal(deferred.resolve);
|
|
17
|
+
const [rejHandle, rejShouldBeDisposed] = marshal(deferred.reject);
|
|
18
|
+
call(
|
|
19
|
+
vm,
|
|
20
|
+
"(p, res, rej) => { p.then(res, rej); }",
|
|
21
|
+
undefined,
|
|
22
|
+
handle,
|
|
23
|
+
resHandle,
|
|
24
|
+
rejHandle
|
|
25
|
+
);
|
|
26
|
+
if (resShouldBeDisposed) resHandle.dispose();
|
|
27
|
+
if (rejShouldBeDisposed) rejHandle.dispose();
|
|
28
|
+
|
|
29
|
+
return preUnmarshal(deferred.promise, handle) ?? deferred.promise;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isPromiseHandle(handle: QuickJSHandle): boolean {
|
|
33
|
+
if (!handle.owner) return false;
|
|
34
|
+
return handle.owner
|
|
35
|
+
.unwrapResult(handle.owner.evalCode("Promise"))
|
|
36
|
+
.consume((promise) => {
|
|
37
|
+
if (!handle.owner) return false;
|
|
38
|
+
return instanceOf(handle.owner, handle, promise);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import unmarshalProperties from "./properties";
|
|
3
5
|
|
|
4
6
|
test("works", async () => {
|
|
5
7
|
const vm = (await getQuickJS()).createVm();
|
|
6
8
|
const disposables: QuickJSHandle[] = [];
|
|
7
|
-
const unmarshal =
|
|
9
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
8
10
|
disposables.push(v);
|
|
9
11
|
return [vm.typeof(v) === "function" ? () => {} : vm.dump(v), false];
|
|
10
12
|
});
|
|
@@ -45,7 +47,7 @@ test("works", async () => {
|
|
|
45
47
|
expect(unmarshal).toReturnWith(["c", false]);
|
|
46
48
|
expect(unmarshal).toReturnWith([expect.any(Function), false]); // get, set
|
|
47
49
|
|
|
48
|
-
disposables.forEach(d => d.dispose());
|
|
50
|
+
disposables.forEach((d) => d.dispose());
|
|
49
51
|
handle.dispose();
|
|
50
52
|
vm.dispose();
|
|
51
53
|
});
|
|
@@ -16,14 +16,16 @@ export default function unmarshalProperties(
|
|
|
16
16
|
)
|
|
17
17
|
return;
|
|
18
18
|
|
|
19
|
-
const desc = (
|
|
20
|
-
[
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const desc = (
|
|
20
|
+
[
|
|
21
|
+
["value", true],
|
|
22
|
+
["get", true],
|
|
23
|
+
["set", true],
|
|
24
|
+
["configurable", false],
|
|
25
|
+
["enumerable", false],
|
|
26
|
+
["writable", false],
|
|
27
|
+
] as const
|
|
28
|
+
).reduce<PropertyDescriptor>((desc, [key, unmarshable]) => {
|
|
27
29
|
const h = vm.getProp(value, key);
|
|
28
30
|
const ty = vm.typeof(h);
|
|
29
31
|
|
|
@@ -43,7 +45,7 @@ export default function unmarshalProperties(
|
|
|
43
45
|
}, {});
|
|
44
46
|
|
|
45
47
|
Object.defineProperty(target, keyName, desc);
|
|
46
|
-
}).consume(fn => {
|
|
48
|
+
}).consume((fn) => {
|
|
47
49
|
call(
|
|
48
50
|
vm,
|
|
49
51
|
`(o, fn) => {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import unmarshalSymbol from "./symbol";
|
|
3
5
|
|
|
4
6
|
test("works", async () => {
|
|
5
7
|
const vm = (await getQuickJS()).createVm();
|
|
6
|
-
const pre =
|
|
8
|
+
const pre = vi.fn();
|
|
7
9
|
const obj = vm.newObject();
|
|
8
10
|
const handle = vm.unwrapResult(vm.evalCode(`Symbol("foobar")`));
|
|
9
11
|
|
package/src/util.test.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expect, test, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
isES2015Class,
|
|
4
|
+
isObject,
|
|
5
|
+
walkObject,
|
|
6
|
+
complexity,
|
|
7
|
+
newDeferred,
|
|
8
|
+
} from "./util";
|
|
2
9
|
|
|
3
10
|
test("isES2015Class", () => {
|
|
4
11
|
expect(isES2015Class(class {})).toBe(true);
|
|
5
12
|
expect(isES2015Class(class A {})).toBe(true);
|
|
6
|
-
expect(isES2015Class(function() {})).toBe(false);
|
|
13
|
+
expect(isES2015Class(function () {})).toBe(false);
|
|
7
14
|
expect(isES2015Class(function A() {})).toBe(false);
|
|
8
15
|
expect(isES2015Class(() => {})).toBe(false);
|
|
9
16
|
expect(isES2015Class({})).toBe(false);
|
|
@@ -14,7 +21,7 @@ test("isES2015Class", () => {
|
|
|
14
21
|
test("isObject", () => {
|
|
15
22
|
expect(isObject({})).toBe(true);
|
|
16
23
|
expect(isObject(Object.create(null))).toBe(true);
|
|
17
|
-
expect(isObject(function() {})).toBe(true);
|
|
24
|
+
expect(isObject(function () {})).toBe(true);
|
|
18
25
|
expect(isObject(function A() {})).toBe(true);
|
|
19
26
|
expect(isObject(() => {})).toBe(true);
|
|
20
27
|
expect(isObject(class {})).toBe(true);
|
|
@@ -25,7 +32,7 @@ test("isObject", () => {
|
|
|
25
32
|
});
|
|
26
33
|
|
|
27
34
|
test("walkObject", () => {
|
|
28
|
-
const cb =
|
|
35
|
+
const cb = vi.fn();
|
|
29
36
|
const obj = { a: { b: 1, c: () => {} } };
|
|
30
37
|
const set = new Set<any>([obj, obj.a, obj.a.c]);
|
|
31
38
|
expect(walkObject(obj, cb)).toEqual(set);
|
|
@@ -47,8 +54,18 @@ test("complexity", () => {
|
|
|
47
54
|
expect(complexity({ a: 1 })).toBe(1);
|
|
48
55
|
expect(complexity(() => {})).toBe(1);
|
|
49
56
|
expect(complexity([{}])).toBe(2);
|
|
50
|
-
expect(complexity(function() {})).toBe(2);
|
|
57
|
+
expect(complexity(function () {})).toBe(2);
|
|
51
58
|
expect(complexity(class {})).toBe(2);
|
|
52
59
|
expect(complexity({ a: {} })).toBe(2);
|
|
53
60
|
expect(complexity({ a: {} }, 1)).toBe(1);
|
|
54
61
|
});
|
|
62
|
+
|
|
63
|
+
test("newDeferred", () => {
|
|
64
|
+
const deferred = newDeferred();
|
|
65
|
+
deferred.resolve("foo");
|
|
66
|
+
expect(deferred.promise).resolves.toBe("foo");
|
|
67
|
+
|
|
68
|
+
const deferred2 = newDeferred();
|
|
69
|
+
deferred2.reject("bar");
|
|
70
|
+
expect(deferred2.promise).rejects.toBe("bar");
|
|
71
|
+
});
|
package/src/util.ts
CHANGED
|
@@ -51,3 +51,18 @@ export function walkObject(
|
|
|
51
51
|
export function complexity(value: any, max?: number): number {
|
|
52
52
|
return walkObject(value, max ? (_, set) => set.size < max : undefined).size;
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
export function newDeferred<T = unknown>() {
|
|
56
|
+
let res: (v: T | PromiseLike<T>) => void = () => {};
|
|
57
|
+
let rej: (v: T | PromiseLike<T>) => void = () => {};
|
|
58
|
+
const promise = new Promise<T>((resolve, reject) => {
|
|
59
|
+
res = resolve;
|
|
60
|
+
rej = reject;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
promise,
|
|
65
|
+
resolve: res,
|
|
66
|
+
reject: rej,
|
|
67
|
+
};
|
|
68
|
+
}
|