quickjs-emscripten-sync 1.1.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/LICENSE +2 -2
- package/README.md +59 -49
- package/dist/index.d.ts +121 -26
- package/dist/quickjs-emscripten-sync.es.js +962 -0
- package/dist/quickjs-emscripten-sync.umd.js +64 -0
- package/package.json +28 -40
- package/src/default.ts +2 -2
- package/src/index.test.ts +371 -69
- package/src/index.ts +135 -72
- package/src/marshal/function.test.ts +70 -61
- package/src/marshal/function.ts +10 -9
- package/src/marshal/index.test.ts +135 -62
- package/src/marshal/index.ts +33 -16
- package/src/marshal/json.test.ts +94 -0
- package/src/marshal/json.ts +16 -0
- package/src/marshal/object.test.ts +65 -58
- package/src/marshal/object.ts +6 -5
- package/src/marshal/primitive.test.ts +23 -17
- package/src/marshal/primitive.ts +10 -9
- package/src/marshal/promise.test.ts +86 -0
- package/src/marshal/promise.ts +26 -0
- package/src/marshal/properties.test.ts +23 -19
- package/src/marshal/properties.ts +11 -10
- package/src/marshal/symbol.test.ts +9 -7
- package/src/marshal/symbol.ts +5 -4
- package/src/unmarshal/function.test.ts +70 -61
- package/src/unmarshal/function.ts +39 -30
- package/src/unmarshal/index.test.ts +101 -100
- package/src/unmarshal/index.ts +13 -9
- package/src/unmarshal/object.test.ts +45 -41
- package/src/unmarshal/object.ts +14 -13
- package/src/unmarshal/primitive.test.ts +20 -15
- package/src/unmarshal/primitive.ts +10 -10
- package/src/unmarshal/promise.test.ts +44 -0
- package/src/unmarshal/promise.ts +38 -0
- package/src/unmarshal/properties.test.ts +10 -8
- package/src/unmarshal/properties.ts +47 -42
- package/src/unmarshal/symbol.test.ts +9 -7
- package/src/unmarshal/symbol.ts +4 -4
- package/src/util.test.ts +23 -5
- package/src/util.ts +15 -0
- package/src/vmmap.test.ts +88 -82
- package/src/vmmap.ts +21 -17
- package/src/vmutil.test.ts +159 -53
- package/src/vmutil.ts +91 -19
- package/src/wrapper.test.ts +151 -115
- package/src/wrapper.ts +69 -48
- package/dist/default.d.ts +0 -4
- package/dist/index.js +0 -8
- 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 -1289
- 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 -1272
- package/dist/quickjs-emscripten-sync.esm.js.map +0 -1
- 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
|
@@ -1,16 +1,18 @@
|
|
|
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
|
-
const
|
|
6
|
-
const unmarshal =
|
|
7
|
-
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
9
|
+
ctx.dump(v),
|
|
8
10
|
false,
|
|
9
11
|
]);
|
|
10
|
-
const preUnmarshal =
|
|
12
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
11
13
|
|
|
12
|
-
const handle =
|
|
13
|
-
const obj = unmarshalObject(
|
|
14
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`({ a: 1, b: true })`));
|
|
15
|
+
const obj = unmarshalObject(ctx, handle, unmarshal, preUnmarshal);
|
|
14
16
|
if (!obj) throw new Error("obj is undefined");
|
|
15
17
|
expect(obj).toEqual({ a: 1, b: true });
|
|
16
18
|
expect(unmarshal).toReturnTimes(4);
|
|
@@ -22,20 +24,20 @@ test("normal object", async () => {
|
|
|
22
24
|
expect(preUnmarshal).toBeCalledWith(obj, handle);
|
|
23
25
|
|
|
24
26
|
handle.dispose();
|
|
25
|
-
|
|
27
|
+
ctx.dispose();
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
test("properties", async () => {
|
|
29
|
-
const
|
|
31
|
+
const ctx = (await getQuickJS()).newContext();
|
|
30
32
|
const disposables: QuickJSHandle[] = [];
|
|
31
|
-
const unmarshal =
|
|
33
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
32
34
|
disposables.push(v);
|
|
33
|
-
return [
|
|
35
|
+
return [ctx.typeof(v) === "function" ? () => {} : ctx.dump(v), false];
|
|
34
36
|
});
|
|
35
|
-
const preUnmarshal =
|
|
37
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
36
38
|
|
|
37
|
-
const handle =
|
|
38
|
-
|
|
39
|
+
const handle = ctx.unwrapResult(
|
|
40
|
+
ctx.evalCode(`{
|
|
39
41
|
const obj = {};
|
|
40
42
|
Object.defineProperties(obj, {
|
|
41
43
|
a: { value: 1, writable: true, configurable: true, enumerable: true },
|
|
@@ -45,7 +47,7 @@ test("properties", async () => {
|
|
|
45
47
|
obj
|
|
46
48
|
}`)
|
|
47
49
|
);
|
|
48
|
-
const obj = unmarshalObject(
|
|
50
|
+
const obj = unmarshalObject(ctx, handle, unmarshal, preUnmarshal);
|
|
49
51
|
if (!obj) throw new Error("obj is undefined");
|
|
50
52
|
expect(obj).toEqual({
|
|
51
53
|
a: 1,
|
|
@@ -70,21 +72,21 @@ 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());
|
|
74
76
|
handle.dispose();
|
|
75
|
-
|
|
77
|
+
ctx.dispose();
|
|
76
78
|
});
|
|
77
79
|
|
|
78
80
|
test("array", async () => {
|
|
79
|
-
const
|
|
80
|
-
const unmarshal =
|
|
81
|
-
|
|
81
|
+
const ctx = (await getQuickJS()).newContext();
|
|
82
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
83
|
+
ctx.dump(v),
|
|
82
84
|
false,
|
|
83
85
|
]);
|
|
84
|
-
const preUnmarshal =
|
|
86
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
85
87
|
|
|
86
|
-
const handle =
|
|
87
|
-
const array = unmarshalObject(
|
|
88
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`[1, true, "a"]`));
|
|
89
|
+
const array = unmarshalObject(ctx, handle, unmarshal, preUnmarshal);
|
|
88
90
|
expect((array as any)[0]).toEqual(1);
|
|
89
91
|
expect(Array.isArray(array)).toBe(true);
|
|
90
92
|
expect(unmarshal.mock.results[0].value).toEqual(["0", false]);
|
|
@@ -98,19 +100,21 @@ test("array", async () => {
|
|
|
98
100
|
expect(preUnmarshal).toBeCalledWith(array, handle);
|
|
99
101
|
|
|
100
102
|
handle.dispose();
|
|
101
|
-
|
|
103
|
+
ctx.dispose();
|
|
102
104
|
});
|
|
103
105
|
|
|
104
106
|
test("prototype", async () => {
|
|
105
|
-
const
|
|
106
|
-
const unmarshal =
|
|
107
|
-
|
|
107
|
+
const ctx = (await getQuickJS()).newContext();
|
|
108
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
|
|
109
|
+
ctx.typeof(v) === "object" ? { a: () => 1 } : ctx.dump(v),
|
|
108
110
|
false,
|
|
109
111
|
]);
|
|
110
|
-
const preUnmarshal =
|
|
112
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
111
113
|
|
|
112
|
-
const handle =
|
|
113
|
-
|
|
114
|
+
const handle = ctx.unwrapResult(
|
|
115
|
+
ctx.evalCode(`Object.create({ a: () => 1 })`)
|
|
116
|
+
);
|
|
117
|
+
const obj = unmarshalObject(ctx, handle, unmarshal, preUnmarshal) as any;
|
|
114
118
|
if (!obj) throw new Error("obj is undefined");
|
|
115
119
|
expect(Object.getPrototypeOf(obj)).toEqual({ a: expect.any(Function) });
|
|
116
120
|
expect(obj.a()).toBe(1);
|
|
@@ -120,25 +124,25 @@ test("prototype", async () => {
|
|
|
120
124
|
expect(preUnmarshal).toBeCalledWith(obj, handle);
|
|
121
125
|
|
|
122
126
|
handle.dispose();
|
|
123
|
-
|
|
127
|
+
ctx.dispose();
|
|
124
128
|
});
|
|
125
129
|
|
|
126
130
|
test("undefined", async () => {
|
|
127
|
-
const
|
|
128
|
-
const f =
|
|
131
|
+
const ctx = (await getQuickJS()).newContext();
|
|
132
|
+
const f = vi.fn();
|
|
129
133
|
|
|
130
|
-
expect(unmarshalObject(
|
|
131
|
-
expect(unmarshalObject(
|
|
132
|
-
expect(unmarshalObject(
|
|
133
|
-
expect(unmarshalObject(
|
|
134
|
-
expect(unmarshalObject(
|
|
135
|
-
expect(unmarshalObject(
|
|
134
|
+
expect(unmarshalObject(ctx, ctx.undefined, f, f)).toEqual(undefined);
|
|
135
|
+
expect(unmarshalObject(ctx, ctx.true, f, f)).toEqual(undefined);
|
|
136
|
+
expect(unmarshalObject(ctx, ctx.false, f, f)).toEqual(undefined);
|
|
137
|
+
expect(unmarshalObject(ctx, ctx.null, f, f)).toEqual(undefined);
|
|
138
|
+
expect(unmarshalObject(ctx, ctx.newString("hoge"), f, f)).toEqual(undefined);
|
|
139
|
+
expect(unmarshalObject(ctx, ctx.newNumber(-10), f, f)).toEqual(undefined);
|
|
136
140
|
|
|
137
|
-
const func =
|
|
138
|
-
expect(unmarshalObject(
|
|
141
|
+
const func = ctx.newFunction("", () => {});
|
|
142
|
+
expect(unmarshalObject(ctx, func, f, f)).toEqual(undefined);
|
|
139
143
|
|
|
140
144
|
expect(f).toBeCalledTimes(0);
|
|
141
145
|
|
|
142
146
|
func.dispose();
|
|
143
|
-
|
|
147
|
+
ctx.dispose();
|
|
144
148
|
});
|
package/src/unmarshal/object.ts
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import unmarshalProperties from "./properties";
|
|
3
4
|
import { call } from "../vmutil";
|
|
4
5
|
|
|
5
6
|
export default function unmarshalObject(
|
|
6
|
-
|
|
7
|
+
ctx: QuickJSContext,
|
|
7
8
|
handle: QuickJSHandle,
|
|
8
9
|
unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
|
|
9
10
|
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
10
11
|
): object | undefined {
|
|
11
12
|
if (
|
|
12
|
-
|
|
13
|
+
ctx.typeof(handle) !== "object" ||
|
|
13
14
|
// null check
|
|
14
|
-
|
|
15
|
-
.unwrapResult(
|
|
16
|
-
.consume(n =>
|
|
17
|
-
|
|
15
|
+
ctx
|
|
16
|
+
.unwrapResult(ctx.evalCode("o => o === null"))
|
|
17
|
+
.consume((n) =>
|
|
18
|
+
ctx.dump(ctx.unwrapResult(ctx.callFunction(n, ctx.undefined, handle)))
|
|
18
19
|
)
|
|
19
20
|
)
|
|
20
21
|
return;
|
|
21
22
|
|
|
22
|
-
const raw = call(
|
|
23
|
-
|
|
23
|
+
const raw = call(ctx, "Array.isArray", undefined, handle).consume((r) =>
|
|
24
|
+
ctx.dump(r)
|
|
24
25
|
)
|
|
25
26
|
? []
|
|
26
27
|
: {};
|
|
27
28
|
const obj = preUnmarshal(raw, handle) ?? raw;
|
|
28
29
|
|
|
29
30
|
const prototype = call(
|
|
30
|
-
|
|
31
|
+
ctx,
|
|
31
32
|
`o => {
|
|
32
33
|
const p = Object.getPrototypeOf(o);
|
|
33
34
|
return !p || p === Object.prototype || p === Array.prototype ? undefined : p;
|
|
34
35
|
}`,
|
|
35
36
|
undefined,
|
|
36
37
|
handle
|
|
37
|
-
).consume(prototype => {
|
|
38
|
-
if (
|
|
38
|
+
).consume((prototype) => {
|
|
39
|
+
if (ctx.typeof(prototype) === "undefined") return;
|
|
39
40
|
const [proto] = unmarshal(prototype);
|
|
40
41
|
return proto;
|
|
41
42
|
});
|
|
@@ -43,7 +44,7 @@ export default function unmarshalObject(
|
|
|
43
44
|
Object.setPrototypeOf(obj, prototype);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
unmarshalProperties(
|
|
47
|
+
unmarshalProperties(ctx, handle, raw, unmarshal);
|
|
47
48
|
|
|
48
49
|
return obj;
|
|
49
50
|
}
|
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
|
|
2
4
|
import unmarshalPrimitive from "./primitive";
|
|
3
5
|
|
|
4
6
|
test("works", async () => {
|
|
5
|
-
const
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
6
8
|
|
|
7
|
-
expect(unmarshalPrimitive(
|
|
8
|
-
expect(unmarshalPrimitive(
|
|
9
|
-
expect(unmarshalPrimitive(
|
|
10
|
-
expect(unmarshalPrimitive(
|
|
11
|
-
expect(unmarshalPrimitive(
|
|
12
|
-
|
|
9
|
+
expect(unmarshalPrimitive(ctx, ctx.undefined)).toEqual([undefined, true]);
|
|
10
|
+
expect(unmarshalPrimitive(ctx, ctx.true)).toEqual([true, true]);
|
|
11
|
+
expect(unmarshalPrimitive(ctx, ctx.false)).toEqual([false, true]);
|
|
12
|
+
expect(unmarshalPrimitive(ctx, ctx.null)).toEqual([null, true]);
|
|
13
|
+
expect(unmarshalPrimitive(ctx, ctx.newString("hoge"))).toEqual([
|
|
14
|
+
"hoge",
|
|
15
|
+
true,
|
|
16
|
+
]);
|
|
17
|
+
expect(unmarshalPrimitive(ctx, ctx.newNumber(-10))).toEqual([-10, true]);
|
|
13
18
|
// expect(
|
|
14
|
-
// unmarshalPrimitive(
|
|
19
|
+
// unmarshalPrimitive(ctx, ctx.unwrapResult(vm.evalCode(`BigInt(1)`)))
|
|
15
20
|
// ).toEqual([BigInt(1), true]);
|
|
16
21
|
|
|
17
|
-
const obj =
|
|
18
|
-
expect(unmarshalPrimitive(
|
|
19
|
-
const array =
|
|
20
|
-
expect(unmarshalPrimitive(
|
|
21
|
-
const func =
|
|
22
|
-
expect(unmarshalPrimitive(
|
|
22
|
+
const obj = ctx.newObject();
|
|
23
|
+
expect(unmarshalPrimitive(ctx, obj)).toEqual([undefined, false]);
|
|
24
|
+
const array = ctx.newArray();
|
|
25
|
+
expect(unmarshalPrimitive(ctx, array)).toEqual([undefined, false]);
|
|
26
|
+
const func = ctx.newFunction("", () => {});
|
|
27
|
+
expect(unmarshalPrimitive(ctx, func)).toEqual([undefined, false]);
|
|
23
28
|
|
|
24
29
|
obj.dispose();
|
|
25
30
|
array.dispose();
|
|
26
31
|
func.dispose();
|
|
27
|
-
|
|
32
|
+
ctx.dispose();
|
|
28
33
|
});
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
2
|
|
|
3
3
|
export default function unmarshalPrimitive(
|
|
4
|
-
|
|
4
|
+
ctx: QuickJSContext,
|
|
5
5
|
handle: QuickJSHandle
|
|
6
6
|
): [any, boolean] {
|
|
7
|
-
const ty =
|
|
7
|
+
const ty = ctx.typeof(handle);
|
|
8
8
|
if (
|
|
9
9
|
ty === "undefined" ||
|
|
10
10
|
ty === "number" ||
|
|
11
11
|
ty === "string" ||
|
|
12
12
|
ty === "boolean"
|
|
13
13
|
) {
|
|
14
|
-
return [
|
|
14
|
+
return [ctx.dump(handle), true];
|
|
15
15
|
} else if (ty === "object") {
|
|
16
|
-
const isNull =
|
|
17
|
-
.unwrapResult(
|
|
18
|
-
.consume(n =>
|
|
19
|
-
|
|
16
|
+
const isNull = ctx
|
|
17
|
+
.unwrapResult(ctx.evalCode("a => a === null"))
|
|
18
|
+
.consume((n) =>
|
|
19
|
+
ctx.dump(ctx.unwrapResult(ctx.callFunction(n, ctx.undefined, handle)))
|
|
20
20
|
);
|
|
21
21
|
if (isNull) {
|
|
22
22
|
return [null, true];
|
|
@@ -25,10 +25,10 @@ export default function unmarshalPrimitive(
|
|
|
25
25
|
|
|
26
26
|
// BigInt is not supported by quickjs-emscripten
|
|
27
27
|
// if (ty === "bigint") {
|
|
28
|
-
// const str =
|
|
28
|
+
// const str = ctx
|
|
29
29
|
// .getProp(handle, "toString")
|
|
30
30
|
// .consume(toString => vm.unwrapResult(vm.callFunction(toString, handle)))
|
|
31
|
-
// .consume(str =>
|
|
31
|
+
// .consume(str => ctx.getString(str));
|
|
32
32
|
// const bi = BigInt(str);
|
|
33
33
|
// return [bi, true];
|
|
34
34
|
// }
|
|
@@ -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 ctx = (await getQuickJS()).newContext();
|
|
8
|
+
const disposables: Disposable[] = [];
|
|
9
|
+
const marshal = vi.fn((v): [QuickJSHandle, boolean] => {
|
|
10
|
+
const f = ctx.newFunction(v.name, (h) => {
|
|
11
|
+
v(ctx.dump(h));
|
|
12
|
+
});
|
|
13
|
+
disposables.push(f);
|
|
14
|
+
return [f, false];
|
|
15
|
+
});
|
|
16
|
+
const preUnmarshal = vi.fn((a) => a);
|
|
17
|
+
|
|
18
|
+
const deferred = ctx.newPromise();
|
|
19
|
+
disposables.push(deferred);
|
|
20
|
+
const promise = unmarshalPromise(ctx, deferred.handle, marshal, preUnmarshal);
|
|
21
|
+
|
|
22
|
+
expect(marshal).toBeCalledTimes(2);
|
|
23
|
+
expect(preUnmarshal).toBeCalledTimes(1);
|
|
24
|
+
expect(ctx.runtime.hasPendingJob()).toBe(false);
|
|
25
|
+
|
|
26
|
+
if (reject) {
|
|
27
|
+
deferred.reject(ctx.newString("hoge"));
|
|
28
|
+
} else {
|
|
29
|
+
deferred.resolve(ctx.newString("hoge"));
|
|
30
|
+
}
|
|
31
|
+
expect(ctx.runtime.hasPendingJob()).toBe(true);
|
|
32
|
+
expect(ctx.unwrapResult(ctx.runtime.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
|
+
ctx.dispose();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
test("resolve", testPromise(false));
|
|
44
|
+
test("reject", testPromise(true));
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { QuickJSContext, 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
|
+
ctx: QuickJSContext,
|
|
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(ctx, 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
|
+
ctx,
|
|
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(ctx: QuickJSContext, handle: QuickJSHandle): boolean {
|
|
33
|
+
if (!handle.owner) return false;
|
|
34
|
+
return ctx.unwrapResult(ctx.evalCode("Promise")).consume((promise) => {
|
|
35
|
+
if (!handle.owner) return false;
|
|
36
|
+
return instanceOf(ctx, handle, promise);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -1,17 +1,19 @@
|
|
|
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
|
-
const
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
6
8
|
const disposables: QuickJSHandle[] = [];
|
|
7
|
-
const unmarshal =
|
|
9
|
+
const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
|
|
8
10
|
disposables.push(v);
|
|
9
|
-
return [
|
|
11
|
+
return [ctx.typeof(v) === "function" ? () => {} : ctx.dump(v), false];
|
|
10
12
|
});
|
|
11
13
|
const obj = {};
|
|
12
14
|
|
|
13
|
-
const handle =
|
|
14
|
-
|
|
15
|
+
const handle = ctx.unwrapResult(
|
|
16
|
+
ctx.evalCode(`{
|
|
15
17
|
const obj = {};
|
|
16
18
|
Object.defineProperties(obj, {
|
|
17
19
|
a: { value: 1, writable: true, configurable: true, enumerable: true },
|
|
@@ -22,7 +24,7 @@ test("works", async () => {
|
|
|
22
24
|
}`)
|
|
23
25
|
);
|
|
24
26
|
|
|
25
|
-
unmarshalProperties(
|
|
27
|
+
unmarshalProperties(ctx, handle, obj, unmarshal);
|
|
26
28
|
|
|
27
29
|
expect(obj).toEqual({
|
|
28
30
|
a: 1,
|
|
@@ -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
|
+
ctx.dispose();
|
|
51
53
|
});
|
|
@@ -1,59 +1,64 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
|
+
|
|
2
3
|
import { call } from "../vmutil";
|
|
3
4
|
|
|
4
5
|
export default function unmarshalProperties(
|
|
5
|
-
|
|
6
|
+
ctx: QuickJSContext,
|
|
6
7
|
handle: QuickJSHandle,
|
|
7
8
|
target: object | Function,
|
|
8
9
|
unmarshal: (handle: QuickJSHandle) => [unknown, boolean]
|
|
9
10
|
) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
ctx
|
|
12
|
+
.newFunction("", (key, value) => {
|
|
13
|
+
const [keyName] = unmarshal(key);
|
|
14
|
+
if (
|
|
15
|
+
typeof keyName !== "string" &&
|
|
16
|
+
typeof keyName !== "number" &&
|
|
17
|
+
typeof keyName !== "symbol"
|
|
18
|
+
)
|
|
19
|
+
return;
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
const desc = (
|
|
22
|
+
[
|
|
23
|
+
["value", true],
|
|
24
|
+
["get", true],
|
|
25
|
+
["set", true],
|
|
26
|
+
["configurable", false],
|
|
27
|
+
["enumerable", false],
|
|
28
|
+
["writable", false],
|
|
29
|
+
] as const
|
|
30
|
+
).reduce<PropertyDescriptor>((desc, [key, unmarshable]) => {
|
|
31
|
+
const h = ctx.getProp(value, key);
|
|
32
|
+
const ty = ctx.typeof(h);
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
if (ty === "undefined") return desc;
|
|
35
|
+
if (!unmarshable && ty === "boolean") {
|
|
36
|
+
desc[key] = ctx.dump(ctx.getProp(value, key));
|
|
37
|
+
return desc;
|
|
38
|
+
}
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
const [v, alreadyExists] = unmarshal(h);
|
|
41
|
+
if (alreadyExists) {
|
|
42
|
+
h.dispose();
|
|
43
|
+
}
|
|
44
|
+
desc[key] = v;
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
return desc;
|
|
47
|
+
}, {});
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
Object.defineProperty(target, keyName, desc);
|
|
50
|
+
})
|
|
51
|
+
.consume((fn) => {
|
|
52
|
+
call(
|
|
53
|
+
ctx,
|
|
54
|
+
`(o, fn) => {
|
|
50
55
|
const descs = Object.getOwnPropertyDescriptors(o);
|
|
51
56
|
Object.entries(descs).forEach(([k, v]) => fn(k, v));
|
|
52
57
|
Object.getOwnPropertySymbols(descs).forEach(k => fn(k, descs[k]));
|
|
53
58
|
}`,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
undefined,
|
|
60
|
+
handle,
|
|
61
|
+
fn
|
|
62
|
+
).dispose();
|
|
63
|
+
});
|
|
59
64
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
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
|
-
const
|
|
6
|
-
const pre =
|
|
7
|
-
const obj =
|
|
8
|
-
const handle =
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
|
+
const pre = vi.fn();
|
|
9
|
+
const obj = ctx.newObject();
|
|
10
|
+
const handle = ctx.unwrapResult(ctx.evalCode(`Symbol("foobar")`));
|
|
9
11
|
|
|
10
|
-
expect(unmarshalSymbol(
|
|
12
|
+
expect(unmarshalSymbol(ctx, obj, pre)).toBe(undefined);
|
|
11
13
|
expect(pre).toBeCalledTimes(0);
|
|
12
14
|
|
|
13
|
-
const sym = unmarshalSymbol(
|
|
15
|
+
const sym = unmarshalSymbol(ctx, handle, pre);
|
|
14
16
|
expect(typeof sym).toBe("symbol");
|
|
15
17
|
expect((sym as any).description).toBe("foobar");
|
|
16
18
|
expect(pre).toReturnTimes(1);
|
|
@@ -19,5 +21,5 @@ test("works", async () => {
|
|
|
19
21
|
|
|
20
22
|
handle.dispose();
|
|
21
23
|
obj.dispose();
|
|
22
|
-
|
|
24
|
+
ctx.dispose();
|
|
23
25
|
});
|
package/src/unmarshal/symbol.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
|
|
2
2
|
|
|
3
3
|
export default function unmarshalSymbol(
|
|
4
|
-
|
|
4
|
+
ctx: QuickJSContext,
|
|
5
5
|
handle: QuickJSHandle,
|
|
6
6
|
preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
|
|
7
7
|
): symbol | undefined {
|
|
8
|
-
if (
|
|
9
|
-
const desc =
|
|
8
|
+
if (ctx.typeof(handle) !== "symbol") return;
|
|
9
|
+
const desc = ctx.getString(ctx.getProp(handle, "description"));
|
|
10
10
|
const sym = Symbol(desc);
|
|
11
11
|
return preUnmarshal(sym, handle) ?? sym;
|
|
12
12
|
}
|
package/src/util.test.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expect, test, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
isES2015Class,
|
|
5
|
+
isObject,
|
|
6
|
+
walkObject,
|
|
7
|
+
complexity,
|
|
8
|
+
newDeferred,
|
|
9
|
+
} from "./util";
|
|
2
10
|
|
|
3
11
|
test("isES2015Class", () => {
|
|
4
12
|
expect(isES2015Class(class {})).toBe(true);
|
|
5
13
|
expect(isES2015Class(class A {})).toBe(true);
|
|
6
|
-
expect(isES2015Class(function() {})).toBe(false);
|
|
14
|
+
expect(isES2015Class(function () {})).toBe(false);
|
|
7
15
|
expect(isES2015Class(function A() {})).toBe(false);
|
|
8
16
|
expect(isES2015Class(() => {})).toBe(false);
|
|
9
17
|
expect(isES2015Class({})).toBe(false);
|
|
@@ -14,7 +22,7 @@ test("isES2015Class", () => {
|
|
|
14
22
|
test("isObject", () => {
|
|
15
23
|
expect(isObject({})).toBe(true);
|
|
16
24
|
expect(isObject(Object.create(null))).toBe(true);
|
|
17
|
-
expect(isObject(function() {})).toBe(true);
|
|
25
|
+
expect(isObject(function () {})).toBe(true);
|
|
18
26
|
expect(isObject(function A() {})).toBe(true);
|
|
19
27
|
expect(isObject(() => {})).toBe(true);
|
|
20
28
|
expect(isObject(class {})).toBe(true);
|
|
@@ -25,7 +33,7 @@ test("isObject", () => {
|
|
|
25
33
|
});
|
|
26
34
|
|
|
27
35
|
test("walkObject", () => {
|
|
28
|
-
const cb =
|
|
36
|
+
const cb = vi.fn();
|
|
29
37
|
const obj = { a: { b: 1, c: () => {} } };
|
|
30
38
|
const set = new Set<any>([obj, obj.a, obj.a.c]);
|
|
31
39
|
expect(walkObject(obj, cb)).toEqual(set);
|
|
@@ -47,8 +55,18 @@ test("complexity", () => {
|
|
|
47
55
|
expect(complexity({ a: 1 })).toBe(1);
|
|
48
56
|
expect(complexity(() => {})).toBe(1);
|
|
49
57
|
expect(complexity([{}])).toBe(2);
|
|
50
|
-
expect(complexity(function() {})).toBe(2);
|
|
58
|
+
expect(complexity(function () {})).toBe(2);
|
|
51
59
|
expect(complexity(class {})).toBe(2);
|
|
52
60
|
expect(complexity({ a: {} })).toBe(2);
|
|
53
61
|
expect(complexity({ a: {} }, 1)).toBe(1);
|
|
54
62
|
});
|
|
63
|
+
|
|
64
|
+
test("newDeferred", () => {
|
|
65
|
+
const deferred = newDeferred();
|
|
66
|
+
deferred.resolve("foo");
|
|
67
|
+
expect(deferred.promise).resolves.toBe("foo");
|
|
68
|
+
|
|
69
|
+
const deferred2 = newDeferred();
|
|
70
|
+
deferred2.reject("bar");
|
|
71
|
+
expect(deferred2.promise).rejects.toBe("bar");
|
|
72
|
+
});
|