quickjs-emscripten-sync 1.0.0 → 1.3.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 (75) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +303 -0
  3. package/dist/index.d.ts +129 -29
  4. package/dist/quickjs-emscripten-sync.es.js +951 -0
  5. package/dist/quickjs-emscripten-sync.umd.js +64 -0
  6. package/package.json +28 -40
  7. package/src/default.ts +6 -2
  8. package/src/index.test.ts +266 -51
  9. package/src/index.ts +123 -66
  10. package/src/marshal/function.test.ts +11 -10
  11. package/src/marshal/function.ts +3 -3
  12. package/src/marshal/index.test.ts +75 -10
  13. package/src/marshal/index.ts +28 -14
  14. package/src/marshal/json.test.ts +94 -0
  15. package/src/marshal/json.ts +15 -0
  16. package/src/marshal/object.test.ts +49 -6
  17. package/src/marshal/object.ts +2 -2
  18. package/src/marshal/primitive.test.ts +2 -0
  19. package/src/marshal/primitive.ts +8 -2
  20. package/src/marshal/promise.test.ts +86 -0
  21. package/src/marshal/promise.ts +26 -0
  22. package/src/marshal/properties.test.ts +7 -5
  23. package/src/marshal/properties.ts +2 -2
  24. package/src/marshal/symbol.test.ts +3 -1
  25. package/src/unmarshal/function.test.ts +28 -21
  26. package/src/unmarshal/function.ts +31 -23
  27. package/src/unmarshal/index.test.ts +86 -86
  28. package/src/unmarshal/index.ts +5 -4
  29. package/src/unmarshal/object.test.ts +36 -8
  30. package/src/unmarshal/object.ts +8 -4
  31. package/src/unmarshal/primitive.test.ts +2 -0
  32. package/src/unmarshal/primitive.ts +1 -2
  33. package/src/unmarshal/promise.test.ts +44 -0
  34. package/src/unmarshal/promise.ts +40 -0
  35. package/src/unmarshal/properties.test.ts +4 -2
  36. package/src/unmarshal/properties.ts +11 -9
  37. package/src/unmarshal/symbol.test.ts +3 -1
  38. package/src/util.test.ts +22 -5
  39. package/src/util.ts +15 -0
  40. package/src/vmmap.test.ts +22 -0
  41. package/src/vmmap.ts +6 -2
  42. package/src/vmutil.test.ts +116 -8
  43. package/src/vmutil.ts +76 -8
  44. package/src/wrapper.test.ts +44 -31
  45. package/src/wrapper.ts +47 -30
  46. package/dist/default.d.ts +0 -4
  47. package/dist/index.js +0 -8
  48. package/dist/marshal/array.d.ts +0 -2
  49. package/dist/marshal/function.d.ts +0 -2
  50. package/dist/marshal/index.d.ts +0 -11
  51. package/dist/marshal/object.d.ts +0 -2
  52. package/dist/marshal/primitive.d.ts +0 -2
  53. package/dist/marshal/properties.d.ts +0 -2
  54. package/dist/marshal/symbol.d.ts +0 -2
  55. package/dist/quickjs-emscripten-sync.cjs.development.js +0 -1302
  56. package/dist/quickjs-emscripten-sync.cjs.development.js.map +0 -1
  57. package/dist/quickjs-emscripten-sync.cjs.production.min.js +0 -2
  58. package/dist/quickjs-emscripten-sync.cjs.production.min.js.map +0 -1
  59. package/dist/quickjs-emscripten-sync.esm.js +0 -1285
  60. package/dist/quickjs-emscripten-sync.esm.js.map +0 -1
  61. package/dist/unmarshal/array.d.ts +0 -2
  62. package/dist/unmarshal/function.d.ts +0 -2
  63. package/dist/unmarshal/index.d.ts +0 -9
  64. package/dist/unmarshal/object.d.ts +0 -2
  65. package/dist/unmarshal/primitive.d.ts +0 -2
  66. package/dist/unmarshal/properties.d.ts +0 -2
  67. package/dist/unmarshal/symbol.d.ts +0 -2
  68. package/dist/util.d.ts +0 -7
  69. package/dist/vmmap.d.ts +0 -35
  70. package/dist/vmutil.d.ts +0 -7
  71. package/dist/wrapper.d.ts +0 -11
  72. package/src/marshal/array.test.ts +0 -40
  73. package/src/marshal/array.ts +0 -24
  74. package/src/unmarshal/array.test.ts +0 -45
  75. package/src/unmarshal/array.ts +0 -32
package/src/vmmap.test.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { getQuickJS } from "quickjs-emscripten";
2
+ import { expect, test } from "vitest";
3
+
2
4
  import VMMap from "./vmmap";
3
5
  import { call } from "./vmutil";
4
6
 
@@ -55,6 +57,26 @@ test("getByHandle", async () => {
55
57
  vm.dispose();
56
58
  });
57
59
 
60
+ test("keys", async () => {
61
+ const quickjs = await getQuickJS();
62
+ const vm = quickjs.createVm();
63
+
64
+ const target = {};
65
+ const handle = vm.newObject();
66
+ const handle2 = vm.newObject();
67
+
68
+ const map = new VMMap(vm);
69
+ expect(Array.from(map.keys())).toEqual([]);
70
+ map.set(target, handle);
71
+ expect(Array.from(map.keys())).toEqual([target]);
72
+ handle.dispose();
73
+ expect(Array.from(map.keys())).toEqual([target]);
74
+
75
+ handle2.dispose();
76
+ map.dispose();
77
+ vm.dispose();
78
+ });
79
+
58
80
  test("delete", async () => {
59
81
  const quickjs = await getQuickJS();
60
82
  const vm = quickjs.createVm();
package/src/vmmap.ts CHANGED
@@ -44,7 +44,7 @@ export default class VMMap {
44
44
  };
45
45
  }`)
46
46
  )
47
- .consume(fn => this._call(fn, undefined));
47
+ .consume((fn) => this._call(fn, undefined));
48
48
 
49
49
  this._mapGet = vm.getProp(result, "get");
50
50
  this._mapSet = vm.getProp(result, "set");
@@ -84,7 +84,7 @@ export default class VMMap {
84
84
  }
85
85
  }
86
86
 
87
- this.vm.newNumber(counter).consume(c => {
87
+ this.vm.newNumber(counter).consume((c) => {
88
88
  this._call(
89
89
  this._mapSet,
90
90
  undefined,
@@ -144,6 +144,10 @@ export default class VMMap {
144
144
  return typeof this.getByHandle(handle) !== "undefined";
145
145
  }
146
146
 
147
+ keys() {
148
+ return this._map1.keys();
149
+ }
150
+
147
151
  delete(key: any, dispose?: boolean) {
148
152
  const num = this._map1.get(key) ?? this._map2.get(key);
149
153
  if (typeof num === "undefined") return;
@@ -1,13 +1,41 @@
1
- import { getQuickJS } from "quickjs-emscripten";
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,
6
9
  instanceOf,
7
10
  isHandleObject,
8
- send,
11
+ json,
12
+ mayConsume,
13
+ mayConsumeAll,
14
+ handleFrom,
9
15
  } from "./vmutil";
10
16
 
17
+ test("fn", async () => {
18
+ const quickjs = await getQuickJS();
19
+ const vm = quickjs.createVm();
20
+
21
+ const f = fn(vm, "(a, b) => a + b");
22
+ expect(vm.getNumber(f(undefined, vm.newNumber(1), vm.newNumber(2)))).toBe(3);
23
+
24
+ const obj = vm.newObject();
25
+ vm.setProp(obj, "a", vm.newNumber(2));
26
+ const f2 = fn(vm, "(function() { return this.a + 1; })");
27
+ expect(vm.getNumber(f2(obj))).toBe(3);
28
+
29
+ obj.dispose();
30
+ expect(f.alive).toBe(true);
31
+ expect(f2.alive).toBe(true);
32
+ f2.dispose();
33
+ f.dispose();
34
+ expect(f.alive).toBe(false);
35
+ expect(f2.alive).toBe(false);
36
+ vm.dispose();
37
+ });
38
+
11
39
  test("call", async () => {
12
40
  const quickjs = await getQuickJS();
13
41
  const vm = quickjs.createVm();
@@ -80,17 +108,17 @@ test("isHandleObject", async () => {
80
108
  vm.dispose();
81
109
  });
82
110
 
83
- test("send", async () => {
111
+ test("json", async () => {
84
112
  const quickjs = await getQuickJS();
85
113
  const vm = quickjs.createVm();
86
114
 
87
- const handle = send(vm, {
115
+ const handle = json(vm, {
88
116
  hoge: { foo: ["bar"] },
89
117
  });
90
118
  expect(
91
119
  vm.dump(call(vm, `a => a.hoge.foo[0] === "bar"`, undefined, handle))
92
120
  ).toBe(true);
93
- expect(vm.typeof(send(vm, undefined))).toBe("undefined");
121
+ expect(vm.typeof(json(vm, undefined))).toBe("undefined");
94
122
 
95
123
  handle.dispose();
96
124
  vm.dispose();
@@ -106,10 +134,10 @@ test("consumeAll", async () => {
106
134
  expect(
107
135
  consumeAll(
108
136
  handles,
109
- jest.fn(_ => o)
137
+ vi.fn(() => o)
110
138
  )
111
139
  ).toBe(o);
112
- expect(handles.every(h => !h.alive)).toBe(true);
140
+ expect(handles.every((h) => !h.alive)).toBe(true);
113
141
 
114
142
  const handles2 = [vm.newObject(), vm.newObject()];
115
143
  expect(() =>
@@ -117,7 +145,87 @@ test("consumeAll", async () => {
117
145
  throw new Error("qes error");
118
146
  })
119
147
  ).toThrow("qes error");
120
- expect(handles2.every(h => !h.alive)).toBe(true);
148
+ expect(handles2.every((h) => !h.alive)).toBe(true);
149
+
150
+ vm.dispose();
151
+ });
121
152
 
153
+ test("mayConsume", async () => {
154
+ const quickjs = await getQuickJS();
155
+ const vm = quickjs.createVm();
156
+
157
+ const o = {};
158
+
159
+ const handle = vm.newArray();
160
+ expect(
161
+ mayConsume(
162
+ [handle, false],
163
+ vi.fn(() => o)
164
+ )
165
+ ).toBe(o);
166
+ expect(handle.alive).toBe(true);
167
+
168
+ mayConsume([handle, true], () => {});
169
+ expect(handle.alive).toBe(false);
170
+
171
+ const handle2 = vm.newArray();
172
+ expect(() =>
173
+ mayConsume([handle2, true], () => {
174
+ throw new Error("qes error");
175
+ })
176
+ ).toThrow("qes error");
177
+ expect(handle.alive).toBe(false);
178
+
179
+ vm.dispose();
180
+ });
181
+
182
+ test("mayConsumeAll", async () => {
183
+ const quickjs = await getQuickJS();
184
+ const vm = quickjs.createVm();
185
+
186
+ const o = {};
187
+
188
+ const handles: [QuickJSHandle, boolean][] = [
189
+ [vm.newObject(), false],
190
+ [vm.newObject(), true],
191
+ ];
192
+ expect(
193
+ mayConsumeAll(
194
+ handles,
195
+ vi.fn((..._: any[]) => o)
196
+ )
197
+ ).toBe(o);
198
+ expect(handles[0][0].alive).toBe(true);
199
+ expect(handles[1][0].alive).toBe(false);
200
+
201
+ const handles2: [QuickJSHandle, boolean][] = [
202
+ [vm.newObject(), false],
203
+ [vm.newObject(), true],
204
+ ];
205
+ expect(() =>
206
+ mayConsumeAll(handles2, (..._args) => {
207
+ throw new Error("qes error");
208
+ })
209
+ ).toThrow("qes error");
210
+ expect(handles2[0][0].alive).toBe(true);
211
+ expect(handles2[1][0].alive).toBe(false);
212
+
213
+ handles[0][0].dispose();
214
+ handles2[0][0].dispose();
215
+ vm.dispose();
216
+ });
217
+
218
+ test("handleFrom", async () => {
219
+ const quickjs = await getQuickJS();
220
+ const vm = quickjs.createVm();
221
+
222
+ const handle = vm.newObject();
223
+ const promise = vm.newPromise();
224
+
225
+ expect(handleFrom(handle) === handle).toBe(true);
226
+ expect(handleFrom(promise) === promise.handle).toBe(true);
227
+
228
+ handle.dispose();
229
+ promise.dispose();
122
230
  vm.dispose();
123
231
  });
package/src/vmutil.ts CHANGED
@@ -1,4 +1,34 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type {
2
+ Disposable,
3
+ QuickJSVm,
4
+ QuickJSHandle,
5
+ QuickJSDeferredPromise,
6
+ } from "quickjs-emscripten";
7
+
8
+ export function fn(
9
+ vm: QuickJSVm,
10
+ code: string
11
+ ): ((
12
+ thisArg: QuickJSHandle | undefined,
13
+ ...args: QuickJSHandle[]
14
+ ) => QuickJSHandle) &
15
+ Disposable {
16
+ const handle = vm.unwrapResult(vm.evalCode(code));
17
+ const f = (
18
+ thisArg: QuickJSHandle | undefined,
19
+ ...args: QuickJSHandle[]
20
+ ): any => {
21
+ return vm.unwrapResult(
22
+ vm.callFunction(handle, thisArg ?? vm.undefined, ...args)
23
+ );
24
+ };
25
+ f.dispose = () => handle.dispose();
26
+ f.alive = true;
27
+ Object.defineProperty(f, "alive", {
28
+ get: () => handle.alive,
29
+ });
30
+ return f;
31
+ }
2
32
 
3
33
  export function call(
4
34
  vm: QuickJSVm,
@@ -6,12 +36,12 @@ export function call(
6
36
  thisArg?: QuickJSHandle,
7
37
  ...args: QuickJSHandle[]
8
38
  ): 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
- });
39
+ const f = fn(vm, code);
40
+ try {
41
+ return f(thisArg, ...args);
42
+ } finally {
43
+ f.dispose();
44
+ }
15
45
  }
16
46
 
17
47
  export function eq(vm: QuickJSVm, a: QuickJSHandle, b: QuickJSHandle): boolean {
@@ -37,7 +67,7 @@ export function isHandleObject(vm: QuickJSVm, a: QuickJSHandle): boolean {
37
67
  );
38
68
  }
39
69
 
40
- export function send(vm: QuickJSVm, target: any): QuickJSHandle {
70
+ export function json(vm: QuickJSVm, target: any): QuickJSHandle {
41
71
  const json = JSON.stringify(target);
42
72
  if (!json) return vm.undefined;
43
73
  return call(vm, `JSON.parse`, undefined, vm.newString(json));
@@ -55,3 +85,41 @@ export function consumeAll<T extends QuickJSHandle[], K>(
55
85
  }
56
86
  }
57
87
  }
88
+
89
+ export function mayConsume<T>(
90
+ [handle, shouldBeDisposed]: [QuickJSHandle, boolean],
91
+ fn: (h: QuickJSHandle) => T
92
+ ) {
93
+ try {
94
+ return fn(handle);
95
+ } finally {
96
+ if (shouldBeDisposed) {
97
+ handle.dispose();
98
+ }
99
+ }
100
+ }
101
+
102
+ export function mayConsumeAll<T, H extends QuickJSHandle[]>(
103
+ handles: { [P in keyof H]: [QuickJSHandle, boolean] },
104
+ fn: (...args: H) => T
105
+ ) {
106
+ try {
107
+ return fn(...(handles.map((h) => h[0]) as H));
108
+ } finally {
109
+ for (const [handle, shouldBeDisposed] of handles) {
110
+ if (shouldBeDisposed) {
111
+ handle.dispose();
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ function isQuickJSDeferredPromise(d: Disposable): d is QuickJSDeferredPromise {
118
+ return "handle" in d;
119
+ }
120
+
121
+ export function handleFrom(
122
+ d: QuickJSDeferredPromise | QuickJSHandle
123
+ ): QuickJSHandle {
124
+ return isQuickJSDeferredPromise(d) ? d.handle : d;
125
+ }
@@ -1,4 +1,6 @@
1
1
  import { QuickJSHandle, getQuickJS } from "quickjs-emscripten";
2
+ import { expect, test, vi } from "vitest";
3
+
2
4
  import {
3
5
  wrap,
4
6
  unwrap,
@@ -8,7 +10,7 @@ import {
8
10
  isHandleWrapped,
9
11
  SyncMode,
10
12
  } from "./wrapper";
11
- import { call, eq, send } from "./vmutil";
13
+ import { call, eq, json } from "./vmutil";
12
14
 
13
15
  test("wrap, unwrap, isWrapped", async () => {
14
16
  const vm = (await getQuickJS()).createVm();
@@ -16,8 +18,8 @@ test("wrap, unwrap, isWrapped", async () => {
16
18
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
17
19
  const proxyKeySymbol = Symbol();
18
20
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
19
- const marshal = jest.fn();
20
- const syncMode = jest.fn();
21
+ const marshal = vi.fn();
22
+ const syncMode = vi.fn();
21
23
 
22
24
  expect(isWrapped(target, proxyKeySymbol)).toBe(false);
23
25
  expect(unwrap(target, proxyKeySymbol)).toBe(target);
@@ -51,8 +53,8 @@ test("wrap without sync", async () => {
51
53
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
52
54
  const proxyKeySymbol = Symbol();
53
55
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
54
- const marshal = jest.fn();
55
- const syncMode = jest.fn();
56
+ const marshal = vi.fn();
57
+ const syncMode = vi.fn();
56
58
 
57
59
  const wrapped = wrap(
58
60
  vm,
@@ -78,6 +80,9 @@ test("wrap without sync", async () => {
78
80
  proxyKeySymbolHandle.dispose();
79
81
  handle.dispose();
80
82
  vm.dispose();
83
+
84
+ wrapped.a = 3; // no error even if vm is disposed
85
+ expect(wrapped.a).toBe(3);
81
86
  });
82
87
 
83
88
  test("wrap with both sync", async () => {
@@ -86,10 +91,11 @@ test("wrap with both sync", async () => {
86
91
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
87
92
  const proxyKeySymbol = Symbol();
88
93
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
89
- const marshal = jest.fn(
90
- (t: any): QuickJSHandle => (t === wrapped ? handle : send(vm, t))
91
- );
92
- const syncMode = jest.fn((): SyncMode => "both");
94
+ const marshal = vi.fn((t: any): [QuickJSHandle, boolean] => [
95
+ t === wrapped ? handle : json(vm, t),
96
+ false,
97
+ ]);
98
+ const syncMode = vi.fn((): SyncMode => "both");
93
99
 
94
100
  const wrapped = wrap(
95
101
  vm,
@@ -121,6 +127,9 @@ test("wrap with both sync", async () => {
121
127
  proxyKeySymbolHandle.dispose();
122
128
  handle.dispose();
123
129
  vm.dispose();
130
+
131
+ wrapped.a = 3; // no error even if vm is disposed
132
+ expect(wrapped.a).toBe(3);
124
133
  });
125
134
 
126
135
  test("wrap with vm sync", async () => {
@@ -129,10 +138,11 @@ test("wrap with vm sync", async () => {
129
138
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
130
139
  const proxyKeySymbol = Symbol();
131
140
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
132
- const marshal = jest.fn(
133
- (t: any): QuickJSHandle => (t === wrapped ? handle : send(vm, t))
134
- );
135
- const syncMode = jest.fn((): SyncMode => "vm");
141
+ const marshal = vi.fn((t: any): [QuickJSHandle, boolean] => [
142
+ t === wrapped ? handle : json(vm, t),
143
+ false,
144
+ ]);
145
+ const syncMode = vi.fn((): SyncMode => "vm");
136
146
 
137
147
  const wrapped = wrap(
138
148
  vm,
@@ -164,6 +174,9 @@ test("wrap with vm sync", async () => {
164
174
  proxyKeySymbolHandle.dispose();
165
175
  handle.dispose();
166
176
  vm.dispose();
177
+
178
+ wrapped.a = 3; // no error even after vm is disposed
179
+ expect(wrapped.a).toBe(1); // vm mode cannot modify obj in host
167
180
  });
168
181
 
169
182
  test("wrapHandle, unwrapHandle, isHandleWrapped", async () => {
@@ -172,8 +185,8 @@ test("wrapHandle, unwrapHandle, isHandleWrapped", async () => {
172
185
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
173
186
  const proxyKeySymbol = Symbol();
174
187
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
175
- const unmarshal = jest.fn();
176
- const syncMode = jest.fn();
188
+ const unmarshal = vi.fn();
189
+ const syncMode = vi.fn();
177
190
 
178
191
  expect(isHandleWrapped(vm, handle, proxyKeySymbolHandle)).toBe(false);
179
192
  expect(unwrapHandle(vm, handle, proxyKeySymbolHandle)).toEqual([
@@ -197,7 +210,7 @@ test("wrapHandle, unwrapHandle, isHandleWrapped", async () => {
197
210
 
198
211
  const [handle2, unwrapped2] = unwrapHandle(vm, wrapped, proxyKeySymbolHandle);
199
212
  expect(unwrapped2).toBe(true);
200
- handle2.consume(h => {
213
+ handle2.consume((h) => {
201
214
  expect(eq(vm, handle, h)).toBe(true);
202
215
  });
203
216
 
@@ -223,10 +236,10 @@ test("wrapHandle without sync", async () => {
223
236
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
224
237
  const proxyKeySymbol = Symbol();
225
238
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
226
- const unmarshal = jest.fn((h: QuickJSHandle) =>
239
+ const unmarshal = vi.fn((h: QuickJSHandle) =>
227
240
  wrapped && eq(vm, h, wrapped) ? target : vm.dump(h)
228
241
  );
229
- const syncMode = jest.fn();
242
+ const syncMode = vi.fn();
230
243
 
231
244
  const [wrapped, w] = wrapHandle(
232
245
  vm,
@@ -262,10 +275,10 @@ test("wrapHandle with both sync", async () => {
262
275
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
263
276
  const proxyKeySymbol = Symbol();
264
277
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
265
- const unmarshal = jest.fn((h: QuickJSHandle) => {
278
+ const unmarshal = vi.fn((h: QuickJSHandle) => {
266
279
  return wrapped && eq(vm, h, wrapped) ? target : vm.dump(h);
267
280
  });
268
- const syncMode = jest.fn((): SyncMode => "both");
281
+ const syncMode = vi.fn((): SyncMode => "both");
269
282
 
270
283
  const [wrapped, w] = wrapHandle(
271
284
  vm,
@@ -314,10 +327,10 @@ test("wrapHandle with host sync", async () => {
314
327
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
315
328
  const proxyKeySymbol = Symbol();
316
329
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
317
- const unmarshal = jest.fn((handle: QuickJSHandle) =>
330
+ const unmarshal = vi.fn((handle: QuickJSHandle) =>
318
331
  wrapped && eq(vm, handle, wrapped) ? target : vm.dump(handle)
319
332
  );
320
- const syncMode = jest.fn((): SyncMode => "host");
333
+ const syncMode = vi.fn((): SyncMode => "host");
321
334
 
322
335
  const [wrapped, w] = wrapHandle(
323
336
  vm,
@@ -359,14 +372,14 @@ test("wrap and wrapHandle", async () => {
359
372
  const handle = vm.unwrapResult(vm.evalCode(`({ a: 1 })`));
360
373
  const proxyKeySymbol = Symbol();
361
374
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
362
- const marshal = jest.fn(
363
- (t: any): QuickJSHandle =>
364
- wrappedHandle && t === wrapped ? wrappedHandle : send(vm, t)
365
- );
366
- const unmarshal = jest.fn((handle: QuickJSHandle) =>
375
+ const marshal = vi.fn((t: any): [QuickJSHandle, boolean] => [
376
+ wrappedHandle && t === wrapped ? wrappedHandle : json(vm, t),
377
+ false,
378
+ ]);
379
+ const unmarshal = vi.fn((handle: QuickJSHandle) =>
367
380
  wrappedHandle && eq(vm, handle, wrappedHandle) ? wrapped : vm.dump(handle)
368
381
  );
369
- const syncMode = jest.fn((): SyncMode => "both");
382
+ const syncMode = vi.fn((): SyncMode => "both");
370
383
 
371
384
  const wrapped = wrap(
372
385
  vm,
@@ -424,7 +437,7 @@ test("non object", async () => {
424
437
  const proxyKeySymbolHandle = vm.unwrapResult(vm.evalCode(`Symbol()`));
425
438
 
426
439
  expect(
427
- wrap(vm, target, proxyKeySymbol, proxyKeySymbolHandle, jest.fn(), jest.fn())
440
+ wrap(vm, target, proxyKeySymbol, proxyKeySymbolHandle, vi.fn(), vi.fn())
428
441
  ).toBe(undefined);
429
442
 
430
443
  expect(
@@ -433,8 +446,8 @@ test("non object", async () => {
433
446
  handle,
434
447
  proxyKeySymbol,
435
448
  proxyKeySymbolHandle,
436
- jest.fn(),
437
- jest.fn()
449
+ vi.fn(),
450
+ vi.fn()
438
451
  )
439
452
  ).toEqual([undefined, false]);
440
453
 
package/src/wrapper.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
2
  import { isObject } from "./util";
3
- import { call, isHandleObject, consumeAll } from "./vmutil";
3
+ import { call, isHandleObject, consumeAll, mayConsumeAll } from "./vmutil";
4
4
 
5
5
  export type SyncMode = "both" | "vm" | "host";
6
6
 
@@ -11,7 +11,7 @@ export function wrap<T = any>(
11
11
  target: T,
12
12
  proxyKeySymbol: symbol,
13
13
  proxyKeySymbolHandle: QuickJSHandle,
14
- marshal: (target: any) => QuickJSHandle,
14
+ marshal: (target: any) => [QuickJSHandle, boolean],
15
15
  syncMode?: (target: T) => SyncMode | undefined
16
16
  ): Wrapped<T> | undefined {
17
17
  if (!isObject(target)) return undefined;
@@ -24,39 +24,56 @@ export function wrap<T = any>(
24
24
  set(obj, key, value, receiver) {
25
25
  const v = unwrap(value, proxyKeySymbol);
26
26
  const sync = syncMode?.(receiver) ?? "host";
27
- if (sync === "vm" || Reflect.set(obj, key, v, receiver)) {
28
- if (sync === "host") return true;
29
- const [handle2, unwrapped] = unwrapHandle(
30
- vm,
31
- marshal(receiver),
32
- proxyKeySymbolHandle
33
- );
34
- if (unwrapped) {
35
- handle2.consume(h => vm.setProp(h, marshal(key), marshal(v)));
36
- } else {
37
- vm.setProp(handle2, marshal(key), marshal(v));
27
+ if (
28
+ (sync !== "vm" && !Reflect.set(obj, key, v, receiver)) ||
29
+ sync === "host" ||
30
+ !vm.alive
31
+ )
32
+ return true;
33
+
34
+ mayConsumeAll(
35
+ [marshal(receiver), marshal(key), marshal(v)],
36
+ (receiverHandle, keyHandle, valueHandle) => {
37
+ const [handle2, unwrapped] = unwrapHandle(
38
+ vm,
39
+ receiverHandle,
40
+ proxyKeySymbolHandle
41
+ );
42
+ if (unwrapped) {
43
+ handle2.consume((h) => vm.setProp(h, keyHandle, valueHandle));
44
+ } else {
45
+ vm.setProp(handle2, keyHandle, valueHandle);
46
+ }
38
47
  }
39
- }
48
+ );
49
+
40
50
  return true;
41
51
  },
42
52
  deleteProperty(obj, key) {
43
53
  const sync = syncMode?.(rec) ?? "host";
44
- const [handle2, unwrapped] = unwrapHandle(
45
- vm,
46
- marshal(rec),
47
- proxyKeySymbolHandle
48
- );
49
- if (sync === "vm" || Reflect.deleteProperty(obj, key)) {
50
- if (sync === "host") return true;
51
- if (unwrapped) {
52
- handle2.consume(h =>
53
- call(vm, `(a, b) => delete a[b]`, undefined, h, marshal(key))
54
+ return mayConsumeAll(
55
+ [marshal(rec), marshal(key)],
56
+ (recHandle, keyHandle) => {
57
+ const [handle2, unwrapped] = unwrapHandle(
58
+ vm,
59
+ recHandle,
60
+ proxyKeySymbolHandle
54
61
  );
55
- } else {
56
- call(vm, `(a, b) => delete a[b]`, undefined, handle2, marshal(key));
62
+
63
+ if (sync === "vm" || Reflect.deleteProperty(obj, key)) {
64
+ if (sync === "host" || !vm.alive) return true;
65
+
66
+ if (unwrapped) {
67
+ handle2.consume((h) =>
68
+ call(vm, `(a, b) => delete a[b]`, undefined, h, keyHandle)
69
+ );
70
+ } else {
71
+ call(vm, `(a, b) => delete a[b]`, undefined, handle2, keyHandle);
72
+ }
73
+ }
74
+ return true;
57
75
  }
58
- }
59
- return true;
76
+ );
60
77
  },
61
78
  }) as Wrapped<T>;
62
79
  return rec;
@@ -75,7 +92,7 @@ export function wrapHandle(
75
92
 
76
93
  return consumeAll(
77
94
  [
78
- vm.newFunction("getSyncMode", h => {
95
+ vm.newFunction("getSyncMode", (h) => {
79
96
  const res = syncMode?.(unmarshal(h));
80
97
  if (typeof res === "string") return vm.newString(res);
81
98
  return vm.undefined;
@@ -95,7 +112,7 @@ export function wrapHandle(
95
112
  delete unwrap(target, proxyKeySymbol)[key];
96
113
  }),
97
114
  ],
98
- args => [
115
+ (args) => [
99
116
  call(
100
117
  vm,
101
118
  `(target, sym, getSyncMode, setter, deleter) => {
package/dist/default.d.ts DELETED
@@ -1,4 +0,0 @@
1
- /**
2
- * Default value of registeredObjects option of the Arena class constructor.
3
- */
4
- export declare const defaultRegisteredObjects: [any, string][];
package/dist/index.js DELETED
@@ -1,8 +0,0 @@
1
-
2
- 'use strict'
3
-
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./quickjs-emscripten-sync.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./quickjs-emscripten-sync.cjs.development.js')
8
- }
@@ -1,2 +0,0 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
- export default function marshalArray(vm: QuickJSVm, target: unknown, marshal: (target: any) => QuickJSHandle, preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined): QuickJSHandle | undefined;
@@ -1,2 +0,0 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
- export default function marshalFunction(vm: QuickJSVm, target: unknown, marshal: (target: unknown) => QuickJSHandle, unmarshal: (handle: QuickJSHandle) => unknown, preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined, preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any): QuickJSHandle | undefined;
@@ -1,11 +0,0 @@
1
- import { QuickJSHandle, QuickJSVm } from "quickjs-emscripten";
2
- export declare type Options = {
3
- vm: QuickJSVm;
4
- unmarshal: (handle: QuickJSHandle) => unknown;
5
- isMarshalable?: (target: unknown) => boolean;
6
- find: (target: unknown) => QuickJSHandle | undefined;
7
- pre: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined;
8
- preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any;
9
- };
10
- export declare function marshal(target: unknown, options: Options): QuickJSHandle;
11
- export default marshal;
@@ -1,2 +0,0 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
- export default function marshalObject(vm: QuickJSVm, target: unknown, marshal: (target: unknown) => QuickJSHandle, preMarshal: (target: unknown, handle: QuickJSHandle) => QuickJSHandle | undefined): QuickJSHandle | undefined;
@@ -1,2 +0,0 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
2
- export default function marshalPrimitive(vm: QuickJSVm, target: unknown): QuickJSHandle | undefined;