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
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import marshalJSON from "./json";
|
|
5
|
+
|
|
6
|
+
test("empty object", async () => {
|
|
7
|
+
const vm = (await getQuickJS()).createVm();
|
|
8
|
+
const prototypeCheck = vm.unwrapResult(
|
|
9
|
+
vm.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const obj = {};
|
|
13
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
14
|
+
|
|
15
|
+
const handle = marshalJSON(vm, obj, preMarshal);
|
|
16
|
+
if (!handle) throw new Error("handle is undefined");
|
|
17
|
+
|
|
18
|
+
expect(vm.typeof(handle)).toBe("object");
|
|
19
|
+
expect(preMarshal).toBeCalledTimes(1);
|
|
20
|
+
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
21
|
+
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
22
|
+
expect(
|
|
23
|
+
vm.dump(
|
|
24
|
+
vm.unwrapResult(vm.callFunction(prototypeCheck, vm.undefined, handle))
|
|
25
|
+
)
|
|
26
|
+
).toBe(true);
|
|
27
|
+
|
|
28
|
+
handle.dispose();
|
|
29
|
+
prototypeCheck.dispose();
|
|
30
|
+
vm.dispose();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("normal object", async () => {
|
|
34
|
+
const vm = (await getQuickJS()).createVm();
|
|
35
|
+
const prototypeCheck = vm.unwrapResult(
|
|
36
|
+
vm.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
|
|
37
|
+
);
|
|
38
|
+
const entries = vm.unwrapResult(vm.evalCode(`Object.entries`));
|
|
39
|
+
|
|
40
|
+
const obj = { a: 100, b: "hoge" };
|
|
41
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
42
|
+
|
|
43
|
+
const handle = marshalJSON(vm, obj, preMarshal);
|
|
44
|
+
if (!handle) throw new Error("handle is undefined");
|
|
45
|
+
|
|
46
|
+
expect(vm.typeof(handle)).toBe("object");
|
|
47
|
+
expect(vm.getNumber(vm.getProp(handle, "a"))).toBe(100);
|
|
48
|
+
expect(vm.getString(vm.getProp(handle, "b"))).toBe("hoge");
|
|
49
|
+
expect(preMarshal).toBeCalledTimes(1);
|
|
50
|
+
expect(preMarshal.mock.calls[0][0]).toBe(obj);
|
|
51
|
+
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
52
|
+
expect(
|
|
53
|
+
vm.dump(
|
|
54
|
+
vm.unwrapResult(vm.callFunction(prototypeCheck, vm.undefined, handle))
|
|
55
|
+
)
|
|
56
|
+
).toBe(true);
|
|
57
|
+
const e = vm.unwrapResult(vm.callFunction(entries, vm.undefined, handle));
|
|
58
|
+
expect(vm.dump(e)).toEqual([
|
|
59
|
+
["a", 100],
|
|
60
|
+
["b", "hoge"],
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
e.dispose();
|
|
64
|
+
handle.dispose();
|
|
65
|
+
prototypeCheck.dispose();
|
|
66
|
+
entries.dispose();
|
|
67
|
+
vm.dispose();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("array", async () => {
|
|
71
|
+
const vm = (await getQuickJS()).createVm();
|
|
72
|
+
const isArray = vm.unwrapResult(vm.evalCode(`Array.isArray`));
|
|
73
|
+
|
|
74
|
+
const array = [1, "aa"];
|
|
75
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
76
|
+
|
|
77
|
+
const handle = marshalJSON(vm, array, preMarshal);
|
|
78
|
+
if (!handle) throw new Error("handle is undefined");
|
|
79
|
+
|
|
80
|
+
expect(vm.typeof(handle)).toBe("object");
|
|
81
|
+
expect(vm.getNumber(vm.getProp(handle, 0))).toBe(1);
|
|
82
|
+
expect(vm.getString(vm.getProp(handle, 1))).toBe("aa");
|
|
83
|
+
expect(vm.getNumber(vm.getProp(handle, "length"))).toBe(2);
|
|
84
|
+
expect(preMarshal).toBeCalledTimes(1);
|
|
85
|
+
expect(preMarshal.mock.calls[0][0]).toBe(array);
|
|
86
|
+
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
87
|
+
expect(
|
|
88
|
+
vm.dump(vm.unwrapResult(vm.callFunction(isArray, vm.undefined, handle)))
|
|
89
|
+
).toBe(true);
|
|
90
|
+
|
|
91
|
+
handle.dispose();
|
|
92
|
+
isArray.dispose();
|
|
93
|
+
vm.dispose();
|
|
94
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
import { json } from "../vmutil";
|
|
3
|
+
|
|
4
|
+
export default function marshalJSON(
|
|
5
|
+
vm: QuickJSVm,
|
|
6
|
+
target: unknown,
|
|
7
|
+
preMarshal: (
|
|
8
|
+
target: unknown,
|
|
9
|
+
handle: QuickJSHandle
|
|
10
|
+
) => QuickJSHandle | undefined
|
|
11
|
+
): QuickJSHandle {
|
|
12
|
+
const raw = json(vm, target);
|
|
13
|
+
const handle = preMarshal(target, raw) ?? raw;
|
|
14
|
+
return handle;
|
|
15
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import { call } from "../vmutil";
|
|
3
5
|
import marshalObject from "./object";
|
|
4
6
|
|
|
@@ -9,8 +11,8 @@ test("empty object", async () => {
|
|
|
9
11
|
);
|
|
10
12
|
|
|
11
13
|
const obj = {};
|
|
12
|
-
const marshal =
|
|
13
|
-
const preMarshal =
|
|
14
|
+
const marshal = vi.fn();
|
|
15
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
14
16
|
|
|
15
17
|
const handle = marshalObject(vm, obj, marshal, preMarshal);
|
|
16
18
|
if (!handle) throw new Error("handle is undefined");
|
|
@@ -39,14 +41,14 @@ test("normal object", async () => {
|
|
|
39
41
|
const entries = vm.unwrapResult(vm.evalCode(`Object.entries`));
|
|
40
42
|
|
|
41
43
|
const obj = { a: 100, b: "hoge" };
|
|
42
|
-
const marshal =
|
|
44
|
+
const marshal = vi.fn((v) =>
|
|
43
45
|
typeof v === "number"
|
|
44
46
|
? vm.newNumber(v)
|
|
45
47
|
: typeof v === "string"
|
|
46
48
|
? vm.newString(v)
|
|
47
49
|
: vm.null
|
|
48
50
|
);
|
|
49
|
-
const preMarshal =
|
|
51
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
50
52
|
|
|
51
53
|
const handle = marshalObject(vm, obj, marshal, preMarshal);
|
|
52
54
|
if (!handle) throw new Error("handle is undefined");
|
|
@@ -76,20 +78,61 @@ test("normal object", async () => {
|
|
|
76
78
|
vm.dispose();
|
|
77
79
|
});
|
|
78
80
|
|
|
81
|
+
test("array", async () => {
|
|
82
|
+
const vm = (await getQuickJS()).createVm();
|
|
83
|
+
const isArray = vm.unwrapResult(vm.evalCode(`Array.isArray`));
|
|
84
|
+
|
|
85
|
+
const array = [1, "aa"];
|
|
86
|
+
const marshal = vi.fn((v) =>
|
|
87
|
+
typeof v === "number"
|
|
88
|
+
? vm.newNumber(v)
|
|
89
|
+
: typeof v === "string"
|
|
90
|
+
? vm.newString(v)
|
|
91
|
+
: vm.null
|
|
92
|
+
);
|
|
93
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
94
|
+
|
|
95
|
+
const handle = marshalObject(vm, array, marshal, preMarshal);
|
|
96
|
+
if (!handle) throw new Error("handle is undefined");
|
|
97
|
+
|
|
98
|
+
expect(vm.typeof(handle)).toBe("object");
|
|
99
|
+
expect(vm.getNumber(vm.getProp(handle, 0))).toBe(1);
|
|
100
|
+
expect(vm.getString(vm.getProp(handle, 1))).toBe("aa");
|
|
101
|
+
expect(vm.getNumber(vm.getProp(handle, "length"))).toBe(2);
|
|
102
|
+
expect(marshal.mock.calls).toEqual([
|
|
103
|
+
["0"],
|
|
104
|
+
[1],
|
|
105
|
+
["1"],
|
|
106
|
+
["aa"],
|
|
107
|
+
["length"],
|
|
108
|
+
[2],
|
|
109
|
+
]);
|
|
110
|
+
expect(preMarshal).toBeCalledTimes(1);
|
|
111
|
+
expect(preMarshal.mock.calls[0][0]).toBe(array);
|
|
112
|
+
expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
|
|
113
|
+
expect(
|
|
114
|
+
vm.dump(vm.unwrapResult(vm.callFunction(isArray, vm.undefined, handle)))
|
|
115
|
+
).toBe(true);
|
|
116
|
+
|
|
117
|
+
handle.dispose();
|
|
118
|
+
isArray.dispose();
|
|
119
|
+
vm.dispose();
|
|
120
|
+
});
|
|
121
|
+
|
|
79
122
|
test("prototype", async () => {
|
|
80
123
|
const vm = (await getQuickJS()).createVm();
|
|
81
124
|
|
|
82
125
|
const proto = { a: 100 };
|
|
83
126
|
const protoHandle = vm.newObject();
|
|
84
127
|
vm.setProp(protoHandle, "a", vm.newNumber(100));
|
|
85
|
-
const preMarshal =
|
|
128
|
+
const preMarshal = vi.fn((_, a) => a);
|
|
86
129
|
|
|
87
130
|
const obj = Object.create(proto);
|
|
88
131
|
obj.b = "hoge";
|
|
89
132
|
const handle = marshalObject(
|
|
90
133
|
vm,
|
|
91
134
|
obj,
|
|
92
|
-
v =>
|
|
135
|
+
(v) =>
|
|
93
136
|
v === proto
|
|
94
137
|
? protoHandle
|
|
95
138
|
: typeof v === "string"
|
package/src/marshal/object.ts
CHANGED
|
@@ -13,13 +13,13 @@ export default function marshalObject(
|
|
|
13
13
|
): QuickJSHandle | undefined {
|
|
14
14
|
if (typeof target !== "object" || target === null) return;
|
|
15
15
|
|
|
16
|
-
const raw = vm.newObject();
|
|
16
|
+
const raw = Array.isArray(target) ? vm.newArray() : vm.newObject();
|
|
17
17
|
const handle = preMarshal(target, raw) ?? raw;
|
|
18
18
|
|
|
19
19
|
// prototype
|
|
20
20
|
const prototype = Object.getPrototypeOf(target);
|
|
21
21
|
const prototypeHandle =
|
|
22
|
-
prototype && prototype !== Object.prototype
|
|
22
|
+
prototype && prototype !== Object.prototype && prototype !== Array.prototype
|
|
23
23
|
? marshal(prototype)
|
|
24
24
|
: undefined;
|
|
25
25
|
if (prototypeHandle) {
|
package/src/marshal/primitive.ts
CHANGED
|
@@ -16,10 +16,16 @@ export default function marshalPrimitive(
|
|
|
16
16
|
return target ? vm.true : vm.false;
|
|
17
17
|
case "object":
|
|
18
18
|
return target === null ? vm.null : undefined;
|
|
19
|
+
|
|
19
20
|
// BigInt is not supported by quickjs-emscripten
|
|
20
21
|
// case "bigint":
|
|
21
|
-
// return call(
|
|
22
|
+
// return call(
|
|
23
|
+
// vm,
|
|
24
|
+
// `s => BigInt(s)`,
|
|
25
|
+
// undefined,
|
|
26
|
+
// vm.newString(target.toString())
|
|
27
|
+
// );
|
|
22
28
|
}
|
|
23
|
-
|
|
29
|
+
|
|
24
30
|
return undefined;
|
|
25
31
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getQuickJS,
|
|
3
|
+
type Disposable,
|
|
4
|
+
type QuickJSDeferredPromise,
|
|
5
|
+
type QuickJSHandle,
|
|
6
|
+
} from "quickjs-emscripten";
|
|
7
|
+
import { expect, test, vi } from "vitest";
|
|
8
|
+
import { newDeferred } from "../util";
|
|
9
|
+
|
|
10
|
+
import { fn, json } from "../vmutil";
|
|
11
|
+
import marshalPromise from "./promise";
|
|
12
|
+
|
|
13
|
+
const testPromise = (reject: boolean) => async () => {
|
|
14
|
+
const vm = (await getQuickJS()).createVm();
|
|
15
|
+
|
|
16
|
+
const disposables: Disposable[] = [];
|
|
17
|
+
const marshal = vi.fn((v) => {
|
|
18
|
+
const handle = json(vm, v);
|
|
19
|
+
disposables.push(handle);
|
|
20
|
+
return handle;
|
|
21
|
+
});
|
|
22
|
+
const preMarshal = vi.fn(
|
|
23
|
+
(_: any, a: QuickJSDeferredPromise): QuickJSHandle => {
|
|
24
|
+
disposables.push(a);
|
|
25
|
+
return a.handle;
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const mockNotify = vi.fn();
|
|
30
|
+
const notify = vm.newFunction("notify", (handle1, handle2) => {
|
|
31
|
+
const arg1 = vm.dump(handle1);
|
|
32
|
+
const arg2 = vm.dump(handle2);
|
|
33
|
+
mockNotify(arg1, arg2);
|
|
34
|
+
});
|
|
35
|
+
disposables.push(notify);
|
|
36
|
+
|
|
37
|
+
const notifier = fn(
|
|
38
|
+
vm,
|
|
39
|
+
`(notify, promise) => { promise.then(d => notify("resolved", d), d => notify("rejected", d)); }`
|
|
40
|
+
);
|
|
41
|
+
disposables.push(notifier);
|
|
42
|
+
|
|
43
|
+
const deferred = newDeferred();
|
|
44
|
+
if (reject) {
|
|
45
|
+
deferred.promise.catch(() => {});
|
|
46
|
+
}
|
|
47
|
+
const handle = marshalPromise(vm, deferred.promise, marshal, preMarshal);
|
|
48
|
+
if (!handle) throw new Error("handle is undefined");
|
|
49
|
+
|
|
50
|
+
expect(marshal).toBeCalledTimes(0);
|
|
51
|
+
expect(preMarshal).toBeCalledTimes(1);
|
|
52
|
+
expect(preMarshal.mock.calls[0][0]).toBe(deferred.promise);
|
|
53
|
+
expect(preMarshal.mock.calls[0][1].handle).toBe(handle);
|
|
54
|
+
|
|
55
|
+
notifier(undefined, notify, handle);
|
|
56
|
+
|
|
57
|
+
expect(mockNotify).toBeCalledTimes(0);
|
|
58
|
+
expect(deferred.resolve).not.toBeUndefined();
|
|
59
|
+
expect(vm.hasPendingJob()).toBe(false);
|
|
60
|
+
|
|
61
|
+
if (reject) {
|
|
62
|
+
deferred.reject("hoge");
|
|
63
|
+
} else {
|
|
64
|
+
deferred.resolve("hoge");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
expect(vm.hasPendingJob()).toBe(false);
|
|
68
|
+
if (reject) {
|
|
69
|
+
await expect(deferred.promise).rejects.toBe("hoge");
|
|
70
|
+
} else {
|
|
71
|
+
await expect(deferred.promise).resolves.toBe("hoge");
|
|
72
|
+
}
|
|
73
|
+
expect(vm.hasPendingJob()).toBe(true);
|
|
74
|
+
const executed = vm.unwrapResult(vm.executePendingJobs());
|
|
75
|
+
expect(executed).toBe(1);
|
|
76
|
+
expect(mockNotify).toBeCalledTimes(1);
|
|
77
|
+
expect(mockNotify).toBeCalledWith(reject ? "rejected" : "resolved", "hoge");
|
|
78
|
+
expect(marshal).toBeCalledTimes(1);
|
|
79
|
+
expect(marshal.mock.calls).toEqual([["hoge"]]);
|
|
80
|
+
|
|
81
|
+
disposables.forEach((h) => h.dispose());
|
|
82
|
+
vm.dispose();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
test("resolve", testPromise(false));
|
|
86
|
+
test("reject", testPromise(true));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
QuickJSDeferredPromise,
|
|
3
|
+
QuickJSHandle,
|
|
4
|
+
QuickJSVm,
|
|
5
|
+
} from "quickjs-emscripten";
|
|
6
|
+
|
|
7
|
+
export default function marshalPromise(
|
|
8
|
+
vm: QuickJSVm,
|
|
9
|
+
target: unknown,
|
|
10
|
+
marshal: (target: unknown) => QuickJSHandle,
|
|
11
|
+
preMarshal: (
|
|
12
|
+
target: unknown,
|
|
13
|
+
handle: QuickJSDeferredPromise
|
|
14
|
+
) => QuickJSHandle | undefined
|
|
15
|
+
) {
|
|
16
|
+
if (!(target instanceof Promise)) return;
|
|
17
|
+
|
|
18
|
+
const promise = vm.newPromise();
|
|
19
|
+
|
|
20
|
+
target.then(
|
|
21
|
+
(d) => promise.resolve(marshal(d)),
|
|
22
|
+
(d) => promise.reject(marshal(d))
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return preMarshal(target, promise) ?? promise.handle;
|
|
26
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
-
import {
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { json } from "../vmutil";
|
|
3
5
|
import marshalProperties from "./properties";
|
|
4
6
|
|
|
5
7
|
test("works", async () => {
|
|
@@ -20,8 +22,8 @@ test("works", async () => {
|
|
|
20
22
|
);
|
|
21
23
|
|
|
22
24
|
const disposables: QuickJSHandle[] = [];
|
|
23
|
-
const marshal =
|
|
24
|
-
if (typeof t !== "function") return
|
|
25
|
+
const marshal = vi.fn((t) => {
|
|
26
|
+
if (typeof t !== "function") return json(vm, t);
|
|
25
27
|
const fn = vm.newFunction("", () => {});
|
|
26
28
|
disposables.push(fn);
|
|
27
29
|
return fn;
|
|
@@ -65,7 +67,7 @@ test("works", async () => {
|
|
|
65
67
|
vm.unwrapResult(vm.callFunction(descTester, vm.undefined, handle, expected));
|
|
66
68
|
|
|
67
69
|
expected.dispose();
|
|
68
|
-
disposables.forEach(d => d.dispose());
|
|
70
|
+
disposables.forEach((d) => d.dispose());
|
|
69
71
|
handle.dispose();
|
|
70
72
|
descTester.dispose();
|
|
71
73
|
vm.dispose();
|
|
@@ -73,7 +75,7 @@ test("works", async () => {
|
|
|
73
75
|
|
|
74
76
|
test("empty", async () => {
|
|
75
77
|
const vm = (await getQuickJS()).createVm();
|
|
76
|
-
const marshal =
|
|
78
|
+
const marshal = vi.fn();
|
|
77
79
|
const handle = vm.newObject();
|
|
78
80
|
const obj = {};
|
|
79
81
|
|
|
@@ -17,7 +17,7 @@ export default function marshalProperties(
|
|
|
17
17
|
const setHandle =
|
|
18
18
|
typeof desc.set === "undefined" ? undefined : marshal(desc.set);
|
|
19
19
|
|
|
20
|
-
vm.newObject().consume(descObj => {
|
|
20
|
+
vm.newObject().consume((descObj) => {
|
|
21
21
|
Object.entries(desc).forEach(([k, v]) => {
|
|
22
22
|
const v2 =
|
|
23
23
|
k === "value"
|
|
@@ -39,7 +39,7 @@ export default function marshalProperties(
|
|
|
39
39
|
|
|
40
40
|
const desc = Object.getOwnPropertyDescriptors(target);
|
|
41
41
|
Object.entries(desc).forEach(([k, v]) => cb(k, v));
|
|
42
|
-
Object.getOwnPropertySymbols(desc).forEach(k => cb(k, (desc as any)[k]));
|
|
42
|
+
Object.getOwnPropertySymbols(desc).forEach((k) => cb(k, (desc as any)[k]));
|
|
43
43
|
|
|
44
44
|
call(vm, `Object.defineProperties`, undefined, handle, descs).dispose();
|
|
45
45
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
2
4
|
import marshalSymbol 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 sym = Symbol("foobar");
|
|
8
10
|
|
|
9
11
|
expect(marshalSymbol(vm, {}, pre)).toBe(undefined);
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
-
import {
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { json } from "../vmutil";
|
|
3
5
|
import unmarshalFunction from "./function";
|
|
4
6
|
|
|
5
7
|
test("arrow function", async () => {
|
|
6
8
|
const vm = (await getQuickJS()).createVm();
|
|
7
|
-
const marshal =
|
|
8
|
-
const unmarshal =
|
|
9
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [json(vm, v), false]);
|
|
10
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
9
11
|
vm.dump(v),
|
|
10
12
|
false,
|
|
11
13
|
]);
|
|
12
|
-
const preUnmarshal =
|
|
14
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
13
15
|
|
|
14
16
|
const handle = vm.unwrapResult(vm.evalCode(`(a, b) => a + b`));
|
|
15
17
|
const func = unmarshalFunction(vm, handle, marshal, unmarshal, preUnmarshal);
|
|
@@ -39,14 +41,17 @@ test("function", async () => {
|
|
|
39
41
|
const vm = (await getQuickJS()).createVm();
|
|
40
42
|
const that = { a: 1 };
|
|
41
43
|
const thatHandle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
|
|
42
|
-
const marshal =
|
|
44
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
45
|
+
v === that ? thatHandle : json(vm, v),
|
|
46
|
+
false,
|
|
47
|
+
]);
|
|
43
48
|
const disposables: QuickJSHandle[] = [];
|
|
44
|
-
const unmarshal =
|
|
49
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
45
50
|
const ty = vm.typeof(v);
|
|
46
51
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
47
52
|
return [vm.dump(v), false];
|
|
48
53
|
});
|
|
49
|
-
const preUnmarshal =
|
|
54
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
50
55
|
|
|
51
56
|
const handle = vm.unwrapResult(
|
|
52
57
|
vm.evalCode(`(function (a) { return this.a + a; })`)
|
|
@@ -70,7 +75,7 @@ test("function", async () => {
|
|
|
70
75
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
71
76
|
expect(preUnmarshal).toBeCalledWith(func, handle);
|
|
72
77
|
|
|
73
|
-
disposables.forEach(d => d.dispose());
|
|
78
|
+
disposables.forEach((d) => d.dispose());
|
|
74
79
|
thatHandle.dispose();
|
|
75
80
|
handle.dispose();
|
|
76
81
|
vm.dispose();
|
|
@@ -79,15 +84,16 @@ test("function", async () => {
|
|
|
79
84
|
test("constructor", async () => {
|
|
80
85
|
const vm = (await getQuickJS()).createVm();
|
|
81
86
|
const disposables: QuickJSHandle[] = [];
|
|
82
|
-
const marshal =
|
|
83
|
-
typeof v === "object" ? vm.undefined :
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
88
|
+
typeof v === "object" ? vm.undefined : json(vm, v),
|
|
89
|
+
false,
|
|
90
|
+
]);
|
|
91
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
86
92
|
const ty = vm.typeof(v);
|
|
87
93
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
88
94
|
return [vm.dump(v), false];
|
|
89
95
|
});
|
|
90
|
-
const preUnmarshal =
|
|
96
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
91
97
|
|
|
92
98
|
const handle = vm.unwrapResult(
|
|
93
99
|
vm.evalCode(`(function (b) { this.a = b + 2; })`)
|
|
@@ -119,23 +125,24 @@ test("constructor", async () => {
|
|
|
119
125
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
120
126
|
expect(preUnmarshal).toBeCalledWith(Cls, handle);
|
|
121
127
|
|
|
122
|
-
disposables.forEach(d => d.dispose());
|
|
128
|
+
disposables.forEach((d) => d.dispose());
|
|
123
129
|
handle.dispose();
|
|
124
130
|
vm.dispose();
|
|
125
131
|
});
|
|
126
132
|
|
|
127
133
|
test("class", async () => {
|
|
128
134
|
const vm = (await getQuickJS()).createVm();
|
|
129
|
-
const marshal =
|
|
130
|
-
typeof v === "object" ? vm.undefined :
|
|
131
|
-
|
|
135
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
|
|
136
|
+
typeof v === "object" ? vm.undefined : json(vm, v),
|
|
137
|
+
false,
|
|
138
|
+
]);
|
|
132
139
|
const disposables: QuickJSHandle[] = [];
|
|
133
|
-
const unmarshal =
|
|
140
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
134
141
|
const ty = vm.typeof(v);
|
|
135
142
|
if (ty === "object" || ty === "function") disposables.push(v);
|
|
136
143
|
return [vm.dump(v), false];
|
|
137
144
|
});
|
|
138
|
-
const preUnmarshal =
|
|
145
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
139
146
|
|
|
140
147
|
const handle = vm.unwrapResult(
|
|
141
148
|
vm.evalCode(`(class A { constructor(a) { this.a = a + 1; } })`)
|
|
@@ -167,14 +174,14 @@ test("class", async () => {
|
|
|
167
174
|
expect(preUnmarshal).toBeCalledTimes(1);
|
|
168
175
|
expect(preUnmarshal).toBeCalledWith(Cls, handle);
|
|
169
176
|
|
|
170
|
-
disposables.forEach(d => d.dispose());
|
|
177
|
+
disposables.forEach((d) => d.dispose());
|
|
171
178
|
handle.dispose();
|
|
172
179
|
vm.dispose();
|
|
173
180
|
});
|
|
174
181
|
|
|
175
182
|
test("undefined", async () => {
|
|
176
183
|
const vm = (await getQuickJS()).createVm();
|
|
177
|
-
const f =
|
|
184
|
+
const f = vi.fn();
|
|
178
185
|
|
|
179
186
|
expect(unmarshalFunction(vm, vm.undefined, f, f, f)).toEqual(undefined);
|
|
180
187
|
expect(unmarshalFunction(vm, vm.true, f, f, f)).toEqual(undefined);
|
|
@@ -1,40 +1,48 @@
|
|
|
1
1
|
import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
-
import { call } from "../vmutil";
|
|
2
|
+
import { call, mayConsumeAll } from "../vmutil";
|
|
3
3
|
import unmarshalProperties from "./properties";
|
|
4
4
|
|
|
5
5
|
export default function unmarshalFunction(
|
|
6
6
|
vm: QuickJSVm,
|
|
7
7
|
handle: QuickJSHandle,
|
|
8
|
-
marshal
|
|
8
|
+
// marshal returns handle and boolean indicates that the handle should be disposed after use
|
|
9
|
+
marshal: (value: unknown) => [QuickJSHandle, boolean],
|
|
9
10
|
unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
|
|
10
11
|
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
11
12
|
): Function | undefined {
|
|
12
13
|
if (vm.typeof(handle) !== "function") return;
|
|
13
14
|
|
|
14
|
-
const raw = function(this: any, ...args: any[]) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const raw = function (this: any, ...args: any[]) {
|
|
16
|
+
return mayConsumeAll(
|
|
17
|
+
[marshal(this), ...args.map((a) => marshal(a))],
|
|
18
|
+
(thisHandle, ...argHandles) => {
|
|
19
|
+
if (new.target) {
|
|
20
|
+
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)
|
|
32
|
+
);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
17
35
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
vm,
|
|
22
|
-
`(Cls, ...args) => new Cls(...args)`,
|
|
23
|
-
thisHandle,
|
|
24
|
-
handle,
|
|
25
|
-
...argHandles
|
|
26
|
-
)
|
|
27
|
-
);
|
|
28
|
-
Object.defineProperties(this, Object.getOwnPropertyDescriptors(instance));
|
|
29
|
-
return this;
|
|
30
|
-
}
|
|
36
|
+
const resultHandle = vm.unwrapResult(
|
|
37
|
+
vm.callFunction(handle, thisHandle, ...argHandles)
|
|
38
|
+
);
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
const [result, alreadyExists] = unmarshal(resultHandle);
|
|
41
|
+
if (alreadyExists) resultHandle.dispose();
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
34
45
|
);
|
|
35
|
-
const [result, alreadyExists] = unmarshal(resultHandle);
|
|
36
|
-
if (alreadyExists) resultHandle.dispose();
|
|
37
|
-
return result;
|
|
38
46
|
};
|
|
39
47
|
|
|
40
48
|
const func = preUnmarshal(raw, handle) ?? raw;
|