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,5 +1,8 @@
1
1
  import { getQuickJS, QuickJSHandle } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
4
  import {
5
+ fn,
3
6
  call,
4
7
  consumeAll,
5
8
  eq,
@@ -8,183 +11,205 @@ import {
8
11
  json,
9
12
  mayConsume,
10
13
  mayConsumeAll,
14
+ handleFrom,
11
15
  } from "./vmutil";
12
16
 
17
+ test("fn", async () => {
18
+ const ctx = (await getQuickJS()).newContext();
19
+
20
+ const f = fn(ctx, "(a, b) => a + b");
21
+ expect(ctx.getNumber(f(undefined, ctx.newNumber(1), ctx.newNumber(2)))).toBe(3);
22
+
23
+ const obj = ctx.newObject();
24
+ ctx.setProp(obj, "a", ctx.newNumber(2));
25
+ const f2 = fn(ctx, "(function() { return this.a + 1; })");
26
+ expect(ctx.getNumber(f2(obj))).toBe(3);
27
+
28
+ obj.dispose();
29
+ expect(f.alive).toBe(true);
30
+ expect(f2.alive).toBe(true);
31
+ f2.dispose();
32
+ f.dispose();
33
+ expect(f.alive).toBe(false);
34
+ expect(f2.alive).toBe(false);
35
+ ctx.dispose();
36
+ });
37
+
13
38
  test("call", async () => {
14
- const quickjs = await getQuickJS();
15
- const vm = quickjs.createVm();
39
+ const ctx = (await getQuickJS()).newContext();
16
40
 
17
41
  expect(
18
- vm.getNumber(
19
- call(vm, "(a, b) => a + b", undefined, vm.newNumber(1), vm.newNumber(2))
20
- )
42
+ ctx.getNumber(call(ctx, "(a, b) => a + b", undefined, ctx.newNumber(1), ctx.newNumber(2))),
21
43
  ).toBe(3);
22
44
 
23
- const obj = vm.newObject();
24
- vm.setProp(obj, "a", vm.newNumber(2));
25
- expect(
26
- vm.getNumber(call(vm, "(function() { return this.a + 1; })", obj))
27
- ).toBe(3);
45
+ const obj = ctx.newObject();
46
+ ctx.setProp(obj, "a", ctx.newNumber(2));
47
+ expect(ctx.getNumber(call(ctx, "(function() { return this.a + 1; })", obj))).toBe(3);
28
48
 
29
49
  obj.dispose();
30
- vm.dispose();
50
+ ctx.dispose();
31
51
  });
32
52
 
33
53
  test("eq", async () => {
34
- const quickjs = await getQuickJS();
35
- const vm = quickjs.createVm();
54
+ const ctx = (await getQuickJS()).newContext();
36
55
 
37
- const math1 = vm.unwrapResult(vm.evalCode("Math"));
38
- const math2 = vm.unwrapResult(vm.evalCode("Math"));
39
- const obj = vm.newObject();
56
+ const math1 = ctx.unwrapResult(ctx.evalCode("Math"));
57
+ const math2 = ctx.unwrapResult(ctx.evalCode("Math"));
58
+ const obj = ctx.newObject();
40
59
  expect(math1 === math2).toBe(false);
41
- expect(eq(vm, math1, math2)).toBe(true);
42
- expect(eq(vm, math1, obj)).toBe(false);
60
+ expect(eq(ctx, math1, math2)).toBe(true);
61
+ expect(eq(ctx, math1, obj)).toBe(false);
43
62
 
44
63
  math1.dispose();
45
64
  math2.dispose();
46
65
  obj.dispose();
47
- vm.dispose();
66
+ ctx.dispose();
48
67
  });
49
68
 
50
69
  test("instanceOf", async () => {
51
- const quickjs = await getQuickJS();
52
- const vm = quickjs.createVm();
70
+ const ctx = (await getQuickJS()).newContext();
53
71
 
54
- const pr = vm.unwrapResult(vm.evalCode("Promise"));
55
- const func = vm.unwrapResult(vm.evalCode("(function() {})"));
56
- const p = vm.unwrapResult(vm.evalCode("Promise.resolve()"));
57
- expect(instanceOf(vm, p, pr)).toBe(true);
58
- expect(instanceOf(vm, p, func)).toBe(false);
72
+ const pr = ctx.unwrapResult(ctx.evalCode("Promise"));
73
+ const func = ctx.unwrapResult(ctx.evalCode("(function() {})"));
74
+ const p = ctx.unwrapResult(ctx.evalCode("Promise.resolve()"));
75
+ expect(instanceOf(ctx, p, pr)).toBe(true);
76
+ expect(instanceOf(ctx, p, func)).toBe(false);
59
77
 
60
78
  p.dispose();
61
79
  pr.dispose();
62
80
  func.dispose();
63
- vm.dispose();
81
+ ctx.dispose();
64
82
  });
65
83
 
66
84
  test("isHandleObject", async () => {
67
- const quickjs = await getQuickJS();
68
- const vm = quickjs.createVm();
69
-
70
- const obj = vm.newObject();
71
- expect(isHandleObject(vm, obj)).toBe(true);
72
- const func = vm.newFunction("", () => {});
73
- expect(isHandleObject(vm, func)).toBe(true);
74
- const array = vm.newArray();
75
- expect(isHandleObject(vm, array)).toBe(true);
76
- const num = vm.newNumber(NaN);
77
- expect(isHandleObject(vm, num)).toBe(false);
85
+ const ctx = (await getQuickJS()).newContext();
86
+
87
+ const obj = ctx.newObject();
88
+ expect(isHandleObject(ctx, obj)).toBe(true);
89
+ const func = ctx.newFunction("", () => {});
90
+ expect(isHandleObject(ctx, func)).toBe(true);
91
+ const array = ctx.newArray();
92
+ expect(isHandleObject(ctx, array)).toBe(true);
93
+ const num = ctx.newNumber(NaN);
94
+ expect(isHandleObject(ctx, num)).toBe(false);
78
95
 
79
96
  obj.dispose();
80
97
  func.dispose();
81
98
  array.dispose();
82
- vm.dispose();
99
+ ctx.dispose();
83
100
  });
84
101
 
85
102
  test("json", async () => {
86
- const quickjs = await getQuickJS();
87
- const vm = quickjs.createVm();
103
+ const ctx = (await getQuickJS()).newContext();
88
104
 
89
- const handle = json(vm, {
105
+ const handle = json(ctx, {
90
106
  hoge: { foo: ["bar"] },
91
107
  });
92
- expect(
93
- vm.dump(call(vm, `a => a.hoge.foo[0] === "bar"`, undefined, handle))
94
- ).toBe(true);
95
- expect(vm.typeof(json(vm, undefined))).toBe("undefined");
108
+ expect(ctx.dump(call(ctx, `a => a.hoge.foo[0] === "bar"`, undefined, handle))).toBe(true);
109
+ expect(ctx.typeof(json(ctx, undefined))).toBe("undefined");
96
110
 
97
111
  handle.dispose();
98
- vm.dispose();
112
+ ctx.dispose();
99
113
  });
100
114
 
101
115
  test("consumeAll", async () => {
102
- const quickjs = await getQuickJS();
103
- const vm = quickjs.createVm();
116
+ const ctx = (await getQuickJS()).newContext();
104
117
 
105
118
  const o = {};
106
119
 
107
- const handles = [vm.newObject(), vm.newObject()];
120
+ const handles = [ctx.newObject(), ctx.newObject()];
108
121
  expect(
109
122
  consumeAll(
110
123
  handles,
111
- jest.fn(() => o)
112
- )
124
+ vi.fn(() => o),
125
+ ),
113
126
  ).toBe(o);
114
- expect(handles.every((h) => !h.alive)).toBe(true);
127
+ expect(handles.every(h => !h.alive)).toBe(true);
115
128
 
116
- const handles2 = [vm.newObject(), vm.newObject()];
129
+ const handles2 = [ctx.newObject(), ctx.newObject()];
117
130
  expect(() =>
118
131
  consumeAll(handles2, () => {
119
132
  throw new Error("qes error");
120
- })
133
+ }),
121
134
  ).toThrow("qes error");
122
- expect(handles2.every((h) => !h.alive)).toBe(true);
135
+ expect(handles2.every(h => !h.alive)).toBe(true);
123
136
 
124
- vm.dispose();
137
+ ctx.dispose();
125
138
  });
126
139
 
127
140
  test("mayConsume", async () => {
128
- const quickjs = await getQuickJS();
129
- const vm = quickjs.createVm();
141
+ const ctx = (await getQuickJS()).newContext();
130
142
 
131
143
  const o = {};
132
144
 
133
- const handle = vm.newArray();
145
+ const handle = ctx.newArray();
134
146
  expect(
135
147
  mayConsume(
136
148
  [handle, false],
137
- jest.fn<any, [QuickJSHandle]>(() => o)
138
- )
149
+ vi.fn(() => o),
150
+ ),
139
151
  ).toBe(o);
140
152
  expect(handle.alive).toBe(true);
141
153
 
142
154
  mayConsume([handle, true], () => {});
143
155
  expect(handle.alive).toBe(false);
144
156
 
145
- const handle2 = vm.newArray();
157
+ const handle2 = ctx.newArray();
146
158
  expect(() =>
147
159
  mayConsume([handle2, true], () => {
148
160
  throw new Error("qes error");
149
- })
161
+ }),
150
162
  ).toThrow("qes error");
151
163
  expect(handle.alive).toBe(false);
152
164
 
153
- vm.dispose();
165
+ ctx.dispose();
154
166
  });
155
167
 
156
168
  test("mayConsumeAll", async () => {
157
- const quickjs = await getQuickJS();
158
- const vm = quickjs.createVm();
169
+ const ctx = (await getQuickJS()).newContext();
159
170
 
160
171
  const o = {};
161
172
 
162
173
  const handles: [QuickJSHandle, boolean][] = [
163
- [vm.newObject(), false],
164
- [vm.newObject(), true],
174
+ [ctx.newObject(), false],
175
+ [ctx.newObject(), true],
165
176
  ];
166
177
  expect(
167
178
  mayConsumeAll(
168
179
  handles,
169
- jest.fn<any, QuickJSHandle[]>(() => o)
170
- )
180
+ vi.fn((..._: any[]) => o),
181
+ ),
171
182
  ).toBe(o);
172
183
  expect(handles[0][0].alive).toBe(true);
173
184
  expect(handles[1][0].alive).toBe(false);
174
185
 
175
186
  const handles2: [QuickJSHandle, boolean][] = [
176
- [vm.newObject(), false],
177
- [vm.newObject(), true],
187
+ [ctx.newObject(), false],
188
+ [ctx.newObject(), true],
178
189
  ];
179
190
  expect(() =>
180
191
  mayConsumeAll(handles2, (..._args) => {
181
192
  throw new Error("qes error");
182
- })
193
+ }),
183
194
  ).toThrow("qes error");
184
195
  expect(handles2[0][0].alive).toBe(true);
185
196
  expect(handles2[1][0].alive).toBe(false);
186
197
 
187
198
  handles[0][0].dispose();
188
199
  handles2[0][0].dispose();
189
- vm.dispose();
200
+ ctx.dispose();
201
+ });
202
+
203
+ test("handleFrom", async () => {
204
+ const ctx = (await getQuickJS()).newContext();
205
+
206
+ const handle = ctx.newObject();
207
+ const promise = ctx.newPromise();
208
+
209
+ expect(handleFrom(handle) === handle).toBe(true);
210
+ expect(handleFrom(promise) === promise.handle).toBe(true);
211
+
212
+ handle.dispose();
213
+ promise.dispose();
214
+ ctx.dispose();
190
215
  });
package/src/vmutil.ts CHANGED
@@ -1,52 +1,61 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type {
2
+ Disposable,
3
+ QuickJSContext,
4
+ QuickJSHandle,
5
+ QuickJSDeferredPromise,
6
+ } from "quickjs-emscripten";
7
+
8
+ export function fn(
9
+ ctx: QuickJSContext,
10
+ code: string,
11
+ ): ((thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]) => QuickJSHandle) & Disposable {
12
+ const handle = ctx.unwrapResult(ctx.evalCode(code));
13
+ const f = (thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]): any => {
14
+ return ctx.unwrapResult(ctx.callFunction(handle, thisArg ?? ctx.undefined, ...args));
15
+ };
16
+ f.dispose = () => handle.dispose();
17
+ f.alive = true;
18
+ Object.defineProperty(f, "alive", {
19
+ get: () => handle.alive,
20
+ });
21
+ return f;
22
+ }
2
23
 
3
24
  export function call(
4
- vm: QuickJSVm,
25
+ ctx: QuickJSContext,
5
26
  code: string,
6
27
  thisArg?: QuickJSHandle,
7
28
  ...args: QuickJSHandle[]
8
29
  ): QuickJSHandle {
9
- return vm.unwrapResult(vm.evalCode(code)).consume((f) => {
10
- if (typeof thisArg === "undefined" && args.length === 0) return f;
11
- return vm.unwrapResult(
12
- vm.callFunction(f, thisArg ?? vm.undefined, ...args)
13
- );
14
- });
30
+ const f = fn(ctx, code);
31
+ try {
32
+ return f(thisArg, ...args);
33
+ } finally {
34
+ f.dispose();
35
+ }
15
36
  }
16
37
 
17
- export function eq(vm: QuickJSVm, a: QuickJSHandle, b: QuickJSHandle): boolean {
18
- return vm.dump(call(vm, "Object.is", undefined, a, b));
38
+ export function eq(ctx: QuickJSContext, a: QuickJSHandle, b: QuickJSHandle): boolean {
39
+ return ctx.dump(call(ctx, "Object.is", undefined, a, b));
19
40
  }
20
41
 
21
- export function instanceOf(
22
- vm: QuickJSVm,
23
- a: QuickJSHandle,
24
- b: QuickJSHandle
25
- ): boolean {
26
- return vm.dump(call(vm, "(a, b) => a instanceof b", undefined, a, b));
42
+ export function instanceOf(ctx: QuickJSContext, a: QuickJSHandle, b: QuickJSHandle): boolean {
43
+ return ctx.dump(call(ctx, "(a, b) => a instanceof b", undefined, a, b));
27
44
  }
28
45
 
29
- export function isHandleObject(vm: QuickJSVm, a: QuickJSHandle): boolean {
30
- return vm.dump(
31
- call(
32
- vm,
33
- `a => typeof a === "object" && a !== null || typeof a === "function"`,
34
- undefined,
35
- a
36
- )
46
+ export function isHandleObject(ctx: QuickJSContext, h: QuickJSHandle): boolean {
47
+ return ctx.dump(
48
+ call(ctx, `a => typeof a === "object" && a !== null || typeof a === "function"`, undefined, h),
37
49
  );
38
50
  }
39
51
 
40
- export function json(vm: QuickJSVm, target: any): QuickJSHandle {
52
+ export function json(ctx: QuickJSContext, target: any): QuickJSHandle {
41
53
  const json = JSON.stringify(target);
42
- if (!json) return vm.undefined;
43
- return call(vm, `JSON.parse`, undefined, vm.newString(json));
54
+ if (!json) return ctx.undefined;
55
+ return call(ctx, `JSON.parse`, undefined, ctx.newString(json));
44
56
  }
45
57
 
46
- export function consumeAll<T extends QuickJSHandle[], K>(
47
- handles: T,
48
- cb: (handles: T) => K
49
- ): K {
58
+ export function consumeAll<T extends QuickJSHandle[], K>(handles: T, cb: (handles: T) => K): K {
50
59
  try {
51
60
  return cb(handles);
52
61
  } finally {
@@ -58,7 +67,7 @@ export function consumeAll<T extends QuickJSHandle[], K>(
58
67
 
59
68
  export function mayConsume<T>(
60
69
  [handle, shouldBeDisposed]: [QuickJSHandle, boolean],
61
- fn: (h: QuickJSHandle) => T
70
+ fn: (h: QuickJSHandle) => T,
62
71
  ) {
63
72
  try {
64
73
  return fn(handle);
@@ -71,10 +80,10 @@ export function mayConsume<T>(
71
80
 
72
81
  export function mayConsumeAll<T, H extends QuickJSHandle[]>(
73
82
  handles: { [P in keyof H]: [QuickJSHandle, boolean] },
74
- fn: (...args: H) => T
83
+ fn: (...args: H) => T,
75
84
  ) {
76
85
  try {
77
- return fn(...(handles.map((h) => h[0]) as H));
86
+ return fn(...(handles.map(h => h[0]) as H));
78
87
  } finally {
79
88
  for (const [handle, shouldBeDisposed] of handles) {
80
89
  if (shouldBeDisposed) {
@@ -83,3 +92,11 @@ export function mayConsumeAll<T, H extends QuickJSHandle[]>(
83
92
  }
84
93
  }
85
94
  }
95
+
96
+ function isQuickJSDeferredPromise(d: Disposable): d is QuickJSDeferredPromise {
97
+ return "handle" in d;
98
+ }
99
+
100
+ export function handleFrom(d: QuickJSDeferredPromise | QuickJSHandle): QuickJSHandle {
101
+ return isQuickJSDeferredPromise(d) ? d.handle : d;
102
+ }