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/index.test.ts CHANGED
@@ -1,21 +1,109 @@
1
1
  import { getQuickJS } from "quickjs-emscripten";
2
- import Arena from ".";
2
+ import { describe, expect, test, vi } from "vitest";
3
+
4
+ import { Arena } from ".";
5
+
6
+ describe("readme", () => {
7
+ test("first", async () => {
8
+ class Cls {
9
+ field = 0;
10
+
11
+ method() {
12
+ return ++this.field;
13
+ }
14
+ }
15
+
16
+ const vm = (await getQuickJS()).createVm();
17
+ const arena = new Arena(vm, { isMarshalable: true });
18
+
19
+ // We can pass objects to the VM and run code safely
20
+ const exposed = {
21
+ Cls,
22
+ cls: new Cls(),
23
+ syncedCls: arena.sync(new Cls()),
24
+ };
25
+ arena.expose(exposed);
26
+
27
+ expect(arena.evalCode(`cls instanceof Cls`)).toBe(true);
28
+ expect(arena.evalCode(`cls.field`)).toBe(0);
29
+ expect(arena.evalCode(`cls.method()`)).toBe(1);
30
+ expect(arena.evalCode(`cls.field`)).toBe(1);
31
+
32
+ expect(arena.evalCode(`syncedCls.field`)).toBe(0);
33
+ expect(exposed.syncedCls.method()).toBe(1);
34
+ expect(arena.evalCode(`syncedCls.field`)).toBe(1);
35
+
36
+ arena.dispose();
37
+ vm.dispose();
38
+ });
39
+
40
+ test("usage", async () => {
41
+ const quickjs = await getQuickJS();
42
+ const vm = quickjs.createVm();
43
+
44
+ // init Arena
45
+ // ⚠️ Marshaling is opt-in for security reasons.
46
+ // ⚠️ Be careful when activating marshalling.
47
+ const arena = new Arena(vm, { isMarshalable: true });
48
+
49
+ // expose objects as global objects in QuickJS VM
50
+ const log = vi.fn();
51
+ arena.expose({
52
+ console: { log },
53
+ });
54
+ arena.evalCode(`console.log("hello, world");`); // run console.log
55
+ expect(log).toBeCalledWith("hello, world");
56
+ arena.evalCode(`1 + 1`); // 2
57
+
58
+ // expose objects but also enable sync
59
+ const data = arena.sync({ hoge: "foo" });
60
+ arena.expose({ data });
61
+
62
+ arena.evalCode(`data.hoge = "bar"`);
63
+ // eval code and operations to exposed objects are automatically synced
64
+ expect(data.hoge).toBe("bar");
65
+ data.hoge = "changed!";
66
+ expect(arena.evalCode(`data.hoge`)).toBe("changed!");
67
+
68
+ // Don't forget calling arena.dispose() before disposing QuickJS VM!
69
+ arena.dispose();
70
+ vm.dispose();
71
+ });
72
+ });
3
73
 
4
74
  describe("evalCode", () => {
5
75
  test("simple object and function", async () => {
6
76
  const vm = (await getQuickJS()).createVm();
7
- const arena = new Arena(vm);
77
+ const arena = new Arena(vm, { isMarshalable: true });
8
78
 
9
79
  const result = arena.evalCode(
10
- `({ a: 1, b: a => Math.floor(a), c: () => { throw new Error("hoge") } })`
80
+ `({
81
+ a: 1,
82
+ b: a => Math.floor(a),
83
+ c: () => { throw new Error("hoge") },
84
+ d: (yourFavoriteNumber) => ({
85
+ myFavoriteNumber: 42,
86
+ yourFavoriteNumber,
87
+ }),
88
+ get e() {
89
+ return { a: 1 };
90
+ }
91
+ })`
11
92
  );
12
93
  expect(result).toEqual({
13
94
  a: 1,
14
95
  b: expect.any(Function),
15
96
  c: expect.any(Function),
97
+ d: expect.any(Function),
98
+ e: { a: 1 },
16
99
  });
17
100
  expect(result.b(1.1)).toBe(1);
18
101
  expect(() => result.c()).toThrow("hoge");
102
+ expect(result.d(1)).toStrictEqual({
103
+ myFavoriteNumber: 42,
104
+ yourFavoriteNumber: 1,
105
+ });
106
+ expect(result.e).toStrictEqual({ a: 1 });
19
107
 
20
108
  arena.dispose();
21
109
  vm.dispose();
@@ -23,7 +111,7 @@ describe("evalCode", () => {
23
111
 
24
112
  test("Math", async () => {
25
113
  const vm = (await getQuickJS()).createVm();
26
- const arena = new Arena(vm);
114
+ const arena = new Arena(vm, { isMarshalable: true });
27
115
 
28
116
  const VMMath = arena.evalCode(`Math`) as Math;
29
117
  expect(VMMath.floor(1.1)).toBe(1);
@@ -34,7 +122,7 @@ describe("evalCode", () => {
34
122
 
35
123
  test("class", async () => {
36
124
  const vm = (await getQuickJS()).createVm();
37
- const arena = new Arena(vm);
125
+ const arena = new Arena(vm, { isMarshalable: true });
38
126
 
39
127
  const instance = arena.evalCode(`{
40
128
  globalThis.Cls = class D {
@@ -45,7 +133,7 @@ describe("evalCode", () => {
45
133
  return ++this.a;
46
134
  }
47
135
  };
48
-
136
+
49
137
  new Cls(100);
50
138
  }`);
51
139
  const Cls = arena.evalCode(`globalThis.Cls`);
@@ -60,7 +148,7 @@ describe("evalCode", () => {
60
148
 
61
149
  test("obj", async () => {
62
150
  const vm = (await getQuickJS()).createVm();
63
- const arena = new Arena(vm);
151
+ const arena = new Arena(vm, { isMarshalable: true });
64
152
 
65
153
  const obj = arena.evalCode(`globalThis.AAA = { a: 1 }`);
66
154
 
@@ -78,21 +166,35 @@ describe("evalCode", () => {
78
166
  describe("expose without sync", () => {
79
167
  test("simple object and function", async () => {
80
168
  const vm = (await getQuickJS()).createVm();
81
- const arena = new Arena(vm);
169
+ const arena = new Arena(vm, { isMarshalable: true });
82
170
 
83
- arena.expose({
84
- obj: {
85
- a: 1,
86
- b: (a: number) => Math.floor(a),
87
- c: () => {
88
- throw new Error("hoge");
89
- },
171
+ const obj = {
172
+ a: 1,
173
+ b: (a: number) => Math.floor(a),
174
+ c: () => {
175
+ throw new Error("hoge");
176
+ },
177
+ d: (yourFavoriteNumber: number) => ({
178
+ myFavoriteNumber: 42,
179
+ yourFavoriteNumber,
180
+ }),
181
+ get e() {
182
+ return { a: 1 };
90
183
  },
184
+ };
185
+ arena.expose({
186
+ obj,
91
187
  });
92
188
 
189
+ expect(arena.evalCode(`obj`)).toBe(obj);
93
190
  expect(arena.evalCode(`obj.a`)).toBe(1);
94
191
  expect(arena.evalCode(`obj.b(1.1)`)).toBe(1);
95
192
  expect(() => arena.evalCode(`obj.c()`)).toThrow("hoge");
193
+ expect(arena.evalCode(`obj.d(1)`)).toStrictEqual({
194
+ myFavoriteNumber: 42,
195
+ yourFavoriteNumber: 1,
196
+ });
197
+ expect(arena.evalCode(`obj.e`)).toStrictEqual({ a: 1 });
96
198
 
97
199
  arena.dispose();
98
200
  vm.dispose();
@@ -100,10 +202,12 @@ describe("expose without sync", () => {
100
202
 
101
203
  test("Math", async () => {
102
204
  const vm = (await getQuickJS()).createVm();
103
- const arena = new Arena(vm);
205
+ const arena = new Arena(vm, { isMarshalable: true });
104
206
 
105
- arena.expose({ Math });
106
- expect(arena.evalCode(`Math.floor(1.1)`)).toBe(1);
207
+ arena.expose({ Math2: Math });
208
+ expect(arena.evalCode(`Math`)).not.toBe(Math);
209
+ expect(arena.evalCode(`Math2`)).toBe(Math);
210
+ expect(arena.evalCode(`Math2.floor(1.1)`)).toBe(1);
107
211
 
108
212
  arena.dispose();
109
213
  vm.dispose();
@@ -111,7 +215,7 @@ describe("expose without sync", () => {
111
215
 
112
216
  test("class", async () => {
113
217
  const vm = (await getQuickJS()).createVm();
114
- const arena = new Arena(vm);
218
+ const arena = new Arena(vm, { isMarshalable: true });
115
219
 
116
220
  class D {
117
221
  a: number;
@@ -125,7 +229,10 @@ describe("expose without sync", () => {
125
229
  }
126
230
  }
127
231
 
128
- arena.expose({ D, d: new D(100) });
232
+ const d = new D(100);
233
+ arena.expose({ D, d });
234
+ expect(arena.evalCode(`D`)).toBe(D);
235
+ expect(arena.evalCode(`d`)).toBe(d);
129
236
  expect(arena.evalCode(`d instanceof D`)).toBe(true);
130
237
  expect(arena.evalCode(`d.a`)).toBe(101);
131
238
  expect(arena.evalCode(`d.foo()`)).toBe(102);
@@ -137,7 +244,7 @@ describe("expose without sync", () => {
137
244
 
138
245
  test("object and function", async () => {
139
246
  const vm = (await getQuickJS()).createVm();
140
- const arena = new Arena(vm);
247
+ const arena = new Arena(vm, { isMarshalable: true });
141
248
 
142
249
  const obj = {
143
250
  a: 1,
@@ -146,9 +253,13 @@ describe("expose without sync", () => {
146
253
  return this.a++;
147
254
  },
148
255
  };
149
- const obj2 = arena.expose({ obj });
256
+ arena.expose({ obj });
150
257
 
258
+ expect(arena.evalCode(`obj`)).toBe(obj);
259
+ expect(arena.evalCode(`obj.a`)).toBe(1);
260
+ expect(arena.evalCode(`obj.b`)).toBe(obj.b);
151
261
  expect(arena.evalCode(`obj.b(1.1)`)).toBe(1);
262
+ expect(arena.evalCode(`obj.c`)).toBe(obj.c);
152
263
  expect(arena.evalCode(`obj.c()`)).toBe(1);
153
264
  expect(arena.evalCode(`obj.a`)).toBe(2);
154
265
  expect(obj.a).toBe(2);
@@ -156,8 +267,7 @@ describe("expose without sync", () => {
156
267
  expect(arena.evalCode(`obj.a`)).toBe(3);
157
268
  expect(obj.a).toBe(3);
158
269
 
159
- expect(obj).toBe(obj2.obj);
160
- obj2.obj.a = 10;
270
+ obj.a = 10;
161
271
  expect(obj.a).toBe(10);
162
272
  expect(arena.evalCode(`obj.a`)).toBe(3); // not affected
163
273
 
@@ -171,9 +281,9 @@ describe("expose without sync", () => {
171
281
  });
172
282
 
173
283
  describe("expose with sync", () => {
174
- test("object and function", async () => {
284
+ test("sync before expose", async () => {
175
285
  const vm = (await getQuickJS()).createVm();
176
- const arena = new Arena(vm);
286
+ const arena = new Arena(vm, { isMarshalable: true });
177
287
 
178
288
  const obj = {
179
289
  a: 1,
@@ -182,9 +292,64 @@ describe("expose with sync", () => {
182
292
  return this.a++;
183
293
  },
184
294
  };
185
- const obj2 = arena.expose({ obj }, true);
295
+ const obj2 = arena.sync(obj);
296
+ arena.expose({ obj: obj2 });
297
+
298
+ const obj3 = arena.evalCode(`obj`);
299
+ expect(obj3).toBe(obj2);
300
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj.c); // wrapped object
301
+ expect(arena.evalCode(`obj.b`)).not.toBe(obj2.b); // wrapped object
302
+ expect(arena.evalCode(`obj.b`)).not.toBe(obj3.b); // wrapped object
303
+ expect(arena.evalCode(`obj.b(1.1)`)).toBe(1);
304
+ expect(arena.evalCode(`obj.a`)).toBe(1);
305
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj.c); // wrapped object
306
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj2.c); // wrapped object
307
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj3.c); // wrapped object
308
+ expect(arena.evalCode(`obj.c()`)).toBe(1);
309
+ expect(arena.evalCode(`obj.a`)).toBe(2);
310
+ expect(obj.a).toBe(2);
311
+ expect(arena.evalCode(`obj.c()`)).toBe(2);
312
+ expect(arena.evalCode(`obj.a`)).toBe(3);
313
+ expect(obj.a).toBe(3);
314
+
315
+ expect(obj).not.toBe(obj2);
316
+ obj2.a = 10;
317
+ expect(obj.a).toBe(10);
318
+ expect(arena.evalCode(`obj.a`)).toBe(10); // affected
186
319
 
320
+ arena.evalCode(`obj.a = 100`);
321
+ expect(obj.a).toBe(100); // affected
322
+ expect(arena.evalCode(`obj.a`)).toBe(100);
323
+
324
+ arena.dispose();
325
+ vm.dispose();
326
+ });
327
+
328
+ test("sync after expose", async () => {
329
+ const vm = (await getQuickJS()).createVm();
330
+ const arena = new Arena(vm, { isMarshalable: true });
331
+
332
+ const obj = {
333
+ a: 1,
334
+ b: (a: number) => Math.floor(a),
335
+ c() {
336
+ return this.a++;
337
+ },
338
+ };
339
+ arena.expose({ obj });
340
+ const obj2 = arena.sync(obj);
341
+
342
+ const obj3 = arena.evalCode(`obj`);
343
+ expect(obj3).not.toBe(obj); // wrapped object
344
+ expect(obj3).not.toBe(obj2); // wrapped object
345
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj.c); // wrapped object
346
+ expect(arena.evalCode(`obj.b`)).not.toBe(obj2.b); // wrapped object
347
+ expect(arena.evalCode(`obj.b`)).not.toBe(obj3.b); // wrapped object
187
348
  expect(arena.evalCode(`obj.b(1.1)`)).toBe(1);
349
+ expect(arena.evalCode(`obj.a`)).toBe(1);
350
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj.c); // wrapped object
351
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj2.c); // wrapped object
352
+ expect(arena.evalCode(`obj.c`)).not.toBe(obj3.c); // wrapped object
188
353
  expect(arena.evalCode(`obj.c()`)).toBe(1);
189
354
  expect(arena.evalCode(`obj.a`)).toBe(2);
190
355
  expect(obj.a).toBe(2);
@@ -192,8 +357,8 @@ describe("expose with sync", () => {
192
357
  expect(arena.evalCode(`obj.a`)).toBe(3);
193
358
  expect(obj.a).toBe(3);
194
359
 
195
- expect(obj).not.toBe(obj2.obj);
196
- obj2.obj.a = 10;
360
+ expect(obj).not.toBe(obj2);
361
+ obj2.a = 10;
197
362
  expect(obj.a).toBe(10);
198
363
  expect(arena.evalCode(`obj.a`)).toBe(10); // affected
199
364
 
@@ -208,13 +373,12 @@ describe("expose with sync", () => {
208
373
 
209
374
  test("evalCode -> expose", async () => {
210
375
  const vm = (await getQuickJS()).createVm();
211
- const arena = new Arena(vm);
376
+ const arena = new Arena(vm, { isMarshalable: true });
212
377
 
213
- const { obj } = arena.expose(
214
- { obj: arena.evalCode(`({ a: 1, b: 1 })`) },
215
- true
216
- );
378
+ const obj = arena.evalCode(`({ a: 1, b: 1 })`);
379
+ arena.expose({ obj });
217
380
 
381
+ expect(obj).toBe(obj);
218
382
  expect(obj.a).toBe(1);
219
383
  expect(arena.evalCode(`obj.a`)).toBe(1);
220
384
  expect(obj.b).toBe(1);
@@ -240,21 +404,34 @@ test("evalCode -> expose", async () => {
240
404
 
241
405
  test("expose -> evalCode", async () => {
242
406
  const vm = (await getQuickJS()).createVm();
243
- const arena = new Arena(vm);
407
+ const arena = new Arena(vm, { isMarshalable: true });
244
408
 
245
409
  const obj = { a: 1 };
246
- const { obj: obj2 } = arena.expose({ obj }, true);
247
- const obj3 = arena.evalCode(`obj`);
410
+ arena.expose({ obj });
411
+ const obj2 = arena.evalCode(`obj`);
248
412
 
249
- expect(obj3).toBe(obj2);
413
+ expect(obj2).toBe(obj);
250
414
 
251
- obj3.a = 2;
415
+ obj2.a = 2;
252
416
  expect(obj.a).toBe(2);
253
- expect(arena.evalCode(`obj.a`)).toBe(2);
417
+ expect(arena.evalCode(`obj.a`)).toBe(1);
418
+
419
+ arena.evalCode("obj.a = 3");
420
+ expect(obj.a).toBe(2);
421
+ expect(arena.evalCode(`obj.a`)).toBe(3);
422
+
423
+ arena.dispose();
424
+ vm.dispose();
425
+ });
426
+
427
+ test("evalCode -> expose -> evalCode", async () => {
428
+ const vm = (await getQuickJS()).createVm();
429
+ const arena = new Arena(vm, { isMarshalable: true });
254
430
 
255
- arena.evalCode("obj.a = 4");
256
- expect(obj.a).toBe(4);
257
- expect(arena.evalCode(`obj.a`)).toBe(4);
431
+ const obj = [1];
432
+ expect(arena.evalCode("a => a[0] + 10")(obj)).toBe(11);
433
+ arena.expose({ obj });
434
+ expect(arena.evalCode("obj")).toBe(obj);
258
435
 
259
436
  arena.dispose();
260
437
  vm.dispose();
@@ -262,7 +439,7 @@ test("expose -> evalCode", async () => {
262
439
 
263
440
  test("register and unregister", async () => {
264
441
  const vm = (await getQuickJS()).createVm();
265
- const arena = new Arena(vm, { registeredObjects: [] });
442
+ const arena = new Arena(vm, { isMarshalable: true, registeredObjects: [] });
266
443
 
267
444
  arena.register(Math, `Math`);
268
445
  expect(arena.evalCode(`Math`)).toBe(Math);
@@ -283,6 +460,7 @@ test("register and unregister", async () => {
283
460
  test("registeredObjects option", async () => {
284
461
  const vm = (await getQuickJS()).createVm();
285
462
  const arena = new Arena(vm, {
463
+ isMarshalable: true,
286
464
  registeredObjects: [[Symbol.iterator, "Symbol.iterator"]],
287
465
  });
288
466
 
@@ -295,14 +473,51 @@ test("registeredObjects option", async () => {
295
473
  vm.dispose();
296
474
  });
297
475
 
298
- test("isMarshalable option", async () => {
299
- const vm = (await getQuickJS()).createVm();
300
- const arena = new Arena(vm, {
301
- isMarshalable: o => o !== globalThis,
476
+ describe("isMarshalable option", () => {
477
+ test("false", async () => {
478
+ const vm = (await getQuickJS()).createVm();
479
+ const arena = new Arena(vm, { isMarshalable: false });
480
+
481
+ expect(arena.evalCode(`s => s === undefined`)(globalThis)).toBe(true);
482
+ expect(arena.evalCode(`s => s === undefined`)({})).toBe(true);
483
+ arena.expose({ aaa: globalThis });
484
+ expect(arena.evalCode(`aaa`)).toBeUndefined();
485
+
486
+ arena.dispose();
487
+ vm.dispose();
302
488
  });
303
489
 
304
- expect(arena.evalCode(`s => s === undefined`)(globalThis)).toBe(true);
490
+ test("json", async () => {
491
+ const vm = (await getQuickJS()).createVm();
492
+ const arena = new Arena(vm, { isMarshalable: "json" });
305
493
 
306
- arena.dispose();
307
- vm.dispose();
494
+ const obj = { a: () => {}, b: new Date(), c: [() => {}, 1] };
495
+ const objJSON = { b: obj.b.toISOString(), c: [null, 1] };
496
+ const objJSON2 = arena.evalCode(`a => a`)(obj);
497
+ expect(objJSON2).toStrictEqual(objJSON);
498
+ arena.expose({ obj });
499
+ const exposedObj = arena.evalCode(`obj`);
500
+ expect(exposedObj).toStrictEqual(objJSON);
501
+ expect(exposedObj).not.toBe(objJSON2);
502
+
503
+ arena.dispose();
504
+ vm.dispose();
505
+ });
506
+
507
+ test("conditional", async () => {
508
+ const vm = (await getQuickJS()).createVm();
509
+ const arena = new Arena(vm, {
510
+ isMarshalable: (o) => o !== globalThis,
511
+ });
512
+
513
+ const obj = { a: 1 };
514
+ expect(arena.evalCode(`s => s === undefined`)(globalThis)).toBe(true);
515
+ expect(arena.evalCode(`s => s === undefined`)(obj)).toBe(false);
516
+ arena.expose({ aaa: globalThis, bbb: obj });
517
+ expect(arena.evalCode(`aaa`)).toBeUndefined();
518
+ expect(arena.evalCode(`bbb`)).toBe(obj);
519
+
520
+ arena.dispose();
521
+ vm.dispose();
522
+ });
308
523
  });