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