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.
Files changed (71) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +59 -49
  3. package/dist/index.d.ts +121 -26
  4. package/dist/quickjs-emscripten-sync.es.js +962 -0
  5. package/dist/quickjs-emscripten-sync.umd.js +64 -0
  6. package/package.json +28 -40
  7. package/src/default.ts +2 -2
  8. package/src/index.test.ts +371 -69
  9. package/src/index.ts +135 -72
  10. package/src/marshal/function.test.ts +70 -61
  11. package/src/marshal/function.ts +10 -9
  12. package/src/marshal/index.test.ts +135 -62
  13. package/src/marshal/index.ts +33 -16
  14. package/src/marshal/json.test.ts +94 -0
  15. package/src/marshal/json.ts +16 -0
  16. package/src/marshal/object.test.ts +65 -58
  17. package/src/marshal/object.ts +6 -5
  18. package/src/marshal/primitive.test.ts +23 -17
  19. package/src/marshal/primitive.ts +10 -9
  20. package/src/marshal/promise.test.ts +86 -0
  21. package/src/marshal/promise.ts +26 -0
  22. package/src/marshal/properties.test.ts +23 -19
  23. package/src/marshal/properties.ts +11 -10
  24. package/src/marshal/symbol.test.ts +9 -7
  25. package/src/marshal/symbol.ts +5 -4
  26. package/src/unmarshal/function.test.ts +70 -61
  27. package/src/unmarshal/function.ts +39 -30
  28. package/src/unmarshal/index.test.ts +101 -100
  29. package/src/unmarshal/index.ts +13 -9
  30. package/src/unmarshal/object.test.ts +45 -41
  31. package/src/unmarshal/object.ts +14 -13
  32. package/src/unmarshal/primitive.test.ts +20 -15
  33. package/src/unmarshal/primitive.ts +10 -10
  34. package/src/unmarshal/promise.test.ts +44 -0
  35. package/src/unmarshal/promise.ts +38 -0
  36. package/src/unmarshal/properties.test.ts +10 -8
  37. package/src/unmarshal/properties.ts +47 -42
  38. package/src/unmarshal/symbol.test.ts +9 -7
  39. package/src/unmarshal/symbol.ts +4 -4
  40. package/src/util.test.ts +23 -5
  41. package/src/util.ts +15 -0
  42. package/src/vmmap.test.ts +88 -82
  43. package/src/vmmap.ts +21 -17
  44. package/src/vmutil.test.ts +159 -53
  45. package/src/vmutil.ts +91 -19
  46. package/src/wrapper.test.ts +151 -115
  47. package/src/wrapper.ts +69 -48
  48. package/dist/default.d.ts +0 -4
  49. package/dist/index.js +0 -8
  50. package/dist/marshal/function.d.ts +0 -2
  51. package/dist/marshal/index.d.ts +0 -11
  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.development.js +0 -1289
  57. package/dist/quickjs-emscripten-sync.cjs.development.js.map +0 -1
  58. package/dist/quickjs-emscripten-sync.cjs.production.min.js +0 -2
  59. package/dist/quickjs-emscripten-sync.cjs.production.min.js.map +0 -1
  60. package/dist/quickjs-emscripten-sync.esm.js +0 -1272
  61. package/dist/quickjs-emscripten-sync.esm.js.map +0 -1
  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
@@ -1,18 +1,20 @@
1
1
  import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
2
- import { send } from "../vmutil";
2
+ import { expect, test, vi } from "vitest";
3
+
4
+ import { json } from "../vmutil";
3
5
  import unmarshalFunction from "./function";
4
6
 
5
7
  test("arrow function", async () => {
6
- const vm = (await getQuickJS()).createVm();
7
- const marshal = jest.fn(v => send(vm, v));
8
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => [
9
- vm.dump(v),
8
+ const ctx = (await getQuickJS()).newContext();
9
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [json(ctx, v), false]);
10
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => [
11
+ ctx.dump(v),
10
12
  false,
11
13
  ]);
12
- const preUnmarshal = jest.fn(a => a);
14
+ const preUnmarshal = vi.fn((a) => a);
13
15
 
14
- const handle = vm.unwrapResult(vm.evalCode(`(a, b) => a + b`));
15
- const func = unmarshalFunction(vm, handle, marshal, unmarshal, preUnmarshal);
16
+ const handle = ctx.unwrapResult(ctx.evalCode(`(a, b) => a + b`));
17
+ const func = unmarshalFunction(ctx, handle, marshal, unmarshal, preUnmarshal);
16
18
  if (!func) throw new Error("func is undefined");
17
19
 
18
20
  expect(func(1, 2)).toBe(3);
@@ -32,27 +34,30 @@ test("arrow function", async () => {
32
34
  handle.dispose();
33
35
  expect(() => func(1, 2)).toThrow("Lifetime not alive");
34
36
 
35
- vm.dispose();
37
+ ctx.dispose();
36
38
  });
37
39
 
38
40
  test("function", async () => {
39
- const vm = (await getQuickJS()).createVm();
41
+ const ctx = (await getQuickJS()).newContext();
40
42
  const that = { a: 1 };
41
- const thatHandle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
42
- const marshal = jest.fn(v => (v === that ? thatHandle : send(vm, v)));
43
+ const thatHandle = ctx.unwrapResult(ctx.evalCode(`({ a: 1 })`));
44
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
45
+ v === that ? thatHandle : json(ctx, v),
46
+ false,
47
+ ]);
43
48
  const disposables: QuickJSHandle[] = [];
44
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
45
- const ty = vm.typeof(v);
49
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
50
+ const ty = ctx.typeof(v);
46
51
  if (ty === "object" || ty === "function") disposables.push(v);
47
- return [vm.dump(v), false];
52
+ return [ctx.dump(v), false];
48
53
  });
49
- const preUnmarshal = jest.fn(a => a);
54
+ const preUnmarshal = vi.fn((a) => a);
50
55
 
51
- const handle = vm.unwrapResult(
52
- vm.evalCode(`(function (a) { return this.a + a; })`)
56
+ const handle = ctx.unwrapResult(
57
+ ctx.evalCode(`(function (a) { return this.a + a; })`)
53
58
  );
54
59
 
55
- const func = unmarshalFunction(vm, handle, marshal, unmarshal, preUnmarshal);
60
+ const func = unmarshalFunction(ctx, handle, marshal, unmarshal, preUnmarshal);
56
61
  if (!func) throw new Error("func is undefined");
57
62
 
58
63
  expect(func.call(that, 2)).toBe(3);
@@ -70,31 +75,32 @@ test("function", async () => {
70
75
  expect(preUnmarshal).toBeCalledTimes(1);
71
76
  expect(preUnmarshal).toBeCalledWith(func, handle);
72
77
 
73
- disposables.forEach(d => d.dispose());
78
+ disposables.forEach((d) => d.dispose());
74
79
  thatHandle.dispose();
75
80
  handle.dispose();
76
- vm.dispose();
81
+ ctx.dispose();
77
82
  });
78
83
 
79
84
  test("constructor", async () => {
80
- const vm = (await getQuickJS()).createVm();
85
+ const ctx = (await getQuickJS()).newContext();
81
86
  const disposables: QuickJSHandle[] = [];
82
- const marshal = jest.fn(v =>
83
- typeof v === "object" ? vm.undefined : send(vm, v)
84
- );
85
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
86
- const ty = vm.typeof(v);
87
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
88
+ typeof v === "object" ? ctx.undefined : json(ctx, v),
89
+ false,
90
+ ]);
91
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
92
+ const ty = ctx.typeof(v);
87
93
  if (ty === "object" || ty === "function") disposables.push(v);
88
- return [vm.dump(v), false];
94
+ return [ctx.dump(v), false];
89
95
  });
90
- const preUnmarshal = jest.fn(a => a);
96
+ const preUnmarshal = vi.fn((a) => a);
91
97
 
92
- const handle = vm.unwrapResult(
93
- vm.evalCode(`(function (b) { this.a = b + 2; })`)
98
+ const handle = ctx.unwrapResult(
99
+ ctx.evalCode(`(function (b) { this.a = b + 2; })`)
94
100
  );
95
101
 
96
102
  const Cls = unmarshalFunction(
97
- vm,
103
+ ctx,
98
104
  handle,
99
105
  marshal,
100
106
  unmarshal,
@@ -119,30 +125,31 @@ test("constructor", async () => {
119
125
  expect(preUnmarshal).toBeCalledTimes(1);
120
126
  expect(preUnmarshal).toBeCalledWith(Cls, handle);
121
127
 
122
- disposables.forEach(d => d.dispose());
128
+ disposables.forEach((d) => d.dispose());
123
129
  handle.dispose();
124
- vm.dispose();
130
+ ctx.dispose();
125
131
  });
126
132
 
127
133
  test("class", async () => {
128
- const vm = (await getQuickJS()).createVm();
129
- const marshal = jest.fn(v =>
130
- typeof v === "object" ? vm.undefined : send(vm, v)
131
- );
134
+ const ctx = (await getQuickJS()).newContext();
135
+ const marshal = vi.fn((v): [QuickJSHandle, boolean] => [
136
+ typeof v === "object" ? ctx.undefined : json(ctx, v),
137
+ false,
138
+ ]);
132
139
  const disposables: QuickJSHandle[] = [];
133
- const unmarshal = jest.fn((v: QuickJSHandle): [unknown, boolean] => {
134
- const ty = vm.typeof(v);
140
+ const unmarshal = vi.fn((v: QuickJSHandle): [unknown, boolean] => {
141
+ const ty = ctx.typeof(v);
135
142
  if (ty === "object" || ty === "function") disposables.push(v);
136
- return [vm.dump(v), false];
143
+ return [ctx.dump(v), false];
137
144
  });
138
- const preUnmarshal = jest.fn(a => a);
145
+ const preUnmarshal = vi.fn((a) => a);
139
146
 
140
- const handle = vm.unwrapResult(
141
- vm.evalCode(`(class A { constructor(a) { this.a = a + 1; } })`)
147
+ const handle = ctx.unwrapResult(
148
+ ctx.evalCode(`(class A { constructor(a) { this.a = a + 1; } })`)
142
149
  );
143
150
 
144
151
  const Cls = unmarshalFunction(
145
- vm,
152
+ ctx,
146
153
  handle,
147
154
  marshal,
148
155
  unmarshal,
@@ -167,32 +174,34 @@ test("class", async () => {
167
174
  expect(preUnmarshal).toBeCalledTimes(1);
168
175
  expect(preUnmarshal).toBeCalledWith(Cls, handle);
169
176
 
170
- disposables.forEach(d => d.dispose());
177
+ disposables.forEach((d) => d.dispose());
171
178
  handle.dispose();
172
- vm.dispose();
179
+ ctx.dispose();
173
180
  });
174
181
 
175
182
  test("undefined", async () => {
176
- const vm = (await getQuickJS()).createVm();
177
- const f = jest.fn();
178
-
179
- expect(unmarshalFunction(vm, vm.undefined, f, f, f)).toEqual(undefined);
180
- expect(unmarshalFunction(vm, vm.true, f, f, f)).toEqual(undefined);
181
- expect(unmarshalFunction(vm, vm.false, f, f, f)).toEqual(undefined);
182
- expect(unmarshalFunction(vm, vm.null, f, f, f)).toEqual(undefined);
183
- expect(unmarshalFunction(vm, vm.newString("hoge"), f, f, f)).toEqual(
183
+ const ctx = (await getQuickJS()).newContext();
184
+ const f = vi.fn();
185
+
186
+ expect(unmarshalFunction(ctx, ctx.undefined, f, f, f)).toEqual(undefined);
187
+ expect(unmarshalFunction(ctx, ctx.true, f, f, f)).toEqual(undefined);
188
+ expect(unmarshalFunction(ctx, ctx.false, f, f, f)).toEqual(undefined);
189
+ expect(unmarshalFunction(ctx, ctx.null, f, f, f)).toEqual(undefined);
190
+ expect(unmarshalFunction(ctx, ctx.newString("hoge"), f, f, f)).toEqual(
191
+ undefined
192
+ );
193
+ expect(unmarshalFunction(ctx, ctx.newNumber(-10), f, f, f)).toEqual(
184
194
  undefined
185
195
  );
186
- expect(unmarshalFunction(vm, vm.newNumber(-10), f, f, f)).toEqual(undefined);
187
196
 
188
- const obj = vm.newObject();
189
- expect(unmarshalFunction(vm, obj, f, f, f)).toEqual(undefined);
190
- const array = vm.newArray();
191
- expect(unmarshalFunction(vm, array, f, f, f)).toEqual(undefined);
197
+ const obj = ctx.newObject();
198
+ expect(unmarshalFunction(ctx, obj, f, f, f)).toEqual(undefined);
199
+ const array = ctx.newArray();
200
+ expect(unmarshalFunction(ctx, array, f, f, f)).toEqual(undefined);
192
201
 
193
202
  expect(f).toBeCalledTimes(0);
194
203
 
195
204
  obj.dispose();
196
205
  array.dispose();
197
- vm.dispose();
206
+ ctx.dispose();
198
207
  });
@@ -1,44 +1,53 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
- import { call } from "../vmutil";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
3
+ import { call, mayConsumeAll } from "../vmutil";
3
4
  import unmarshalProperties from "./properties";
4
5
 
5
6
  export default function unmarshalFunction(
6
- vm: QuickJSVm,
7
+ ctx: QuickJSContext,
7
8
  handle: QuickJSHandle,
8
- marshal: (value: unknown) => QuickJSHandle,
9
+ /** marshal returns handle and boolean indicates that the handle should be disposed after use */
10
+ marshal: (value: unknown) => [QuickJSHandle, boolean],
9
11
  unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
10
12
  preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined
11
13
  ): Function | undefined {
12
- if (vm.typeof(handle) !== "function") return;
13
-
14
- const raw = function(this: any, ...args: any[]) {
15
- const thisHandle = marshal(this);
16
- const argHandles = args.map(a => marshal(a));
17
-
18
- if (new.target) {
19
- const [instance] = unmarshal(
20
- call(
21
- vm,
22
- `(Cls, ...args) => new Cls(...args)`,
23
- thisHandle,
24
- handle,
25
- ...argHandles
26
- )
27
- );
28
- Object.defineProperties(this, Object.getOwnPropertyDescriptors(instance));
29
- return this;
30
- }
31
-
32
- const resultHandle = vm.unwrapResult(
33
- vm.callFunction(handle, thisHandle, ...argHandles)
14
+ if (ctx.typeof(handle) !== "function") return;
15
+
16
+ const raw = function (this: any, ...args: any[]) {
17
+ return mayConsumeAll(
18
+ [marshal(this), ...args.map((a) => marshal(a))],
19
+ (thisHandle, ...argHandles) => {
20
+ if (new.target) {
21
+ const [instance] = unmarshal(
22
+ call(
23
+ ctx,
24
+ `(Cls, ...args) => new Cls(...args)`,
25
+ thisHandle,
26
+ handle,
27
+ ...argHandles
28
+ )
29
+ );
30
+ Object.defineProperties(
31
+ this,
32
+ Object.getOwnPropertyDescriptors(instance)
33
+ );
34
+ return this;
35
+ }
36
+
37
+ const resultHandle = ctx.unwrapResult(
38
+ ctx.callFunction(handle, thisHandle, ...argHandles)
39
+ );
40
+
41
+ const [result, alreadyExists] = unmarshal(resultHandle);
42
+ if (alreadyExists) resultHandle.dispose();
43
+
44
+ return result;
45
+ }
34
46
  );
35
- const [result, alreadyExists] = unmarshal(resultHandle);
36
- if (alreadyExists) resultHandle.dispose();
37
- return result;
38
47
  };
39
48
 
40
49
  const func = preUnmarshal(raw, handle) ?? raw;
41
- unmarshalProperties(vm, handle, raw, unmarshal);
50
+ unmarshalProperties(ctx, handle, raw, unmarshal);
42
51
 
43
52
  return func;
44
53
  }
@@ -1,19 +1,15 @@
1
1
  import { 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 { ctx, unmarshal, marshal, map, dispose } = await setup();
14
10
 
15
- const handle = vm.unwrapResult(
16
- vm.evalCode(`({
11
+ const handle = ctx.unwrapResult(
12
+ ctx.evalCode(`({
17
13
  hoge: "foo",
18
14
  foo: 1,
19
15
  aaa: [1, true, {}],
@@ -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,119 +28,91 @@ 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 =>
36
- expect(map.getByHandle(h)).toBe(target.aaa)
37
- );
38
- 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 =>
42
- expect(map.getByHandle(h)).toBe(target.nested)
43
- );
44
- vm.getProp(handle, "bbb").consume(h =>
45
- expect(map.getByHandle(h)).toBe(target.bbb)
46
- );
31
+ ctx
32
+ .getProp(handle, "aaa")
33
+ .consume((h) => expect(map.getByHandle(h)).toBe(target.aaa));
34
+ ctx
35
+ .getProp(handle, "aaa")
36
+ .consume((h) => ctx.getProp(h, 2))
37
+ .consume((h) => expect(map.getByHandle(h)).toBe(target.aaa[2]));
38
+ ctx
39
+ .getProp(handle, "nested")
40
+ .consume((h) => expect(map.getByHandle(h)).toBe(target.nested));
41
+ ctx
42
+ .getProp(handle, "bbb")
43
+ .consume((h) => expect(map.getByHandle(h)).toBe(target.bbb));
47
44
 
48
45
  expect(marshal).toBeCalledTimes(0);
49
46
  expect(target.bbb()).toBe("bar");
50
47
  expect(marshal).toBeCalledTimes(1);
51
48
  expect(marshal).toBeCalledWith(target); // thisArg of target.bbb()
52
49
 
53
- handle.dispose();
54
- map.dispose();
55
- vm.dispose();
50
+ dispose();
56
51
  });
57
52
 
58
53
  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
- };
54
+ const { ctx, unmarshal, dispose } = await setup();
65
55
 
66
- const handle = vm.unwrapResult(
67
- vm.evalCode(`({
56
+ const handle = ctx.unwrapResult(
57
+ ctx.evalCode(`({
68
58
  hoge: "foo",
69
59
  [Symbol("a")]: "bar"
70
60
  })`)
71
61
  );
72
- const target = unmarshal(handle, {
73
- vm,
74
- pre,
75
- find: () => undefined,
76
- marshal: () => vm.undefined,
77
- });
62
+ const target = unmarshal(handle);
78
63
 
79
64
  expect(target.hoge).toBe("foo");
80
65
  expect(target[Object.getOwnPropertySymbols(target)[0]]).toBe("bar");
81
66
 
82
- handle.dispose();
83
- map.dispose();
84
- vm.dispose();
67
+ dispose();
85
68
  });
86
69
 
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
- });
70
+ test("function", async () => {
71
+ const { ctx, unmarshal, marshal, map, dispose } = await setup();
106
72
 
107
- const handle = vm.unwrapResult(
108
- vm.evalCode(`(function(a) { return a.a + "!"; })`)
73
+ const handle = ctx.unwrapResult(
74
+ ctx.evalCode(`(function(a) { return a.a + "!"; })`)
109
75
  );
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 });
76
+ const func = unmarshal(handle);
117
77
  const arg = { a: "hoge" };
118
78
  expect(func(arg)).toBe("hoge!");
119
79
  expect(marshal).toBeCalledTimes(2);
120
80
  expect(marshal).toBeCalledWith(undefined); // this
121
81
  expect(marshal).toBeCalledWith(arg); // arg
122
- expect(map.size).toBe(2);
82
+ expect(map.size).toBe(3);
123
83
  expect(map.getByHandle(handle)).toBe(func);
84
+ expect(map.has(func)).toBe(true);
124
85
  expect(map.has(func.prototype)).toBe(true);
86
+ expect(map.has(arg)).toBe(true);
125
87
 
126
- map.dispose();
127
- disposables.forEach(d => d.dispose());
128
- jsonParse.dispose();
129
- vm.dispose();
88
+ dispose();
89
+ });
90
+
91
+ test("promise", async () => {
92
+ const { ctx, unmarshal, dispose } = await setup();
93
+
94
+ const deferred = ctx.newPromise();
95
+ const promise = unmarshal(deferred.handle);
96
+ deferred.resolve(ctx.newString("resolved!"));
97
+ ctx.runtime.executePendingJobs();
98
+ await expect(promise).resolves.toBe("resolved!");
99
+
100
+ const deferred2 = ctx.newPromise();
101
+ const promise2 = unmarshal(deferred2.handle);
102
+ deferred2.reject(ctx.newString("rejected!"));
103
+ ctx.runtime.executePendingJobs();
104
+ await expect(promise2).rejects.toBe("rejected!");
105
+
106
+ deferred.dispose();
107
+ deferred2.dispose();
108
+ dispose();
130
109
  });
131
110
 
132
111
  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
- });
112
+ const { ctx, unmarshal, dispose } = await setup();
145
113
 
146
- const handle = vm.unwrapResult(
147
- vm.evalCode(`{
114
+ const handle = ctx.unwrapResult(
115
+ ctx.evalCode(`{
148
116
  class Cls {
149
117
  static hoge = "foo";
150
118
 
@@ -157,12 +125,7 @@ test("class", async () => {
157
125
  Cls
158
126
  }`)
159
127
  );
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 });
128
+ const Cls = unmarshal(handle);
166
129
 
167
130
  expect(Cls.hoge).toBe("foo");
168
131
  expect(Cls.foo instanceof Cls).toBe(true);
@@ -172,8 +135,46 @@ test("class", async () => {
172
135
  expect(cls.foo).toBe(4);
173
136
 
174
137
  handle.dispose();
175
- map.dispose();
176
- disposables.forEach(d => d.dispose());
177
- jsonParse.dispose();
178
- vm.dispose();
138
+ dispose();
179
139
  });
140
+
141
+ const setup = async () => {
142
+ const ctx = (await getQuickJS()).newContext();
143
+ const map = new VMMap(ctx);
144
+ const disposables: QuickJSHandle[] = [];
145
+ const marshal = vi.fn((target: unknown): [QuickJSHandle, boolean] => {
146
+ const handle = map.get(target);
147
+ if (handle) return [handle, false];
148
+
149
+ const handle2 =
150
+ typeof target === "function"
151
+ ? ctx.newFunction(target.name, (...handles) => {
152
+ target(...handles.map((h) => ctx.dump(h)));
153
+ })
154
+ : json(ctx, target);
155
+ const ty = ctx.typeof(handle2);
156
+ if (ty === "object" || ty === "function") map.set(target, handle2);
157
+ return [handle2, false];
158
+ });
159
+
160
+ return {
161
+ ctx,
162
+ map,
163
+ unmarshal: (handle: QuickJSHandle) =>
164
+ unmarshal(handle, {
165
+ find: (h) => map.getByHandle(h),
166
+ marshal,
167
+ pre: (t, h) => {
168
+ map.set(t, h);
169
+ return t;
170
+ },
171
+ ctx: ctx,
172
+ }),
173
+ marshal,
174
+ dispose: () => {
175
+ disposables.forEach((d) => d.dispose());
176
+ map.dispose();
177
+ ctx.dispose();
178
+ },
179
+ };
180
+ };
@@ -1,14 +1,17 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
2
3
  import unmarshalFunction from "./function";
3
4
  import unmarshalObject from "./object";
4
5
  import unmarshalPrimitive from "./primitive";
6
+ import unmarshalPromise from "./promise";
5
7
  import unmarshalSymbol from "./symbol";
6
8
 
7
9
  export type Options = {
8
- vm: QuickJSVm;
9
- marshal: (target: unknown) => QuickJSHandle;
10
+ ctx: QuickJSContext;
11
+ /** marshal returns handle and boolean indicates that the handle should be disposed after use */
12
+ marshal: (target: unknown) => [QuickJSHandle, boolean];
10
13
  find: (handle: QuickJSHandle) => unknown | undefined;
11
- pre: <T>(target: T, handle: QuickJSHandle) => T | undefined;
14
+ pre: <T = unknown>(target: T, handle: QuickJSHandle) => T | undefined;
12
15
  };
13
16
 
14
17
  export function unmarshal(handle: QuickJSHandle, options: Options): any {
@@ -20,10 +23,10 @@ function unmarshalInner(
20
23
  handle: QuickJSHandle,
21
24
  options: Options
22
25
  ): [any, boolean] {
23
- const { vm, marshal, find, pre } = options;
26
+ const { ctx, marshal, find, pre } = options;
24
27
 
25
28
  {
26
- const [target, ok] = unmarshalPrimitive(vm, handle);
29
+ const [target, ok] = unmarshalPrimitive(ctx, handle);
27
30
  if (ok) return [target, false];
28
31
  }
29
32
 
@@ -37,9 +40,10 @@ function unmarshalInner(
37
40
  const unmarshal2 = (h: QuickJSHandle) => unmarshalInner(h, options);
38
41
 
39
42
  const result =
40
- unmarshalSymbol(vm, handle, pre) ??
41
- unmarshalFunction(vm, handle, marshal, unmarshal2, pre) ??
42
- unmarshalObject(vm, handle, unmarshal2, pre);
43
+ unmarshalSymbol(ctx, handle, pre) ??
44
+ unmarshalPromise(ctx, handle, marshal, pre) ??
45
+ unmarshalFunction(ctx, handle, marshal, unmarshal2, pre) ??
46
+ unmarshalObject(ctx, handle, unmarshal2, pre);
43
47
 
44
48
  return [result, false];
45
49
  }