quickjs-emscripten-sync 1.3.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +60 -37
  2. package/dist/index.d.ts +29 -22
  3. package/dist/quickjs-emscripten-sync.mjs +842 -0
  4. package/dist/quickjs-emscripten-sync.umd.js +15 -15
  5. package/package.json +12 -21
  6. package/src/default.ts +2 -2
  7. package/src/index.test.ts +159 -65
  8. package/src/index.ts +67 -66
  9. package/src/marshal/custom.test.ts +50 -0
  10. package/src/marshal/custom.ts +36 -0
  11. package/src/marshal/function.test.ts +60 -72
  12. package/src/marshal/function.ts +15 -18
  13. package/src/marshal/index.test.ts +88 -84
  14. package/src/marshal/index.ts +16 -18
  15. package/src/marshal/json.test.ts +32 -38
  16. package/src/marshal/json.ts +5 -7
  17. package/src/marshal/object.test.ts +52 -79
  18. package/src/marshal/object.ts +8 -15
  19. package/src/marshal/primitive.test.ts +16 -21
  20. package/src/marshal/primitive.ts +11 -10
  21. package/src/marshal/promise.test.ts +21 -22
  22. package/src/marshal/promise.ts +6 -13
  23. package/src/marshal/properties.test.ts +21 -26
  24. package/src/marshal/properties.ts +15 -17
  25. package/src/unmarshal/custom.test.ts +50 -0
  26. package/src/unmarshal/custom.ts +31 -0
  27. package/src/unmarshal/function.test.ts +52 -74
  28. package/src/unmarshal/function.ts +13 -22
  29. package/src/unmarshal/index.test.ts +58 -50
  30. package/src/unmarshal/index.ts +12 -13
  31. package/src/unmarshal/object.test.ts +37 -43
  32. package/src/unmarshal/object.ts +16 -20
  33. package/src/unmarshal/primitive.test.ts +15 -15
  34. package/src/unmarshal/primitive.ts +11 -18
  35. package/src/unmarshal/promise.test.ts +13 -13
  36. package/src/unmarshal/promise.ts +10 -19
  37. package/src/unmarshal/properties.test.ts +8 -8
  38. package/src/unmarshal/properties.ts +44 -45
  39. package/src/util.test.ts +2 -7
  40. package/src/util.ts +3 -8
  41. package/src/vmmap.test.ts +72 -88
  42. package/src/vmmap.ts +26 -44
  43. package/src/vmutil.test.ts +73 -89
  44. package/src/vmutil.ts +24 -47
  45. package/src/wrapper.test.ts +108 -148
  46. package/src/wrapper.ts +59 -62
  47. package/dist/quickjs-emscripten-sync.es.js +0 -951
  48. package/src/marshal/symbol.test.ts +0 -24
  49. package/src/marshal/symbol.ts +0 -20
  50. package/src/unmarshal/symbol.test.ts +0 -25
  51. package/src/unmarshal/symbol.ts +0 -12
package/src/wrapper.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { QuickJSVm, QuickJSHandle } from "quickjs-emscripten";
1
+ import type { QuickJSHandle, QuickJSContext } from "quickjs-emscripten";
2
+
2
3
  import { isObject } from "./util";
3
4
  import { call, isHandleObject, consumeAll, mayConsumeAll } from "./vmutil";
4
5
 
@@ -7,14 +8,23 @@ export type SyncMode = "both" | "vm" | "host";
7
8
  export type Wrapped<T> = T & { __qes_wrapped: never };
8
9
 
9
10
  export function wrap<T = any>(
10
- vm: QuickJSVm,
11
+ ctx: QuickJSContext,
11
12
  target: T,
12
13
  proxyKeySymbol: symbol,
13
14
  proxyKeySymbolHandle: QuickJSHandle,
14
15
  marshal: (target: any) => [QuickJSHandle, boolean],
15
- syncMode?: (target: T) => SyncMode | undefined
16
+ syncMode?: (target: T) => SyncMode | undefined,
17
+ wrappable?: (target: unknown) => boolean,
16
18
  ): Wrapped<T> | undefined {
17
- if (!isObject(target)) return undefined;
19
+ // promise and date cannot be wrapped
20
+ if (
21
+ !isObject(target) ||
22
+ target instanceof Promise ||
23
+ target instanceof Date ||
24
+ (wrappable && !wrappable(target))
25
+ )
26
+ return undefined;
27
+
18
28
  if (isWrapped(target, proxyKeySymbol)) return target;
19
29
 
20
30
  const rec = new Proxy(target as any, {
@@ -24,80 +34,66 @@ export function wrap<T = any>(
24
34
  set(obj, key, value, receiver) {
25
35
  const v = unwrap(value, proxyKeySymbol);
26
36
  const sync = syncMode?.(receiver) ?? "host";
27
- if (
28
- (sync !== "vm" && !Reflect.set(obj, key, v, receiver)) ||
29
- sync === "host" ||
30
- !vm.alive
31
- )
37
+ if ((sync !== "vm" && !Reflect.set(obj, key, v, receiver)) || sync === "host" || !ctx.alive)
32
38
  return true;
33
39
 
34
40
  mayConsumeAll(
35
41
  [marshal(receiver), marshal(key), marshal(v)],
36
42
  (receiverHandle, keyHandle, valueHandle) => {
37
- const [handle2, unwrapped] = unwrapHandle(
38
- vm,
39
- receiverHandle,
40
- proxyKeySymbolHandle
41
- );
43
+ const [handle2, unwrapped] = unwrapHandle(ctx, receiverHandle, proxyKeySymbolHandle);
42
44
  if (unwrapped) {
43
- handle2.consume((h) => vm.setProp(h, keyHandle, valueHandle));
45
+ handle2.consume(h => ctx.setProp(h, keyHandle, valueHandle));
44
46
  } else {
45
- vm.setProp(handle2, keyHandle, valueHandle);
47
+ ctx.setProp(handle2, keyHandle, valueHandle);
46
48
  }
47
- }
49
+ },
48
50
  );
49
51
 
50
52
  return true;
51
53
  },
52
54
  deleteProperty(obj, key) {
53
55
  const sync = syncMode?.(rec) ?? "host";
54
- return mayConsumeAll(
55
- [marshal(rec), marshal(key)],
56
- (recHandle, keyHandle) => {
57
- const [handle2, unwrapped] = unwrapHandle(
58
- vm,
59
- recHandle,
60
- proxyKeySymbolHandle
61
- );
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
- }
56
+ return mayConsumeAll([marshal(rec), marshal(key)], (recHandle, keyHandle) => {
57
+ const [handle2, unwrapped] = unwrapHandle(ctx, recHandle, proxyKeySymbolHandle);
58
+
59
+ if (sync === "vm" || Reflect.deleteProperty(obj, key)) {
60
+ if (sync === "host" || !ctx.alive) return true;
61
+
62
+ if (unwrapped) {
63
+ handle2.consume(h => call(ctx, `(a, b) => delete a[b]`, undefined, h, keyHandle));
64
+ } else {
65
+ call(ctx, `(a, b) => delete a[b]`, undefined, handle2, keyHandle);
73
66
  }
74
- return true;
75
67
  }
76
- );
68
+ return true;
69
+ });
77
70
  },
78
71
  }) as Wrapped<T>;
79
72
  return rec;
80
73
  }
81
74
 
82
75
  export function wrapHandle(
83
- vm: QuickJSVm,
76
+ ctx: QuickJSContext,
84
77
  handle: QuickJSHandle,
85
78
  proxyKeySymbol: symbol,
86
79
  proxyKeySymbolHandle: QuickJSHandle,
87
80
  unmarshal: (handle: QuickJSHandle) => any,
88
- syncMode?: (target: QuickJSHandle) => SyncMode | undefined
81
+ syncMode?: (target: QuickJSHandle) => SyncMode | undefined,
82
+ wrappable?: (target: QuickJSHandle, ctx: QuickJSContext) => boolean,
89
83
  ): [Wrapped<QuickJSHandle> | undefined, boolean] {
90
- if (!isHandleObject(vm, handle)) return [undefined, false];
91
- if (isHandleWrapped(vm, handle, proxyKeySymbolHandle)) return [handle, false];
84
+ if (!isHandleObject(ctx, handle) || (wrappable && !wrappable(handle, ctx)))
85
+ return [undefined, false];
86
+
87
+ if (isHandleWrapped(ctx, handle, proxyKeySymbolHandle)) return [handle, false];
92
88
 
93
89
  return consumeAll(
94
90
  [
95
- vm.newFunction("getSyncMode", (h) => {
91
+ ctx.newFunction("getSyncMode", h => {
96
92
  const res = syncMode?.(unmarshal(h));
97
- if (typeof res === "string") return vm.newString(res);
98
- return vm.undefined;
93
+ if (typeof res === "string") return ctx.newString(res);
94
+ return ctx.undefined;
99
95
  }),
100
- vm.newFunction("setter", (h, keyHandle, valueHandle) => {
96
+ ctx.newFunction("setter", (h, keyHandle, valueHandle) => {
101
97
  const target = unmarshal(h);
102
98
  if (!target) return;
103
99
  const key = unmarshal(keyHandle);
@@ -105,16 +101,16 @@ export function wrapHandle(
105
101
  const value = unmarshal(valueHandle);
106
102
  unwrap(target, proxyKeySymbol)[key] = value;
107
103
  }),
108
- vm.newFunction("deleter", (h, keyHandle) => {
104
+ ctx.newFunction("deleter", (h, keyHandle) => {
109
105
  const target = unmarshal(h);
110
106
  if (!target) return;
111
107
  const key = unmarshal(keyHandle);
112
108
  delete unwrap(target, proxyKeySymbol)[key];
113
109
  }),
114
110
  ],
115
- (args) => [
111
+ args => [
116
112
  call(
117
- vm,
113
+ ctx,
118
114
  `(target, sym, getSyncMode, setter, deleter) => {
119
115
  const rec = new Proxy(target, {
120
116
  get(obj, key, receiver) {
@@ -147,10 +143,10 @@ export function wrapHandle(
147
143
  undefined,
148
144
  handle,
149
145
  proxyKeySymbolHandle,
150
- ...args
146
+ ...args,
151
147
  ) as Wrapped<QuickJSHandle>,
152
148
  true,
153
- ]
149
+ ],
154
150
  );
155
151
  }
156
152
 
@@ -159,12 +155,12 @@ export function unwrap<T>(obj: T, key: string | symbol): T {
159
155
  }
160
156
 
161
157
  export function unwrapHandle(
162
- vm: QuickJSVm,
158
+ ctx: QuickJSContext,
163
159
  handle: QuickJSHandle,
164
- key: QuickJSHandle
160
+ key: QuickJSHandle,
165
161
  ): [QuickJSHandle, boolean] {
166
- if (!isHandleWrapped(vm, handle, key)) return [handle, false];
167
- return [vm.getProp(handle, key), true];
162
+ if (!isHandleWrapped(ctx, handle, key)) return [handle, false];
163
+ return [ctx.getProp(handle, key), true];
168
164
  }
169
165
 
170
166
  export function isWrapped<T>(obj: T, key: string | symbol): obj is Wrapped<T> {
@@ -172,17 +168,18 @@ export function isWrapped<T>(obj: T, key: string | symbol): obj is Wrapped<T> {
172
168
  }
173
169
 
174
170
  export function isHandleWrapped(
175
- vm: QuickJSVm,
171
+ ctx: QuickJSContext,
176
172
  handle: QuickJSHandle,
177
- key: QuickJSHandle
173
+ key: QuickJSHandle,
178
174
  ): handle is Wrapped<QuickJSHandle> {
179
- return !!vm.dump(
175
+ return !!ctx.dump(
180
176
  call(
181
- vm,
182
- `(a, s) => (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]`,
177
+ ctx,
178
+ // promise and date cannot be wrapped
179
+ `(a, s) => (a instanceof Promise) || (a instanceof Date) || (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]`,
183
180
  undefined,
184
181
  handle,
185
- key
186
- )
182
+ key,
183
+ ),
187
184
  );
188
185
  }