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,43 +1,40 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
2
3
  import { isES2015Class, isObject } from "../util";
3
4
  import { call } from "../vmutil";
5
+
4
6
  import marshalProperties from "./properties";
5
7
 
6
8
  export default function marshalFunction(
7
- vm: QuickJSVm,
9
+ ctx: QuickJSContext,
8
10
  target: unknown,
9
11
  marshal: (target: unknown) => QuickJSHandle,
10
12
  unmarshal: (handle: QuickJSHandle) => unknown,
11
- preMarshal: (
12
- target: unknown,
13
- handle: QuickJSHandle
14
- ) => QuickJSHandle | undefined,
15
- preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any
13
+ preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
14
+ preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any,
16
15
  ): QuickJSHandle | undefined {
17
16
  if (typeof target !== "function") return;
18
17
 
19
- const raw = vm
18
+ const raw = ctx
20
19
  .newFunction(target.name, function (...argHandles) {
21
20
  const that = unmarshal(this);
22
- const args = argHandles.map((a) => unmarshal(a));
21
+ const args = argHandles.map(a => unmarshal(a));
23
22
 
24
23
  if (isES2015Class(target) && isObject(that)) {
25
24
  // Class constructors cannot be invoked without new expression, and new.target is not changed
26
25
  const result = new target(...args);
27
26
  Object.entries(result).forEach(([key, value]) => {
28
- vm.setProp(this, key, marshal(value));
27
+ ctx.setProp(this, key, marshal(value));
29
28
  });
30
29
  return this;
31
30
  }
32
31
 
33
- return marshal(
34
- preApply ? preApply(target, that, args) : target.apply(that, args)
35
- );
32
+ return marshal(preApply ? preApply(target, that, args) : target.apply(that, args));
36
33
  })
37
- .consume((handle2) =>
34
+ .consume(handle2 =>
38
35
  // fucntions created by vm.newFunction are not callable as a class constrcutor
39
36
  call(
40
- vm,
37
+ ctx,
41
38
  `Cls => {
42
39
  const fn = function(...args) { return Cls.apply(this, args); };
43
40
  fn.name = Cls.name;
@@ -45,12 +42,12 @@ export default function marshalFunction(
45
42
  return fn;
46
43
  }`,
47
44
  undefined,
48
- handle2
49
- )
45
+ handle2,
46
+ ),
50
47
  );
51
48
 
52
49
  const handle = preMarshal(target, raw) ?? raw;
53
- marshalProperties(vm, target, raw, marshal);
50
+ marshalProperties(ctx, target, raw, marshal);
54
51
 
55
52
  return handle;
56
53
  }
@@ -1,10 +1,14 @@
1
1
  import { getQuickJS } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
4
+ import { newDeferred } from "../util";
2
5
  import VMMap from "../vmmap";
3
- import { instanceOf, call } from "../vmutil";
6
+ import { instanceOf, call, handleFrom, fn } from "../vmutil";
7
+
4
8
  import marshal from ".";
5
9
 
6
10
  test("primitive, array, object", async () => {
7
- const { vm, map, marshal, dispose } = await setup();
11
+ const { ctx, map, marshal, dispose } = await setup();
8
12
 
9
13
  const target = {
10
14
  hoge: "foo",
@@ -14,7 +18,7 @@ test("primitive, array, object", async () => {
14
18
  };
15
19
  const handle = marshal(target);
16
20
 
17
- expect(vm.dump(handle)).toEqual(target);
21
+ expect(ctx.dump(handle)).toEqual(target);
18
22
  expect(map.size).toBe(4);
19
23
  expect(map.get(target)).toBe(handle);
20
24
  expect(map.has(target.aaa)).toBe(true);
@@ -25,37 +29,33 @@ test("primitive, array, object", async () => {
25
29
  });
26
30
 
27
31
  test("object with symbol key", async () => {
28
- const { vm, marshal, dispose } = await setup();
32
+ const { ctx, marshal, dispose } = await setup();
29
33
 
30
34
  const target = {
31
35
  foo: "hoge",
32
36
  [Symbol("a")]: 1,
33
37
  };
34
38
  const handle = marshal(target);
35
- expect(vm.dump(call(vm, `a => a.foo`, undefined, handle))).toBe("hoge");
36
- expect(
37
- vm.dump(
38
- call(vm, `a => a[Object.getOwnPropertySymbols(a)[0]]`, undefined, handle)
39
- )
40
- ).toBe(1);
39
+ expect(ctx.dump(call(ctx, `a => a.foo`, undefined, handle))).toBe("hoge");
40
+ expect(ctx.dump(call(ctx, `a => a[Object.getOwnPropertySymbols(a)[0]]`, undefined, handle))).toBe(
41
+ 1,
42
+ );
41
43
 
42
44
  dispose();
43
45
  });
44
46
 
45
47
  test("arrow function", async () => {
46
- const { vm, map, marshal, dispose } = await setup();
48
+ const { ctx, map, marshal, dispose } = await setup();
47
49
  const hoge = () => "foo";
48
50
  hoge.foo = { bar: 1 };
49
51
  const handle = marshal(hoge);
50
52
 
51
- expect(vm.typeof(handle)).toBe("function");
52
- expect(vm.dump(vm.getProp(handle, "length"))).toBe(0);
53
- expect(vm.dump(vm.getProp(handle, "name"))).toBe("hoge");
54
- const foo = vm.getProp(handle, "foo");
55
- expect(vm.dump(foo)).toEqual({ bar: 1 });
56
- expect(vm.dump(vm.unwrapResult(vm.callFunction(handle, vm.undefined)))).toBe(
57
- "foo"
58
- );
53
+ expect(ctx.typeof(handle)).toBe("function");
54
+ expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(0);
55
+ expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("hoge");
56
+ const foo = ctx.getProp(handle, "foo");
57
+ expect(ctx.dump(foo)).toEqual({ bar: 1 });
58
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(handle, ctx.undefined)))).toBe("foo");
59
59
  expect(map.size).toBe(2);
60
60
  expect(map.get(hoge)).toBe(handle);
61
61
  expect(map.has(hoge.foo)).toBe(true);
@@ -65,33 +65,69 @@ test("arrow function", async () => {
65
65
  });
66
66
 
67
67
  test("function", async () => {
68
- const { vm, map, marshal, dispose } = await setup();
68
+ const { ctx, map, marshal, dispose } = await setup();
69
69
 
70
70
  const bar = function (a: number, b: { hoge: number }) {
71
71
  return a + b.hoge;
72
72
  };
73
73
  const handle = marshal(bar);
74
74
 
75
- expect(vm.typeof(handle)).toBe("function");
76
- expect(vm.dump(vm.getProp(handle, "length"))).toBe(2);
77
- expect(vm.dump(vm.getProp(handle, "name"))).toBe("bar");
75
+ expect(ctx.typeof(handle)).toBe("function");
76
+ expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(2);
77
+ expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("bar");
78
78
  expect(map.size).toBe(2);
79
79
  expect(map.get(bar)).toBe(handle);
80
80
  expect(map.has(bar.prototype)).toBe(true);
81
81
 
82
- const b = vm.unwrapResult(vm.evalCode(`({ hoge: 2 })`));
82
+ const b = ctx.unwrapResult(ctx.evalCode(`({ hoge: 2 })`));
83
83
  expect(
84
- vm.dump(
85
- vm.unwrapResult(vm.callFunction(handle, vm.undefined, vm.newNumber(1), b))
86
- )
84
+ ctx.dump(ctx.unwrapResult(ctx.callFunction(handle, ctx.undefined, ctx.newNumber(1), b))),
87
85
  ).toBe(3);
88
86
 
89
87
  b.dispose();
90
88
  dispose();
91
89
  });
92
90
 
91
+ test("promise", async () => {
92
+ const { ctx, marshal, dispose } = await setup();
93
+ const register = fn(
94
+ ctx,
95
+ `promise => { promise.then(d => notify("resolve", d), d => notify("reject", d)); }`,
96
+ );
97
+
98
+ let notified: any;
99
+ ctx
100
+ .newFunction("notify", (...handles) => {
101
+ notified = handles.map(h => ctx.dump(h));
102
+ })
103
+ .consume(h => {
104
+ ctx.setProp(ctx.global, "notify", h);
105
+ });
106
+
107
+ const deferred = newDeferred();
108
+ const handle = marshal(deferred.promise);
109
+ register(undefined, handle);
110
+
111
+ deferred.resolve("foo");
112
+ await deferred.promise;
113
+ expect(ctx.unwrapResult(ctx.runtime.executePendingJobs())).toBe(1);
114
+ expect(notified).toEqual(["resolve", "foo"]);
115
+
116
+ const deferred2 = newDeferred();
117
+ const handle2 = marshal(deferred2.promise);
118
+ register(undefined, handle2);
119
+
120
+ deferred2.reject("bar");
121
+ await expect(deferred2.promise).rejects.toBe("bar");
122
+ expect(ctx.unwrapResult(ctx.runtime.executePendingJobs())).toBe(1);
123
+ expect(notified).toEqual(["reject", "bar"]);
124
+
125
+ register.dispose();
126
+ dispose();
127
+ });
128
+
93
129
  test("class", async () => {
94
- const { vm, map, marshal, dispose } = await setup();
130
+ const { ctx, map, marshal, dispose } = await setup();
95
131
 
96
132
  class A {
97
133
  a: number;
@@ -117,6 +153,7 @@ test("class", async () => {
117
153
  }
118
154
  }
119
155
 
156
+ expect(A.name).toBe("_A"); // class A's name is _A in vitest
120
157
  const handle = marshal(A);
121
158
  if (!map) throw new Error("map is undefined");
122
159
 
@@ -125,41 +162,33 @@ test("class", async () => {
125
162
  expect(map.has(A.prototype)).toBe(true);
126
163
  expect(map.has(A.a)).toBe(true);
127
164
  expect(map.has(A.prototype.hoge)).toBe(true);
128
- expect(
129
- map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.get)
130
- ).toBe(true);
131
- expect(
132
- map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.set)
133
- ).toBe(true);
134
-
135
- expect(vm.typeof(handle)).toBe("function");
136
- expect(vm.dump(vm.getProp(handle, "length"))).toBe(1);
137
- expect(vm.dump(vm.getProp(handle, "name"))).toBe("A");
138
- const staticA = vm.getProp(handle, "a");
139
- expect(instanceOf(vm, staticA, handle)).toBe(true);
140
- expect(vm.dump(vm.getProp(staticA, "a"))).toBe(100);
141
- expect(vm.dump(vm.getProp(staticA, "b"))).toBe("a!");
142
-
143
- const newA = vm.unwrapResult(vm.evalCode(`A => new A("foo")`));
144
- const instance = vm.unwrapResult(vm.callFunction(newA, vm.undefined, handle));
145
- expect(instanceOf(vm, instance, handle)).toBe(true);
146
- expect(vm.dump(vm.getProp(instance, "a"))).toBe(100);
147
- expect(vm.dump(vm.getProp(instance, "b"))).toBe("foo!");
148
- const methodHoge = vm.getProp(instance, "hoge");
149
- expect(vm.dump(vm.unwrapResult(vm.callFunction(methodHoge, instance)))).toBe(
150
- 101
165
+ expect(map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.get)).toBe(true);
166
+ expect(map.has(Object.getOwnPropertyDescriptor(A.prototype, "foo")?.set)).toBe(true);
167
+
168
+ expect(ctx.typeof(handle)).toBe("function");
169
+ expect(ctx.dump(ctx.getProp(handle, "length"))).toBe(1);
170
+ expect(ctx.dump(ctx.getProp(handle, "name"))).toBe("_A");
171
+ const staticA = ctx.getProp(handle, "a");
172
+ expect(instanceOf(ctx, staticA, handle)).toBe(true);
173
+ expect(ctx.dump(ctx.getProp(staticA, "a"))).toBe(100);
174
+ expect(ctx.dump(ctx.getProp(staticA, "b"))).toBe("a!");
175
+
176
+ const newA = ctx.unwrapResult(ctx.evalCode(`A => new A("foo")`));
177
+ const instance = ctx.unwrapResult(ctx.callFunction(newA, ctx.undefined, handle));
178
+ expect(instanceOf(ctx, instance, handle)).toBe(true);
179
+ expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100);
180
+ expect(ctx.dump(ctx.getProp(instance, "b"))).toBe("foo!");
181
+ const methodHoge = ctx.getProp(instance, "hoge");
182
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(methodHoge, instance)))).toBe(101);
183
+ expect(ctx.dump(ctx.getProp(instance, "a"))).toBe(100); // not synced
184
+
185
+ const getter = ctx.unwrapResult(ctx.evalCode(`a => a.foo`));
186
+ const setter = ctx.unwrapResult(ctx.evalCode(`(a, b) => a.foo = b`));
187
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(getter, ctx.undefined, instance)))).toBe(
188
+ "foo!",
151
189
  );
152
- expect(vm.dump(vm.getProp(instance, "a"))).toBe(100); // not synced
153
-
154
- const getter = vm.unwrapResult(vm.evalCode(`a => a.foo`));
155
- const setter = vm.unwrapResult(vm.evalCode(`(a, b) => a.foo = b`));
156
- expect(
157
- vm.dump(vm.unwrapResult(vm.callFunction(getter, vm.undefined, instance)))
158
- ).toBe("foo!");
159
- vm.unwrapResult(
160
- vm.callFunction(setter, vm.undefined, instance, vm.newString("b"))
161
- );
162
- expect(vm.dump(vm.getProp(instance, "b"))).toBe("foo!"); // not synced
190
+ ctx.unwrapResult(ctx.callFunction(setter, ctx.undefined, instance, ctx.newString("b")));
191
+ expect(ctx.dump(ctx.getProp(instance, "b"))).toBe("foo!"); // not synced
163
192
 
164
193
  staticA.dispose();
165
194
  newA.dispose();
@@ -167,19 +196,34 @@ test("class", async () => {
167
196
  methodHoge.dispose();
168
197
  getter.dispose();
169
198
  setter.dispose();
170
- map.dispose();
199
+ dispose();
200
+ });
201
+
202
+ test("date", async () => {
203
+ const { ctx, map, marshal, dispose } = await setup();
204
+
205
+ const date = new Date(2022, 7, 26);
206
+ const handle = marshal(date);
207
+ if (!map) throw new Error("map is undefined");
208
+
209
+ expect(map.size).toBe(1);
210
+ expect(map.get(date)).toBe(handle);
211
+
212
+ expect(ctx.dump(call(ctx, "d => d instanceof Date", undefined, handle))).toBe(true);
213
+ expect(ctx.dump(call(ctx, "d => d.getTime()", undefined, handle))).toBe(date.getTime());
214
+
171
215
  dispose();
172
216
  });
173
217
 
174
218
  test("marshalable", async () => {
175
- const isMarshalable = jest.fn((a: any) => a !== globalThis);
176
- const { vm, marshal, dispose } = await setup({
219
+ const isMarshalable = vi.fn((a: any) => a !== globalThis);
220
+ const { ctx, marshal, dispose } = await setup({
177
221
  isMarshalable,
178
222
  });
179
223
 
180
224
  const handle = marshal({ a: globalThis, b: 1 });
181
225
 
182
- expect(vm.dump(handle)).toEqual({ a: undefined, b: 1 });
226
+ expect(ctx.dump(handle)).toEqual({ a: undefined, b: 1 });
183
227
  expect(isMarshalable).toBeCalledWith(globalThis);
184
228
  expect(isMarshalable).toReturnWith(false);
185
229
 
@@ -187,8 +231,8 @@ test("marshalable", async () => {
187
231
  });
188
232
 
189
233
  test("marshalable json", async () => {
190
- const isMarshalable = jest.fn<"json", [any]>(() => "json");
191
- const { vm, marshal, dispose } = await setup({
234
+ const isMarshalable = vi.fn(() => "json" as const);
235
+ const { ctx, marshal, dispose } = await setup({
192
236
  isMarshalable,
193
237
  });
194
238
 
@@ -199,7 +243,7 @@ test("marshalable json", async () => {
199
243
  };
200
244
  const handle = marshal(target);
201
245
 
202
- expect(vm.dump(handle)).toEqual({
246
+ expect(ctx.dump(handle)).toEqual({
203
247
  a: { d: target.a.d.toISOString(), e: [null, 1, {}] },
204
248
  b: 1,
205
249
  });
@@ -215,25 +259,26 @@ const setup = async ({
215
259
  }: {
216
260
  isMarshalable?: (target: any) => boolean | "json";
217
261
  } = {}) => {
218
- const vm = (await getQuickJS()).createVm();
219
- const map = new VMMap(vm);
262
+ const ctx = (await getQuickJS()).newContext();
263
+ const map = new VMMap(ctx);
220
264
  return {
221
- vm,
265
+ ctx,
222
266
  map,
223
267
  marshal: (v: any) =>
224
268
  marshal(v, {
225
- vm,
226
- unmarshal: (h) => map.getByHandle(h) ?? vm.dump(h),
269
+ ctx: ctx,
270
+ unmarshal: h => map.getByHandle(h) ?? ctx.dump(h),
227
271
  isMarshalable,
228
- pre: (t, h) => {
272
+ pre: (t, d) => {
273
+ const h = handleFrom(d);
229
274
  map.set(t, h);
230
275
  return h;
231
276
  },
232
- find: (t) => map.get(t),
277
+ find: t => map.get(t),
233
278
  }),
234
279
  dispose: () => {
235
280
  map.dispose();
236
- vm.dispose();
281
+ ctx.dispose();
237
282
  },
238
283
  };
239
284
  };
@@ -1,28 +1,31 @@
1
- import { QuickJSHandle, QuickJSVm } from "quickjs-emscripten";
1
+ import type { QuickJSDeferredPromise, QuickJSHandle, QuickJSContext } from "quickjs-emscripten";
2
+
3
+ import marshalCustom, { defaultCustom } from "./custom";
2
4
  import marshalFunction from "./function";
5
+ import marshalJSON from "./json";
3
6
  import marshalObject from "./object";
4
7
  import marshalPrimitive from "./primitive";
5
- import marshalSymbol from "./symbol";
6
- import marshalJSON from "./json";
8
+ import marshalPromise from "./promise";
7
9
 
8
10
  export type Options = {
9
- vm: QuickJSVm;
11
+ ctx: QuickJSContext;
10
12
  unmarshal: (handle: QuickJSHandle) => unknown;
11
13
  isMarshalable?: (target: unknown) => boolean | "json";
12
14
  find: (target: unknown) => QuickJSHandle | undefined;
13
15
  pre: (
14
16
  target: unknown,
15
- handle: QuickJSHandle,
16
- mode: true | "json" | undefined
17
+ handle: QuickJSHandle | QuickJSDeferredPromise,
18
+ mode: true | "json" | undefined,
17
19
  ) => QuickJSHandle | undefined;
18
20
  preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any;
21
+ custom?: Iterable<(obj: unknown, ctx: QuickJSContext) => QuickJSHandle | undefined>;
19
22
  };
20
23
 
21
24
  export function marshal(target: unknown, options: Options): QuickJSHandle {
22
- const { vm, unmarshal, isMarshalable, find, pre } = options;
25
+ const { ctx, unmarshal, isMarshalable, find, pre } = options;
23
26
 
24
27
  {
25
- const primitive = marshalPrimitive(vm, target);
28
+ const primitive = marshalPrimitive(ctx, target);
26
29
  if (primitive) {
27
30
  return primitive;
28
31
  }
@@ -35,21 +38,22 @@ export function marshal(target: unknown, options: Options): QuickJSHandle {
35
38
 
36
39
  const marshalable = isMarshalable?.(target);
37
40
  if (marshalable === false) {
38
- return vm.undefined;
41
+ return ctx.undefined;
39
42
  }
40
43
 
41
- const pre2 = (target: any, handle: QuickJSHandle) =>
44
+ const pre2 = (target: any, handle: QuickJSHandle | QuickJSDeferredPromise) =>
42
45
  pre(target, handle, marshalable);
43
46
  if (marshalable === "json") {
44
- return marshalJSON(vm, target, pre2);
47
+ return marshalJSON(ctx, target, pre2);
45
48
  }
46
49
 
47
50
  const marshal2 = (t: unknown) => marshal(t, options);
48
51
  return (
49
- marshalSymbol(vm, target, pre2) ??
50
- marshalFunction(vm, target, marshal2, unmarshal, pre2, options.preApply) ??
51
- marshalObject(vm, target, marshal2, pre2) ??
52
- vm.undefined
52
+ marshalCustom(ctx, target, pre2, [...defaultCustom, ...(options.custom ?? [])]) ??
53
+ marshalPromise(ctx, target, marshal2, pre2) ??
54
+ marshalFunction(ctx, target, marshal2, unmarshal, pre2, options.preApply) ??
55
+ marshalObject(ctx, target, marshal2, pre2) ??
56
+ ctx.undefined
53
57
  );
54
58
  }
55
59
 
@@ -1,59 +1,57 @@
1
1
  import { getQuickJS } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
4
  import marshalJSON from "./json";
3
5
 
4
6
  test("empty object", async () => {
5
- const vm = (await getQuickJS()).createVm();
6
- const prototypeCheck = vm.unwrapResult(
7
- vm.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
7
+ const ctx = (await getQuickJS()).newContext();
8
+ const prototypeCheck = ctx.unwrapResult(
9
+ ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
8
10
  );
9
11
 
10
12
  const obj = {};
11
- const preMarshal = jest.fn((_, a) => a);
13
+ const preMarshal = vi.fn((_, a) => a);
12
14
 
13
- const handle = marshalJSON(vm, obj, preMarshal);
15
+ const handle = marshalJSON(ctx, obj, preMarshal);
14
16
  if (!handle) throw new Error("handle is undefined");
15
17
 
16
- expect(vm.typeof(handle)).toBe("object");
18
+ expect(ctx.typeof(handle)).toBe("object");
17
19
  expect(preMarshal).toBeCalledTimes(1);
18
20
  expect(preMarshal.mock.calls[0][0]).toBe(obj);
19
21
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
20
- expect(
21
- vm.dump(
22
- vm.unwrapResult(vm.callFunction(prototypeCheck, vm.undefined, handle))
23
- )
24
- ).toBe(true);
22
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
23
+ true,
24
+ );
25
25
 
26
26
  handle.dispose();
27
27
  prototypeCheck.dispose();
28
- vm.dispose();
28
+ ctx.dispose();
29
29
  });
30
30
 
31
31
  test("normal object", async () => {
32
- const vm = (await getQuickJS()).createVm();
33
- const prototypeCheck = vm.unwrapResult(
34
- vm.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`)
32
+ const ctx = (await getQuickJS()).newContext();
33
+ const prototypeCheck = ctx.unwrapResult(
34
+ ctx.evalCode(`o => Object.getPrototypeOf(o) === Object.prototype`),
35
35
  );
36
- const entries = vm.unwrapResult(vm.evalCode(`Object.entries`));
36
+ const entries = ctx.unwrapResult(ctx.evalCode(`Object.entries`));
37
37
 
38
38
  const obj = { a: 100, b: "hoge" };
39
- const preMarshal = jest.fn((_, a) => a);
39
+ const preMarshal = vi.fn((_, a) => a);
40
40
 
41
- const handle = marshalJSON(vm, obj, preMarshal);
41
+ const handle = marshalJSON(ctx, obj, preMarshal);
42
42
  if (!handle) throw new Error("handle is undefined");
43
43
 
44
- expect(vm.typeof(handle)).toBe("object");
45
- expect(vm.getNumber(vm.getProp(handle, "a"))).toBe(100);
46
- expect(vm.getString(vm.getProp(handle, "b"))).toBe("hoge");
44
+ expect(ctx.typeof(handle)).toBe("object");
45
+ expect(ctx.getNumber(ctx.getProp(handle, "a"))).toBe(100);
46
+ expect(ctx.getString(ctx.getProp(handle, "b"))).toBe("hoge");
47
47
  expect(preMarshal).toBeCalledTimes(1);
48
48
  expect(preMarshal.mock.calls[0][0]).toBe(obj);
49
49
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
50
- expect(
51
- vm.dump(
52
- vm.unwrapResult(vm.callFunction(prototypeCheck, vm.undefined, handle))
53
- )
54
- ).toBe(true);
55
- const e = vm.unwrapResult(vm.callFunction(entries, vm.undefined, handle));
56
- expect(vm.dump(e)).toEqual([
50
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(prototypeCheck, ctx.undefined, handle)))).toBe(
51
+ true,
52
+ );
53
+ const e = ctx.unwrapResult(ctx.callFunction(entries, ctx.undefined, handle));
54
+ expect(ctx.dump(e)).toEqual([
57
55
  ["a", 100],
58
56
  ["b", "hoge"],
59
57
  ]);
@@ -62,31 +60,29 @@ test("normal object", async () => {
62
60
  handle.dispose();
63
61
  prototypeCheck.dispose();
64
62
  entries.dispose();
65
- vm.dispose();
63
+ ctx.dispose();
66
64
  });
67
65
 
68
66
  test("array", async () => {
69
- const vm = (await getQuickJS()).createVm();
70
- const isArray = vm.unwrapResult(vm.evalCode(`Array.isArray`));
67
+ const ctx = (await getQuickJS()).newContext();
68
+ const isArray = ctx.unwrapResult(ctx.evalCode(`Array.isArray`));
71
69
 
72
70
  const array = [1, "aa"];
73
- const preMarshal = jest.fn((_, a) => a);
71
+ const preMarshal = vi.fn((_, a) => a);
74
72
 
75
- const handle = marshalJSON(vm, array, preMarshal);
73
+ const handle = marshalJSON(ctx, array, preMarshal);
76
74
  if (!handle) throw new Error("handle is undefined");
77
75
 
78
- expect(vm.typeof(handle)).toBe("object");
79
- expect(vm.getNumber(vm.getProp(handle, 0))).toBe(1);
80
- expect(vm.getString(vm.getProp(handle, 1))).toBe("aa");
81
- expect(vm.getNumber(vm.getProp(handle, "length"))).toBe(2);
76
+ expect(ctx.typeof(handle)).toBe("object");
77
+ expect(ctx.getNumber(ctx.getProp(handle, 0))).toBe(1);
78
+ expect(ctx.getString(ctx.getProp(handle, 1))).toBe("aa");
79
+ expect(ctx.getNumber(ctx.getProp(handle, "length"))).toBe(2);
82
80
  expect(preMarshal).toBeCalledTimes(1);
83
81
  expect(preMarshal.mock.calls[0][0]).toBe(array);
84
82
  expect(preMarshal.mock.calls[0][1] === handle).toBe(true); // avoid freeze
85
- expect(
86
- vm.dump(vm.unwrapResult(vm.callFunction(isArray, vm.undefined, handle)))
87
- ).toBe(true);
83
+ expect(ctx.dump(ctx.unwrapResult(ctx.callFunction(isArray, ctx.undefined, handle)))).toBe(true);
88
84
 
89
85
  handle.dispose();
90
86
  isArray.dispose();
91
- vm.dispose();
87
+ ctx.dispose();
92
88
  });
@@ -1,15 +1,13 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
2
3
  import { json } from "../vmutil";
3
4
 
4
5
  export default function marshalJSON(
5
- vm: QuickJSVm,
6
+ ctx: QuickJSContext,
6
7
  target: unknown,
7
- preMarshal: (
8
- target: unknown,
9
- handle: QuickJSHandle
10
- ) => QuickJSHandle | undefined
8
+ preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined,
11
9
  ): QuickJSHandle {
12
- const raw = json(vm, target);
10
+ const raw = json(ctx, target);
13
11
  const handle = preMarshal(target, raw) ?? raw;
14
12
  return handle;
15
13
  }