quickjs-emscripten-sync 1.2.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.
Files changed (59) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +13 -9
  3. package/dist/index.d.ts +106 -20
  4. package/dist/quickjs-emscripten-sync.es.js +951 -0
  5. package/dist/quickjs-emscripten-sync.umd.js +64 -2
  6. package/package.json +24 -46
  7. package/src/index.test.ts +70 -0
  8. package/src/index.ts +9 -4
  9. package/src/marshal/function.test.ts +8 -7
  10. package/src/marshal/index.test.ts +46 -5
  11. package/src/marshal/index.ts +9 -3
  12. package/src/marshal/json.test.ts +5 -3
  13. package/src/marshal/object.test.ts +9 -7
  14. package/src/marshal/primitive.test.ts +2 -0
  15. package/src/marshal/promise.test.ts +86 -0
  16. package/src/marshal/promise.ts +26 -0
  17. package/src/marshal/properties.test.ts +4 -2
  18. package/src/marshal/symbol.test.ts +3 -1
  19. package/src/unmarshal/function.test.ts +15 -16
  20. package/src/unmarshal/index.test.ts +81 -84
  21. package/src/unmarshal/index.ts +4 -2
  22. package/src/unmarshal/object.test.ts +11 -9
  23. package/src/unmarshal/primitive.test.ts +2 -0
  24. package/src/unmarshal/promise.test.ts +44 -0
  25. package/src/unmarshal/promise.ts +40 -0
  26. package/src/unmarshal/properties.test.ts +3 -1
  27. package/src/unmarshal/symbol.test.ts +3 -1
  28. package/src/util.test.ts +19 -2
  29. package/src/util.ts +15 -0
  30. package/src/vmmap.test.ts +22 -0
  31. package/src/vmmap.ts +4 -0
  32. package/src/vmutil.test.ts +44 -3
  33. package/src/vmutil.ts +47 -7
  34. package/src/wrapper.test.ts +24 -22
  35. package/dist/default.d.ts +0 -4
  36. package/dist/marshal/function.d.ts +0 -2
  37. package/dist/marshal/index.d.ts +0 -11
  38. package/dist/marshal/json.d.ts +0 -2
  39. package/dist/marshal/object.d.ts +0 -2
  40. package/dist/marshal/primitive.d.ts +0 -2
  41. package/dist/marshal/properties.d.ts +0 -2
  42. package/dist/marshal/symbol.d.ts +0 -2
  43. package/dist/quickjs-emscripten-sync.cjs +0 -2
  44. package/dist/quickjs-emscripten-sync.cjs.map +0 -1
  45. package/dist/quickjs-emscripten-sync.modern.js +0 -2
  46. package/dist/quickjs-emscripten-sync.modern.js.map +0 -1
  47. package/dist/quickjs-emscripten-sync.module.js +0 -2
  48. package/dist/quickjs-emscripten-sync.module.js.map +0 -1
  49. package/dist/quickjs-emscripten-sync.umd.js.map +0 -1
  50. package/dist/unmarshal/function.d.ts +0 -2
  51. package/dist/unmarshal/index.d.ts +0 -9
  52. package/dist/unmarshal/object.d.ts +0 -2
  53. package/dist/unmarshal/primitive.d.ts +0 -2
  54. package/dist/unmarshal/properties.d.ts +0 -2
  55. package/dist/unmarshal/symbol.d.ts +0 -2
  56. package/dist/util.d.ts +0 -7
  57. package/dist/vmmap.d.ts +0 -35
  58. package/dist/vmutil.d.ts +0 -11
  59. package/dist/wrapper.d.ts +0 -11
@@ -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,4 +1,6 @@
1
1
  import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
4
  import { json } from "../vmutil";
3
5
  import marshalProperties from "./properties";
4
6
 
@@ -20,7 +22,7 @@ test("works", async () => {
20
22
  );
21
23
 
22
24
  const disposables: QuickJSHandle[] = [];
23
- const marshal = jest.fn((t) => {
25
+ const marshal = vi.fn((t) => {
24
26
  if (typeof t !== "function") return json(vm, t);
25
27
  const fn = vm.newFunction("", () => {});
26
28
  disposables.push(fn);
@@ -73,7 +75,7 @@ test("works", async () => {
73
75
 
74
76
  test("empty", async () => {
75
77
  const vm = (await getQuickJS()).createVm();
76
- const marshal = jest.fn();
78
+ const marshal = vi.fn();
77
79
  const handle = vm.newObject();
78
80
  const obj = {};
79
81
 
@@ -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 = jest.fn();
8
+ const pre = vi.fn();
7
9
  const sym = Symbol("foobar");
8
10
 
9
11
  expect(marshalSymbol(vm, {}, pre)).toBe(undefined);
@@ -1,18 +1,17 @@
1
1
  import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
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 = jest.fn((v): [QuickJSHandle, boolean] => [
8
- json(vm, v),
9
- false,
10
- ]);
11
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => [
9
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [json(vm, v), false]);
10
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
12
11
  vm.dump(v),
13
12
  false,
14
13
  ]);
15
- const preUnmarshal = jest.fn((a) => a);
14
+ const preUnmarshal = vi.fn((a) => a);
16
15
 
17
16
  const handle = vm.unwrapResult(vm.evalCode(`(a, b) => a + b`));
18
17
  const func = unmarshalFunction(vm, handle, marshal, unmarshal, preUnmarshal);
@@ -42,17 +41,17 @@ test("function", async () => {
42
41
  const vm = (await getQuickJS()).createVm();
43
42
  const that = { a: 1 };
44
43
  const thatHandle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
45
- const marshal = jest.fn((v): [QuickJSHandle, boolean] => [
44
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
46
45
  v === that ? thatHandle : json(vm, v),
47
46
  false,
48
47
  ]);
49
48
  const disposables: QuickJSHandle[] = [];
50
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
49
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
51
50
  const ty = vm.typeof(v);
52
51
  if (ty === "object" || ty === "function") disposables.push(v);
53
52
  return [vm.dump(v), false];
54
53
  });
55
- const preUnmarshal = jest.fn((a) => a);
54
+ const preUnmarshal = vi.fn((a) => a);
56
55
 
57
56
  const handle = vm.unwrapResult(
58
57
  vm.evalCode(`(function (a) { return this.a + a; })`)
@@ -85,16 +84,16 @@ test("function", async () => {
85
84
  test("constructor", async () => {
86
85
  const vm = (await getQuickJS()).createVm();
87
86
  const disposables: QuickJSHandle[] = [];
88
- const marshal = jest.fn((v): [QuickJSHandle, boolean] => [
87
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
89
88
  typeof v === "object" ? vm.undefined : json(vm, v),
90
89
  false,
91
90
  ]);
92
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
91
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
93
92
  const ty = vm.typeof(v);
94
93
  if (ty === "object" || ty === "function") disposables.push(v);
95
94
  return [vm.dump(v), false];
96
95
  });
97
- const preUnmarshal = jest.fn((a) => a);
96
+ const preUnmarshal = vi.fn((a) => a);
98
97
 
99
98
  const handle = vm.unwrapResult(
100
99
  vm.evalCode(`(function (b) { this.a = b + 2; })`)
@@ -133,17 +132,17 @@ test("constructor", async () => {
133
132
 
134
133
  test("class", async () => {
135
134
  const vm = (await getQuickJS()).createVm();
136
- const marshal = jest.fn((v): [QuickJSHandle, boolean] => [
135
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
137
136
  typeof v === "object" ? vm.undefined : json(vm, v),
138
137
  false,
139
138
  ]);
140
139
  const disposables: QuickJSHandle[] = [];
141
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
140
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
142
141
  const ty = vm.typeof(v);
143
142
  if (ty === "object" || ty === "function") disposables.push(v);
144
143
  return [vm.dump(v), false];
145
144
  });
146
- const preUnmarshal = jest.fn((a) => a);
145
+ const preUnmarshal = vi.fn((a) => a);
147
146
 
148
147
  const handle = vm.unwrapResult(
149
148
  vm.evalCode(`(class A { constructor(a) { this.a = a + 1; } })`)
@@ -182,7 +181,7 @@ test("class", async () => {
182
181
 
183
182
  test("undefined", async () => {
184
183
  const vm = (await getQuickJS()).createVm();
185
- const f = jest.fn();
184
+ const f = vi.fn();
186
185
 
187
186
  expect(unmarshalFunction(vm, vm.undefined, f, f, f)).toEqual(undefined);
188
187
  expect(unmarshalFunction(vm, vm.true, f, f, f)).toEqual(undefined);
@@ -1,19 +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 = (await getQuickJS()).createVm();
7
- const marshal = jest.fn((): [QuickJSHandle, boolean] => [
8
- vm.undefined,
9
- false,
10
- ]);
11
- const map = new VMMap(vm);
12
- const find = jest.fn((h) => map.getByHandle(h));
13
- const pre = jest.fn((t: any, h: QuickJSHandle) => {
14
- map.set(t, h);
15
- return t;
16
- });
9
+ const { vm, unmarshal, marshal, map, dispose } = await setup();
17
10
 
18
11
  const handle = vm.unwrapResult(
19
12
  vm.evalCode(`({
@@ -24,7 +17,7 @@ test("primitive, array, object", async () => {
24
17
  bbb: () => "bar"
25
18
  })`)
26
19
  );
27
- const target = unmarshal(handle, { vm, pre, find, marshal });
20
+ const target = unmarshal(handle);
28
21
 
29
22
  expect(target).toEqual({
30
23
  hoge: "foo",
@@ -53,18 +46,11 @@ test("primitive, array, object", async () => {
53
46
  expect(marshal).toBeCalledTimes(1);
54
47
  expect(marshal).toBeCalledWith(target); // thisArg of target.bbb()
55
48
 
56
- handle.dispose();
57
- map.dispose();
58
- vm.dispose();
49
+ dispose();
59
50
  });
60
51
 
61
52
  test("object with symbol key", async () => {
62
- const vm = (await getQuickJS()).createVm();
63
- const map = new VMMap(vm);
64
- const pre = (t: any, h: QuickJSHandle) => {
65
- map.set(t, h);
66
- return t;
67
- };
53
+ const { vm, unmarshal, dispose } = await setup();
68
54
 
69
55
  const handle = vm.unwrapResult(
70
56
  vm.evalCode(`({
@@ -72,79 +58,57 @@ test("object with symbol key", async () => {
72
58
  [Symbol("a")]: "bar"
73
59
  })`)
74
60
  );
75
- const target = unmarshal(handle, {
76
- vm,
77
- pre,
78
- find: () => undefined,
79
- marshal: () => [vm.undefined, false],
80
- });
61
+ const target = unmarshal(handle);
81
62
 
82
63
  expect(target.hoge).toBe("foo");
83
64
  expect(target[Object.getOwnPropertySymbols(target)[0]]).toBe("bar");
84
65
 
85
- handle.dispose();
86
- map.dispose();
87
- vm.dispose();
66
+ dispose();
88
67
  });
89
68
 
90
- test("func", async () => {
91
- const vm = (await getQuickJS()).createVm();
92
- const jsonParse = vm.unwrapResult(vm.evalCode(`JSON.parse`));
93
- const disposables: QuickJSHandle[] = [];
94
- const marshal = jest.fn((t: unknown): [QuickJSHandle, boolean] => {
95
- const h =
96
- t === undefined
97
- ? vm.undefined
98
- : vm.unwrapResult(
99
- vm.callFunction(
100
- jsonParse,
101
- vm.undefined,
102
- vm.newString(JSON.stringify(t))
103
- )
104
- );
105
- const ty = vm.typeof(h);
106
- if (ty === "object" || ty === "function") disposables.push(h);
107
- return [h, false];
108
- });
69
+ test("function", async () => {
70
+ const { vm, unmarshal, marshal, map, dispose } = await setup();
109
71
 
110
72
  const handle = vm.unwrapResult(
111
73
  vm.evalCode(`(function(a) { return a.a + "!"; })`)
112
74
  );
113
- const map = new VMMap(vm);
114
- const find = jest.fn((h) => map.getByHandle(h));
115
- const pre = jest.fn((t: any, h: QuickJSHandle) => {
116
- map.set(t, h);
117
- return t;
118
- });
119
- const func = unmarshal(handle, { vm, find, pre, marshal });
75
+ const func = unmarshal(handle);
120
76
  const arg = { a: "hoge" };
121
77
  expect(func(arg)).toBe("hoge!");
122
78
  expect(marshal).toBeCalledTimes(2);
123
79
  expect(marshal).toBeCalledWith(undefined); // this
124
80
  expect(marshal).toBeCalledWith(arg); // arg
125
- expect(map.size).toBe(2);
81
+ expect(map.size).toBe(3);
126
82
  expect(map.getByHandle(handle)).toBe(func);
83
+ expect(map.has(func)).toBe(true);
127
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!");
128
98
 
129
- map.dispose();
130
- disposables.forEach((d) => d.dispose());
131
- jsonParse.dispose();
132
- vm.dispose();
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();
133
108
  });
134
109
 
135
110
  test("class", async () => {
136
- const vm = (await getQuickJS()).createVm();
137
- const jsonParse = vm.unwrapResult(vm.evalCode(`JSON.parse`));
138
- const disposables: QuickJSHandle[] = [];
139
- const map = new VMMap(vm);
140
- const marshal = jest.fn((t: unknown): [QuickJSHandle, boolean] => {
141
- const h = vm.unwrapResult(
142
- vm.callFunction(jsonParse, vm.undefined, vm.newString(JSON.stringify(t)))
143
- );
144
- const ty = vm.typeof(h);
145
- if (ty === "object" || ty === "function") disposables.push(h);
146
- return [h, false];
147
- });
111
+ const { vm, unmarshal, dispose } = await setup();
148
112
 
149
113
  const handle = vm.unwrapResult(
150
114
  vm.evalCode(`{
@@ -160,12 +124,7 @@ test("class", async () => {
160
124
  Cls
161
125
  }`)
162
126
  );
163
- const find = jest.fn((h) => map.getByHandle(h));
164
- const pre = jest.fn((t: any, h: QuickJSHandle) => {
165
- map.set(t, h);
166
- return t;
167
- });
168
- const Cls = unmarshal(handle, { vm, find, pre, marshal });
127
+ const Cls = unmarshal(handle);
169
128
 
170
129
  expect(Cls.hoge).toBe("foo");
171
130
  expect(Cls.foo instanceof Cls).toBe(true);
@@ -175,8 +134,46 @@ test("class", async () => {
175
134
  expect(cls.foo).toBe(4);
176
135
 
177
136
  handle.dispose();
178
- map.dispose();
179
- disposables.forEach((d) => d.dispose());
180
- jsonParse.dispose();
181
- vm.dispose();
137
+ dispose();
182
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
+ };
@@ -2,14 +2,15 @@ import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
2
  import unmarshalFunction from "./function";
3
3
  import unmarshalObject from "./object";
4
4
  import unmarshalPrimitive from "./primitive";
5
+ import unmarshalPromise from "./promise";
5
6
  import unmarshalSymbol from "./symbol";
6
7
 
7
8
  export type Options = {
8
9
  vm: QuickJSVm;
9
- // marshal returns handle and boolean indicates that the handle should be disposed after use
10
+ /** marshal returns handle and boolean indicates that the handle should be disposed after use */
10
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,6 +40,7 @@ function unmarshalInner(
39
40
 
40
41
  const result =
41
42
  unmarshalSymbol(vm, handle, pre) ??
43
+ unmarshalPromise(vm, handle, marshal, pre) ??
42
44
  unmarshalFunction(vm, handle, marshal, unmarshal2, pre) ??
43
45
  unmarshalObject(vm, handle, unmarshal2, pre);
44
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 = jest.fn((v: QuickJSHandle): [unknown, boolean] => [
8
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
7
9
  vm.dump(v),
8
10
  false,
9
11
  ]);
10
- const preUnmarshal = jest.fn((a) => a);
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 = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
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 = jest.fn((a) => a);
37
+ const preUnmarshal = vi.fn((a) => a);
36
38
 
37
39
  const handle = vm.unwrapResult(
38
40
  vm.evalCode(`{
@@ -77,11 +79,11 @@ test("properties", async () => {
77
79
 
78
80
  test("array", async () => {
79
81
  const vm = (await getQuickJS()).createVm();
80
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => [
82
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
81
83
  vm.dump(v),
82
84
  false,
83
85
  ]);
84
- const preUnmarshal = jest.fn((a) => a);
86
+ const preUnmarshal = vi.fn((a) => a);
85
87
 
86
88
  const handle = vm.unwrapResult(vm.evalCode(`[1, true, "a"]`));
87
89
  const array = unmarshalObject(vm, handle, unmarshal, preUnmarshal);
@@ -103,11 +105,11 @@ test("array", async () => {
103
105
 
104
106
  test("prototype", async () => {
105
107
  const vm = (await getQuickJS()).createVm();
106
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => [
108
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
107
109
  vm.typeof(v) === "object" ? { a: () => 1 } : vm.dump(v),
108
110
  false,
109
111
  ]);
110
- const preUnmarshal = jest.fn((a) => a);
112
+ const preUnmarshal = vi.fn((a) => a);
111
113
 
112
114
  const handle = vm.unwrapResult(vm.evalCode(`Object.create({ a: () => 1 })`));
113
115
  const obj = unmarshalObject(vm, handle, unmarshal, preUnmarshal) as any;
@@ -125,7 +127,7 @@ test("prototype", async () => {
125
127
 
126
128
  test("undefined", async () => {
127
129
  const vm = (await getQuickJS()).createVm();
128
- const f = jest.fn();
130
+ const f = vi.fn();
129
131
 
130
132
  expect(unmarshalObject(vm, vm.undefined, f, f)).toEqual(undefined);
131
133
  expect(unmarshalObject(vm, vm.true, f, f)).toEqual(undefined);
@@ -1,4 +1,6 @@
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 () => {
@@ -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 = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
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
  });