quickjs-emscripten-sync 1.2.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.
Files changed (76) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +71 -44
  3. package/dist/index.d.ts +116 -23
  4. package/dist/quickjs-emscripten-sync.mjs +842 -0
  5. package/dist/quickjs-emscripten-sync.umd.js +64 -2
  6. package/package.json +22 -53
  7. package/src/default.ts +2 -2
  8. package/src/index.test.ts +223 -59
  9. package/src/index.ts +72 -66
  10. package/src/marshal/custom.test.ts +50 -0
  11. package/src/marshal/custom.ts +36 -0
  12. package/src/marshal/function.test.ts +64 -75
  13. package/src/marshal/function.ts +15 -18
  14. package/src/marshal/index.test.ts +122 -77
  15. package/src/marshal/index.ts +19 -15
  16. package/src/marshal/json.test.ts +37 -41
  17. package/src/marshal/json.ts +5 -7
  18. package/src/marshal/object.test.ts +59 -84
  19. package/src/marshal/object.ts +8 -15
  20. package/src/marshal/primitive.test.ts +18 -21
  21. package/src/marshal/primitive.ts +11 -10
  22. package/src/marshal/promise.test.ts +85 -0
  23. package/src/marshal/promise.ts +19 -0
  24. package/src/marshal/properties.test.ts +24 -27
  25. package/src/marshal/properties.ts +15 -17
  26. package/src/unmarshal/custom.test.ts +50 -0
  27. package/src/unmarshal/custom.ts +31 -0
  28. package/src/unmarshal/function.test.ts +63 -86
  29. package/src/unmarshal/function.ts +13 -22
  30. package/src/unmarshal/index.test.ts +114 -109
  31. package/src/unmarshal/index.ts +15 -14
  32. package/src/unmarshal/object.test.ts +42 -46
  33. package/src/unmarshal/object.ts +16 -20
  34. package/src/unmarshal/primitive.test.ts +17 -15
  35. package/src/unmarshal/primitive.ts +11 -18
  36. package/src/unmarshal/promise.test.ts +44 -0
  37. package/src/unmarshal/promise.ts +31 -0
  38. package/src/unmarshal/properties.test.ts +11 -9
  39. package/src/unmarshal/properties.ts +44 -45
  40. package/src/util.test.ts +14 -2
  41. package/src/util.ts +18 -8
  42. package/src/vmmap.test.ts +88 -82
  43. package/src/vmmap.ts +30 -44
  44. package/src/vmutil.test.ts +100 -75
  45. package/src/vmutil.ts +51 -34
  46. package/src/wrapper.test.ts +129 -167
  47. package/src/wrapper.ts +59 -62
  48. package/dist/default.d.ts +0 -4
  49. package/dist/marshal/function.d.ts +0 -2
  50. package/dist/marshal/index.d.ts +0 -11
  51. package/dist/marshal/json.d.ts +0 -2
  52. package/dist/marshal/object.d.ts +0 -2
  53. package/dist/marshal/primitive.d.ts +0 -2
  54. package/dist/marshal/properties.d.ts +0 -2
  55. package/dist/marshal/symbol.d.ts +0 -2
  56. package/dist/quickjs-emscripten-sync.cjs +0 -2
  57. package/dist/quickjs-emscripten-sync.cjs.map +0 -1
  58. package/dist/quickjs-emscripten-sync.modern.js +0 -2
  59. package/dist/quickjs-emscripten-sync.modern.js.map +0 -1
  60. package/dist/quickjs-emscripten-sync.module.js +0 -2
  61. package/dist/quickjs-emscripten-sync.module.js.map +0 -1
  62. package/dist/quickjs-emscripten-sync.umd.js.map +0 -1
  63. package/dist/unmarshal/function.d.ts +0 -2
  64. package/dist/unmarshal/index.d.ts +0 -9
  65. package/dist/unmarshal/object.d.ts +0 -2
  66. package/dist/unmarshal/primitive.d.ts +0 -2
  67. package/dist/unmarshal/properties.d.ts +0 -2
  68. package/dist/unmarshal/symbol.d.ts +0 -2
  69. package/dist/util.d.ts +0 -7
  70. package/dist/vmmap.d.ts +0 -35
  71. package/dist/vmutil.d.ts +0 -11
  72. package/dist/wrapper.d.ts +0 -11
  73. package/src/marshal/symbol.test.ts +0 -22
  74. package/src/marshal/symbol.ts +0 -20
  75. package/src/unmarshal/symbol.test.ts +0 -23
  76. package/src/unmarshal/symbol.ts +0 -12
@@ -1,70 +1,65 @@
1
1
  import { getQuickJS } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
4
  import { call } from "../vmutil";
5
+
3
6
  import marshalObject from "./object";
4
7
 
5
8
  test("empty object", async () => {
6
- const vm = (await getQuickJS()).createVm();
7
- const prototypeCheck = vm.unwrapResult(
8
- vm.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
9
+ const ctx = (await getQuickJS()).newContext();
10
+ const prototypeCheck = ctx.unwrapResult(
11
+ ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
9
12
  );
10
13
 
11
14
  const obj = {};
12
- const marshal = jest.fn();
13
- const preMarshal = jest.fn((_, a) => a);
15
+ const marshal = vi.fn();
16
+ const preMarshal = vi.fn((_, a) => a);
14
17
 
15
- const handle = marshalObject(vm, obj, marshal, preMarshal);
18
+ const handle = marshalObject(ctx, obj, marshal, preMarshal);
16
19
  if (!handle) throw new Error("handle is undefined");
17
20
 
18
- expect(vm.typeof(handle)).toBe("object");
21
+ expect(ctx.typeof(handle)).toBe("object");
19
22
  expect(marshal).toBeCalledTimes(0);
20
23
  expect(preMarshal).toBeCalledTimes(1);
21
24
  expect(preMarshal.mock.calls[0][0]).toBe(obj);
22
25
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
23
- expect(
24
- vm.dump(
25
- vm.unwrapResult(vm.callFunction(prototypeCheck, vm.undefined, handle))
26
- )
27
- ).toBe(true);
26
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
27
+ true,
28
+ );
28
29
 
29
30
  handle.dispose();
30
31
  prototypeCheck.dispose();
31
- vm.dispose();
32
+ ctx.dispose();
32
33
  });
33
34
 
34
35
  test("normal object", async () => {
35
- const vm = (await getQuickJS()).createVm();
36
- const prototypeCheck = vm.unwrapResult(
37
- vm.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
36
+ const ctx = (await getQuickJS()).newContext();
37
+ const prototypeCheck = ctx.unwrapResult(
38
+ ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
38
39
  );
39
- const entries = vm.unwrapResult(vm.evalCode(`Object.entries`));
40
+ const entries = ctx.unwrapResult(ctx.evalCode(`Object.entries`));
40
41
 
41
42
  const obj = { a: 100, b: "hoge" };
42
- const marshal = jest.fn((v) =>
43
- typeof v === "number"
44
- ? vm.newNumber(v)
45
- : typeof v === "string"
46
- ? vm.newString(v)
47
- : vm.null
43
+ const marshal = vi.fn(v =>
44
+ typeof v === "number" ? ctx.newNumber(v) : typeof v === "string" ? ctx.newString(v) : ctx.null,
48
45
  );
49
- const preMarshal = jest.fn((_, a) => a);
46
+ const preMarshal = vi.fn((_, a) => a);
50
47
 
51
- const handle = marshalObject(vm, obj, marshal, preMarshal);
48
+ const handle = marshalObject(ctx, obj, marshal, preMarshal);
52
49
  if (!handle) throw new Error("handle is undefined");
53
50
 
54
- expect(vm.typeof(handle)).toBe("object");
55
- expect(vm.getNumber(vm.getProp(handle, "a"))).toBe(100);
56
- expect(vm.getString(vm.getProp(handle, "b"))).toBe("hoge");
51
+ expect(ctx.typeof(handle)).toBe("object");
52
+ expect(ctx.getNumber(ctx.getProp(handle, "a"))).toBe(100);
53
+ expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
57
54
  expect(marshal.mock.calls).toEqual([["a"], [100], ["b"], ["hoge"]]);
58
55
  expect(preMarshal).toBeCalledTimes(1);
59
56
  expect(preMarshal.mock.calls[0][0]).toBe(obj);
60
57
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
61
- expect(
62
- vm.dump(
63
- vm.unwrapResult(vm.callFunction(prototypeCheck, vm.undefined, handle))
64
- )
65
- ).toBe(true);
66
- const e = vm.unwrapResult(vm.callFunction(entries, vm.undefined, handle));
67
- expect(vm.dump(e)).toEqual([
58
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
59
+ true,
60
+ );
61
+ const e = ctx.unwrapResult(ctx.callFunction(entries, ctx.undefined, handle));
62
+ expect(ctx.dump(e)).toEqual([
68
63
  ["a", 100],
69
64
  ["b", "hoge"],
70
65
  ]);
@@ -73,89 +68,69 @@ test("normal object", async () => {
73
68
  handle.dispose();
74
69
  prototypeCheck.dispose();
75
70
  entries.dispose();
76
- vm.dispose();
71
+ ctx.dispose();
77
72
  });
78
73
 
79
74
  test("array", async () => {
80
- const vm = (await getQuickJS()).createVm();
81
- const isArray = vm.unwrapResult(vm.evalCode(`Array.isArray`));
75
+ const ctx = (await getQuickJS()).newContext();
76
+ const isArray = ctx.unwrapResult(ctx.evalCode(`Array.isArray`));
82
77
 
83
78
  const array = [1, "aa"];
84
- const marshal = jest.fn((v) =>
85
- typeof v === "number"
86
- ? vm.newNumber(v)
87
- : typeof v === "string"
88
- ? vm.newString(v)
89
- : vm.null
79
+ const marshal = vi.fn(v =>
80
+ typeof v === "number" ? ctx.newNumber(v) : typeof v === "string" ? ctx.newString(v) : ctx.null,
90
81
  );
91
- const preMarshal = jest.fn((_, a) => a);
82
+ const preMarshal = vi.fn((_, a) => a);
92
83
 
93
- const handle = marshalObject(vm, array, marshal, preMarshal);
84
+ const handle = marshalObject(ctx, array, marshal, preMarshal);
94
85
  if (!handle) throw new Error("handle is undefined");
95
86
 
96
- expect(vm.typeof(handle)).toBe("object");
97
- expect(vm.getNumber(vm.getProp(handle, 0))).toBe(1);
98
- expect(vm.getString(vm.getProp(handle, 1))).toBe("aa");
99
- expect(vm.getNumber(vm.getProp(handle, "length"))).toBe(2);
100
- expect(marshal.mock.calls).toEqual([
101
- ["0"],
102
- [1],
103
- ["1"],
104
- ["aa"],
105
- ["length"],
106
- [2],
107
- ]);
87
+ expect(ctx.typeof(handle)).toBe("object");
88
+ expect(ctx.getNumber(ctx.getProp(handle, 0))).toBe(1);
89
+ expect(ctx.getString(ctx.getProp(handle, 1))).toBe("aa");
90
+ expect(ctx.getNumber(ctx.getProp(handle, "length"))).toBe(2);
91
+ expect(marshal.mock.calls).toEqual([["0"], [1], ["1"], ["aa"], ["length"], [2]]);
108
92
  expect(preMarshal).toBeCalledTimes(1);
109
93
  expect(preMarshal.mock.calls[0][0]).toBe(array);
110
94
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
111
- expect(
112
- vm.dump(vm.unwrapResult(vm.callFunction(isArray, vm.undefined, handle)))
113
- ).toBe(true);
95
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))).toBe(true);
114
96
 
115
97
  handle.dispose();
116
98
  isArray.dispose();
117
- vm.dispose();
99
+ ctx.dispose();
118
100
  });
119
101
 
120
102
  test("prototype", async () => {
121
- const vm = (await getQuickJS()).createVm();
103
+ const ctx = (await getQuickJS()).newContext();
122
104
 
123
105
  const proto = { a: 100 };
124
- const protoHandle = vm.newObject();
125
- vm.setProp(protoHandle, "a", vm.newNumber(100));
126
- const preMarshal = jest.fn((_, a) => a);
106
+ const protoHandle = ctx.newObject();
107
+ ctx.setProp(protoHandle, "a", ctx.newNumber(100));
108
+ const preMarshal = vi.fn((_, a) => a);
127
109
 
128
110
  const obj = Object.create(proto);
129
111
  obj.b = "hoge";
130
112
  const handle = marshalObject(
131
- vm,
113
+ ctx,
132
114
  obj,
133
- (v) =>
134
- v === proto
135
- ? protoHandle
136
- : typeof v === "string"
137
- ? vm.newString(v)
138
- : vm.null,
139
- preMarshal
115
+ v => (v === proto ? protoHandle : typeof v === "string" ? ctx.newString(v) : ctx.null),
116
+ preMarshal,
140
117
  );
141
118
  if (!handle) throw new Error("handle is undefined");
142
119
 
143
120
  expect(preMarshal).toBeCalledTimes(1);
144
121
  expect(preMarshal.mock.calls[0][0]).toBe(obj);
145
122
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
146
- expect(vm.typeof(handle)).toBe("object");
147
- expect(vm.getNumber(vm.getProp(handle, "a"))).toBe(100);
148
- expect(vm.getString(vm.getProp(handle, "b"))).toBe("hoge");
149
- const e = call(vm, "Object.entries", undefined, handle);
150
- expect(vm.dump(e)).toEqual([["b", "hoge"]]);
151
- const protoHandle2 = call(vm, "Object.getPrototypeOf", vm.undefined, handle);
152
- expect(
153
- vm.dump(call(vm, `Object.is`, undefined, protoHandle, protoHandle2))
154
- ).toBe(true);
123
+ expect(ctx.typeof(handle)).toBe("object");
124
+ expect(ctx.getNumber(ctx.getProp(handle, "a"))).toBe(100);
125
+ expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
126
+ const e = call(ctx, "Object.entries", undefined, handle);
127
+ expect(ctx.dump(e)).toEqual([["b", "hoge"]]);
128
+ const protoHandle2 = call(ctx, "Object.getPrototypeOf", ctx.undefined, handle);
129
+ expect(ctx.dump(call(ctx, `Object.is`, undefined, protoHandle, protoHandle2))).toBe(true);
155
130
 
156
131
  protoHandle2.dispose();
157
132
  e.dispose();
158
133
  handle.dispose();
159
134
  protoHandle.dispose();
160
- vm.dispose();
135
+ ctx.dispose();
161
136
  });
@@ -1,19 +1,18 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
2
3
  import { call } from "../vmutil";
4
+
3
5
  import marshalProperties from "./properties";
4
6
 
5
7
  export default function marshalObject(
6
- vm: QuickJSVm,
8
+ ctx: QuickJSContext,
7
9
  target: unknown,
8
10
  marshal: (target: unknown) => QuickJSHandle,
9
- preMarshal: (
10
- target: unknown,
11
- handle: QuickJSHandle
12
- ) => QuickJSHandle | undefined
11
+ preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
13
12
  ): QuickJSHandle | undefined {
14
13
  if (typeof target !== "object" || target === null) return;
15
14
 
16
- const raw = Array.isArray(target) ? vm.newArray() : vm.newObject();
15
+ const raw = Array.isArray(target) ? ctx.newArray() : ctx.newObject();
17
16
  const handle = preMarshal(target, raw) ?? raw;
18
17
 
19
18
  // prototype
@@ -23,16 +22,10 @@ export default function marshalObject(
23
22
  ? marshal(prototype)
24
23
  : undefined;
25
24
  if (prototypeHandle) {
26
- call(
27
- vm,
28
- "Object.setPrototypeOf",
29
- undefined,
30
- handle,
31
- prototypeHandle
32
- ).dispose();
25
+ call(ctx, "Object.setPrototypeOf", undefined, handle, prototypeHandle).dispose();
33
26
  }
34
27
 
35
- marshalProperties(vm, target, raw, marshal);
28
+ marshalProperties(ctx, target, raw, marshal);
36
29
 
37
30
  return handle;
38
31
  }
@@ -1,34 +1,31 @@
1
1
  import { getQuickJS } from "quickjs-emscripten";
2
+ import { expect, test } from "vitest";
3
+
2
4
  import { eq } from "../vmutil";
5
+
3
6
  import marshalPrimitive from "./primitive";
4
7
 
5
8
  test("works", async () => {
6
- const vm = (await getQuickJS()).createVm();
9
+ const ctx = (await getQuickJS()).newContext();
7
10
 
8
- expect(marshalPrimitive(vm, undefined)).toBe(vm.undefined);
9
- expect(marshalPrimitive(vm, null)).toBe(vm.null);
10
- expect(marshalPrimitive(vm, false)).toBe(vm.false);
11
- expect(marshalPrimitive(vm, true)).toBe(vm.true);
12
- expect(eq(vm, marshalPrimitive(vm, 1) ?? vm.undefined, vm.newNumber(1))).toBe(
13
- true
14
- );
15
- expect(
16
- eq(vm, marshalPrimitive(vm, -100) ?? vm.undefined, vm.newNumber(-100))
17
- ).toBe(true);
18
- expect(
19
- eq(vm, marshalPrimitive(vm, "hoge") ?? vm.undefined, vm.newString("hoge"))
20
- ).toBe(true);
11
+ expect(marshalPrimitive(ctx, undefined)).toBe(ctx.undefined);
12
+ expect(marshalPrimitive(ctx, null)).toBe(ctx.null);
13
+ expect(marshalPrimitive(ctx, false)).toBe(ctx.false);
14
+ expect(marshalPrimitive(ctx, true)).toBe(ctx.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);
21
18
  // expect(
22
19
  // eq(
23
- // vm,
24
- // marshalPrimitive(vm, BigInt(1)) ?? vm.undefined,
25
- // vm.unwrapResult(vm.evalCode("BigInt(1)"))
20
+ // ctx,
21
+ // marshalPrimitive(ctx, BigInt(1)) ?? ctx.undefined,
22
+ // ctx.unwrapResult(ctx.evalCode("BigInt(1)"))
26
23
  // )
27
24
  // ).toBe(true);
28
25
 
29
- expect(marshalPrimitive(vm, () => {})).toBe(undefined);
30
- expect(marshalPrimitive(vm, [])).toBe(undefined);
31
- expect(marshalPrimitive(vm, {})).toBe(undefined);
26
+ expect(marshalPrimitive(ctx, () => {})).toBe(undefined);
27
+ expect(marshalPrimitive(ctx, [])).toBe(undefined);
28
+ expect(marshalPrimitive(ctx, {})).toBe(undefined);
32
29
 
33
- vm.dispose();
30
+ ctx.dispose();
34
31
  });
@@ -1,29 +1,30 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
2
3
  // import { call } from "../vmutil";
3
4
 
4
5
  export default function marshalPrimitive(
5
- vm: QuickJSVm,
6
- target: unknown
6
+ ctx: QuickJSContext,
7
+ target: unknown,
7
8
  ): QuickJSHandle | undefined {
8
9
  switch (typeof target) {
9
10
  case "undefined":
10
- return vm.undefined;
11
+ return ctx.undefined;
11
12
  case "number":
12
- return vm.newNumber(target);
13
+ return ctx.newNumber(target);
13
14
  case "string":
14
- return vm.newString(target);
15
+ return ctx.newString(target);
15
16
  case "boolean":
16
- return target ? vm.true : vm.false;
17
+ return target ? ctx.true : ctx.false;
17
18
  case "object":
18
- return target === null ? vm.null : undefined;
19
+ return target === null ? ctx.null : undefined;
19
20
 
20
21
  // BigInt is not supported by quickjs-emscripten
21
22
  // case "bigint":
22
23
  // return call(
23
- // vm,
24
+ // ctx,
24
25
  // `s => BigInt(s)`,
25
26
  // undefined,
26
- // vm.newString(target.toString())
27
+ // ctx.newString(target.toString())
27
28
  // );
28
29
  }
29
30
 
@@ -0,0 +1,85 @@
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
+
9
+ import { newDeferred } from "../util";
10
+ import { fn, json } from "../vmutil";
11
+
12
+ import marshalPromise from "./promise";
13
+
14
+ const testPromise = (reject: boolean) => async () => {
15
+ const ctx = (await getQuickJS()).newContext();
16
+
17
+ const disposables: Disposable[] = [];
18
+ const marshal = vi.fn(v => {
19
+ const handle = json(ctx, v);
20
+ disposables.push(handle);
21
+ return handle;
22
+ });
23
+ const preMarshal = vi.fn((_: any, a: QuickJSDeferredPromise): QuickJSHandle => {
24
+ disposables.push(a);
25
+ return a.handle;
26
+ });
27
+
28
+ const mockNotify = vi.fn();
29
+ const notify = ctx.newFunction("notify", (handle1, handle2) => {
30
+ const arg1 = ctx.dump(handle1);
31
+ const arg2 = ctx.dump(handle2);
32
+ mockNotify(arg1, arg2);
33
+ });
34
+ disposables.push(notify);
35
+
36
+ const notifier = fn(
37
+ ctx,
38
+ `(notify, promise) => { promise.then(d => notify("resolved", d), d => notify("rejected", d)); }`,
39
+ );
40
+ disposables.push(notifier);
41
+
42
+ const deferred = newDeferred();
43
+ if (reject) {
44
+ deferred.promise.catch(() => {});
45
+ }
46
+ const handle = marshalPromise(ctx, deferred.promise, marshal, preMarshal);
47
+ if (!handle) throw new Error("handle is undefined");
48
+
49
+ expect(marshal).toBeCalledTimes(0);
50
+ expect(preMarshal).toBeCalledTimes(1);
51
+ expect(preMarshal.mock.calls[0][0]).toBe(deferred.promise);
52
+ expect(preMarshal.mock.calls[0][1].handle).toBe(handle);
53
+
54
+ notifier(undefined, notify, handle);
55
+
56
+ expect(mockNotify).toBeCalledTimes(0);
57
+ expect(deferred.resolve).not.toBeUndefined();
58
+ expect(ctx.runtime.hasPendingJob()).toBe(false);
59
+
60
+ if (reject) {
61
+ deferred.reject("hoge");
62
+ } else {
63
+ deferred.resolve("hoge");
64
+ }
65
+
66
+ expect(ctx.runtime.hasPendingJob()).toBe(false);
67
+ if (reject) {
68
+ await expect(deferred.promise).rejects.toBe("hoge");
69
+ } else {
70
+ await expect(deferred.promise).resolves.toBe("hoge");
71
+ }
72
+ expect(ctx.runtime.hasPendingJob()).toBe(true);
73
+ const executed = ctx.unwrapResult(ctx.runtime.executePendingJobs());
74
+ expect(executed).toBe(1);
75
+ expect(mockNotify).toBeCalledTimes(1);
76
+ expect(mockNotify).toBeCalledWith(reject ? "rejected" : "resolved", "hoge");
77
+ expect(marshal).toBeCalledTimes(1);
78
+ expect(marshal.mock.calls).toEqual([["hoge"]]);
79
+
80
+ disposables.forEach(h => h.dispose());
81
+ ctx.dispose();
82
+ };
83
+
84
+ test("resolve", testPromise(false));
85
+ test("reject", testPromise(true));
@@ -0,0 +1,19 @@
1
+ import type { QuickJSDeferredPromise, QuickJSHandle, QuickJSContext } from "quickjs-emscripten";
2
+
3
+ export default function marshalPromise(
4
+ ctx: QuickJSContext,
5
+ target: unknown,
6
+ marshal: (target: unknown) => QuickJSHandle,
7
+ preMarshal: (target: unknown, handle: QuickJSDeferredPromise) => QuickJSHandle | undefined,
8
+ ) {
9
+ if (!(target instanceof Promise)) return;
10
+
11
+ const promise = ctx.newPromise();
12
+
13
+ target.then(
14
+ d => promise.resolve(marshal(d)),
15
+ d => promise.reject(marshal(d)),
16
+ );
17
+
18
+ return preMarshal(target, promise) ?? promise.handle;
19
+ }
@@ -1,11 +1,14 @@
1
1
  import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
4
  import { json } from "../vmutil";
5
+
3
6
  import marshalProperties from "./properties";
4
7
 
5
8
  test("works", async () => {
6
- const vm = (await getQuickJS()).createVm();
7
- const descTester = vm.unwrapResult(
8
- vm.evalCode(`(obj, expected) => {
9
+ const ctx = (await getQuickJS()).newContext();
10
+ const descTester = ctx.unwrapResult(
11
+ ctx.evalCode(`(obj, expected) => {
9
12
  const descs = Object.getOwnPropertyDescriptors(obj);
10
13
  for (const [k, v] of Object.entries(expected)) {
11
14
  const d = descs[k];
@@ -16,18 +19,18 @@ test("works", async () => {
16
19
  if (typeof v.configurable === "boolean" && d.configurable !== v.configurable) throw new Error(k + " configurable invalid: " + d.configurable);
17
20
  if (typeof v.writable === "boolean" && d.writable !== v.writable) throw new Error(k + " writable invalid: " + d.writable);
18
21
  }
19
- }`)
22
+ }`),
20
23
  );
21
24
 
22
25
  const disposables: QuickJSHandle[] = [];
23
- const marshal = jest.fn((t) => {
24
- if (typeof t !== "function") return json(vm, t);
25
- const fn = vm.newFunction("", () => {});
26
+ const marshal = vi.fn(t => {
27
+ if (typeof t !== "function") return json(ctx, t);
28
+ const fn = ctx.newFunction("", () => {});
26
29
  disposables.push(fn);
27
30
  return fn;
28
31
  });
29
32
 
30
- const handle = vm.newObject();
33
+ const handle = ctx.newObject();
31
34
  const obj = {};
32
35
  const bar = () => {};
33
36
  const fooGet = () => {};
@@ -47,39 +50,33 @@ test("works", async () => {
47
50
  },
48
51
  });
49
52
 
50
- marshalProperties(vm, obj, handle, marshal);
51
- expect(marshal.mock.calls).toEqual([
52
- ["bar"],
53
- [bar],
54
- ["foo"],
55
- [fooGet],
56
- [fooSet],
57
- ]);
53
+ marshalProperties(ctx, obj, handle, marshal);
54
+ expect(marshal.mock.calls).toEqual([["bar"], [bar], ["foo"], [fooGet], [fooSet]]);
58
55
 
59
- const expected = vm.unwrapResult(
60
- vm.evalCode(`({
56
+ const expected = ctx.unwrapResult(
57
+ ctx.evalCode(`({
61
58
  bar: { valueType: "function", getType: "undefined", setType: "undefined", enumerable: true, configurable: true, writable: true },
62
59
  foo: { valueType: "undefined", getType: "function", setType: "function", enumerable: false, configurable: true }
63
- })`)
60
+ })`),
64
61
  );
65
- vm.unwrapResult(vm.callFunction(descTester, vm.undefined, handle, expected));
62
+ ctx.unwrapResult(ctx.callFunction(descTester, ctx.undefined, handle, expected));
66
63
 
67
64
  expected.dispose();
68
- disposables.forEach((d) => d.dispose());
65
+ disposables.forEach(d => d.dispose());
69
66
  handle.dispose();
70
67
  descTester.dispose();
71
- vm.dispose();
68
+ ctx.dispose();
72
69
  });
73
70
 
74
71
  test("empty", async () => {
75
- const vm = (await getQuickJS()).createVm();
76
- const marshal = jest.fn();
77
- const handle = vm.newObject();
72
+ const ctx = (await getQuickJS()).newContext();
73
+ const marshal = vi.fn();
74
+ const handle = ctx.newObject();
78
75
  const obj = {};
79
76
 
80
- marshalProperties(vm, obj, handle, marshal);
77
+ marshalProperties(ctx, obj, handle, marshal);
81
78
  expect(marshal).toHaveBeenCalledTimes(0);
82
79
 
83
80
  handle.dispose();
84
- vm.dispose();
81
+ ctx.dispose();
85
82
  });
@@ -1,23 +1,21 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
2
3
  import { call } from "../vmutil";
3
4
 
4
5
  export default function marshalProperties(
5
- vm: QuickJSVm,
6
+ ctx: QuickJSContext,
6
7
  target: object | Function,
7
8
  handle: QuickJSHandle,
8
- marshal: (target: unknown) => QuickJSHandle
9
+ marshal: (target: unknown) => QuickJSHandle,
9
10
  ): void {
10
- const descs = vm.newObject();
11
+ const descs = ctx.newObject();
11
12
  const cb = (key: string | number | symbol, desc: PropertyDescriptor) => {
12
13
  const keyHandle = marshal(key);
13
- const valueHandle =
14
- typeof desc.value === "undefined" ? undefined : marshal(desc.value);
15
- const getHandle =
16
- typeof desc.get === "undefined" ? undefined : marshal(desc.get);
17
- const setHandle =
18
- typeof desc.set === "undefined" ? undefined : marshal(desc.set);
14
+ const valueHandle = typeof desc.value === "undefined" ? undefined : marshal(desc.value);
15
+ const getHandle = typeof desc.get === "undefined" ? undefined : marshal(desc.get);
16
+ const setHandle = typeof desc.set === "undefined" ? undefined : marshal(desc.set);
19
17
 
20
- vm.newObject().consume((descObj) => {
18
+ ctx.newObject().consume(descObj => {
21
19
  Object.entries(desc).forEach(([k, v]) => {
22
20
  const v2 =
23
21
  k === "value"
@@ -27,21 +25,21 @@ export default function marshalProperties(
27
25
  : k === "set"
28
26
  ? setHandle
29
27
  : v
30
- ? vm.true
31
- : vm.false;
28
+ ? ctx.true
29
+ : ctx.false;
32
30
  if (v2) {
33
- vm.setProp(descObj, k, v2);
31
+ ctx.setProp(descObj, k, v2);
34
32
  }
35
33
  });
36
- vm.setProp(descs, keyHandle, descObj);
34
+ ctx.setProp(descs, keyHandle, descObj);
37
35
  });
38
36
  };
39
37
 
40
38
  const desc = Object.getOwnPropertyDescriptors(target);
41
39
  Object.entries(desc).forEach(([k, v]) => cb(k, v));
42
- Object.getOwnPropertySymbols(desc).forEach((k) => cb(k, (desc as any)[k]));
40
+ Object.getOwnPropertySymbols(desc).forEach(k => cb(k, (desc as any)[k]));
43
41
 
44
- call(vm, `Object.defineProperties`, undefined, handle, descs).dispose();
42
+ call(ctx, `Object.defineProperties`, undefined, handle, descs).dispose();
45
43
 
46
44
  descs.dispose();
47
45
  }
@@ -0,0 +1,50 @@
1
+ import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
4
+ import unmarshalCustom, { defaultCustom } from "./custom";
5
+
6
+ test("symbol", async () => {
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")`));
11
+
12
+ const unmarshal = (h: QuickJSHandle): any => unmarshalCustom(ctx, h, pre, defaultCustom);
13
+
14
+ expect(unmarshal(obj)).toBe(undefined);
15
+ expect(pre).toBeCalledTimes(0);
16
+
17
+ const sym = unmarshal(handle);
18
+ expect(typeof sym).toBe("symbol");
19
+ expect((sym as any).description).toBe("foobar");
20
+ expect(pre).toReturnTimes(1);
21
+ expect(pre.mock.calls[0][0]).toBe(sym);
22
+ expect(pre.mock.calls[0][1] === handle).toBe(true);
23
+
24
+ handle.dispose();
25
+ obj.dispose();
26
+ ctx.dispose();
27
+ });
28
+
29
+ test("date", async () => {
30
+ const ctx = (await getQuickJS()).newContext();
31
+ const pre = vi.fn();
32
+ const obj = ctx.newObject();
33
+ const handle = ctx.unwrapResult(ctx.evalCode(`new Date(2022, 7, 26)`));
34
+
35
+ const unmarshal = (h: QuickJSHandle): any => unmarshalCustom(ctx, h, pre, defaultCustom);
36
+
37
+ expect(unmarshal(obj)).toBe(undefined);
38
+ expect(pre).toBeCalledTimes(0);
39
+
40
+ const date = unmarshal(handle);
41
+ expect(date).toBeInstanceOf(Date);
42
+ expect(date.getTime()).toBe(new Date(2022, 7, 26).getTime());
43
+ expect(pre).toReturnTimes(1);
44
+ expect(pre.mock.calls[0][0]).toBe(date);
45
+ expect(pre.mock.calls[0][1] === handle).toBe(true);
46
+
47
+ handle.dispose();
48
+ obj.dispose();
49
+ ctx.dispose();
50
+ });