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.
- package/README.md +60 -37
- package/dist/index.d.ts +29 -22
- package/dist/quickjs-emscripten-sync.mjs +842 -0
- package/dist/quickjs-emscripten-sync.umd.js +15 -15
- package/package.json +12 -21
- package/src/default.ts +2 -2
- package/src/index.test.ts +159 -65
- package/src/index.ts +67 -66
- package/src/marshal/custom.test.ts +50 -0
- package/src/marshal/custom.ts +36 -0
- package/src/marshal/function.test.ts +60 -72
- package/src/marshal/function.ts +15 -18
- package/src/marshal/index.test.ts +88 -84
- package/src/marshal/index.ts +16 -18
- package/src/marshal/json.test.ts +32 -38
- package/src/marshal/json.ts +5 -7
- package/src/marshal/object.test.ts +52 -79
- package/src/marshal/object.ts +8 -15
- package/src/marshal/primitive.test.ts +16 -21
- package/src/marshal/primitive.ts +11 -10
- package/src/marshal/promise.test.ts +21 -22
- package/src/marshal/promise.ts +6 -13
- package/src/marshal/properties.test.ts +21 -26
- package/src/marshal/properties.ts +15 -17
- package/src/unmarshal/custom.test.ts +50 -0
- package/src/unmarshal/custom.ts +31 -0
- package/src/unmarshal/function.test.ts +52 -74
- package/src/unmarshal/function.ts +13 -22
- package/src/unmarshal/index.test.ts +58 -50
- package/src/unmarshal/index.ts +12 -13
- package/src/unmarshal/object.test.ts +37 -43
- package/src/unmarshal/object.ts +16 -20
- package/src/unmarshal/primitive.test.ts +15 -15
- package/src/unmarshal/primitive.ts +11 -18
- package/src/unmarshal/promise.test.ts +13 -13
- package/src/unmarshal/promise.ts +10 -19
- package/src/unmarshal/properties.test.ts +8 -8
- package/src/unmarshal/properties.ts +44 -45
- package/src/util.test.ts +2 -7
- package/src/util.ts +3 -8
- package/src/vmmap.test.ts +72 -88
- package/src/vmmap.ts +26 -44
- package/src/vmutil.test.ts +73 -89
- package/src/vmutil.ts +24 -47
- package/src/wrapper.test.ts +108 -148
- package/src/wrapper.ts +59 -62
- package/dist/quickjs-emscripten-sync.es.js +0 -951
- package/src/marshal/symbol.test.ts +0 -24
- package/src/marshal/symbol.ts +0 -20
- package/src/unmarshal/symbol.test.ts +0 -25
- package/src/unmarshal/symbol.ts +0 -12
package/src/wrapper.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
45
|
+
handle2.consume(h => ctx.setProp(h, keyHandle, valueHandle));
|
|
44
46
|
} else {
|
|
45
|
-
|
|
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
|
-
[
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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(
|
|
91
|
-
|
|
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
|
-
|
|
91
|
+
ctx.newFunction("getSyncMode", h => {
|
|
96
92
|
const res = syncMode?.(unmarshal(h));
|
|
97
|
-
if (typeof res === "string") return
|
|
98
|
-
return
|
|
93
|
+
if (typeof res === "string") return ctx.newString(res);
|
|
94
|
+
return ctx.undefined;
|
|
99
95
|
}),
|
|
100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
111
|
+
args => [
|
|
116
112
|
call(
|
|
117
|
-
|
|
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
|
-
|
|
158
|
+
ctx: QuickJSContext,
|
|
163
159
|
handle: QuickJSHandle,
|
|
164
|
-
key: QuickJSHandle
|
|
160
|
+
key: QuickJSHandle,
|
|
165
161
|
): [QuickJSHandle, boolean] {
|
|
166
|
-
if (!isHandleWrapped(
|
|
167
|
-
return [
|
|
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
|
-
|
|
171
|
+
ctx: QuickJSContext,
|
|
176
172
|
handle: QuickJSHandle,
|
|
177
|
-
key: QuickJSHandle
|
|
173
|
+
key: QuickJSHandle,
|
|
178
174
|
): handle is Wrapped<QuickJSHandle> {
|
|
179
|
-
return !!
|
|
175
|
+
return !!ctx.dump(
|
|
180
176
|
call(
|
|
181
|
-
|
|
182
|
-
|
|
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
|
}
|