quickjs-emscripten-sync 1.3.0 → 1.5.1

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