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