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.
- package/LICENSE +2 -2
- package/README.md +71 -44
- package/dist/index.d.ts +116 -23
- package/dist/quickjs-emscripten-sync.mjs +842 -0
- package/dist/quickjs-emscripten-sync.umd.js +64 -2
- package/package.json +22 -53
- package/src/default.ts +2 -2
- package/src/index.test.ts +223 -59
- package/src/index.ts +72 -66
- package/src/marshal/custom.test.ts +50 -0
- package/src/marshal/custom.ts +36 -0
- package/src/marshal/function.test.ts +64 -75
- package/src/marshal/function.ts +15 -18
- package/src/marshal/index.test.ts +122 -77
- package/src/marshal/index.ts +19 -15
- package/src/marshal/json.test.ts +37 -41
- package/src/marshal/json.ts +5 -7
- package/src/marshal/object.test.ts +59 -84
- package/src/marshal/object.ts +8 -15
- package/src/marshal/primitive.test.ts +18 -21
- package/src/marshal/primitive.ts +11 -10
- package/src/marshal/promise.test.ts +85 -0
- package/src/marshal/promise.ts +19 -0
- package/src/marshal/properties.test.ts +24 -27
- 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 +63 -86
- package/src/unmarshal/function.ts +13 -22
- package/src/unmarshal/index.test.ts +114 -109
- package/src/unmarshal/index.ts +15 -14
- package/src/unmarshal/object.test.ts +42 -46
- package/src/unmarshal/object.ts +16 -20
- package/src/unmarshal/primitive.test.ts +17 -15
- package/src/unmarshal/primitive.ts +11 -18
- package/src/unmarshal/promise.test.ts +44 -0
- package/src/unmarshal/promise.ts +31 -0
- package/src/unmarshal/properties.test.ts +11 -9
- package/src/unmarshal/properties.ts +44 -45
- package/src/util.test.ts +14 -2
- package/src/util.ts +18 -8
- package/src/vmmap.test.ts +88 -82
- package/src/vmmap.ts +30 -44
- package/src/vmutil.test.ts +100 -75
- package/src/vmutil.ts +51 -34
- package/src/wrapper.test.ts +129 -167
- package/src/wrapper.ts +59 -62
- package/dist/default.d.ts +0 -4
- package/dist/marshal/function.d.ts +0 -2
- package/dist/marshal/index.d.ts +0 -11
- package/dist/marshal/json.d.ts +0 -2
- package/dist/marshal/object.d.ts +0 -2
- package/dist/marshal/primitive.d.ts +0 -2
- package/dist/marshal/properties.d.ts +0 -2
- package/dist/marshal/symbol.d.ts +0 -2
- package/dist/quickjs-emscripten-sync.cjs +0 -2
- package/dist/quickjs-emscripten-sync.cjs.map +0 -1
- package/dist/quickjs-emscripten-sync.modern.js +0 -2
- package/dist/quickjs-emscripten-sync.modern.js.map +0 -1
- package/dist/quickjs-emscripten-sync.module.js +0 -2
- package/dist/quickjs-emscripten-sync.module.js.map +0 -1
- package/dist/quickjs-emscripten-sync.umd.js.map +0 -1
- package/dist/unmarshal/function.d.ts +0 -2
- package/dist/unmarshal/index.d.ts +0 -9
- package/dist/unmarshal/object.d.ts +0 -2
- package/dist/unmarshal/primitive.d.ts +0 -2
- package/dist/unmarshal/properties.d.ts +0 -2
- package/dist/unmarshal/symbol.d.ts +0 -2
- package/dist/util.d.ts +0 -7
- package/dist/vmmap.d.ts +0 -35
- package/dist/vmutil.d.ts +0 -11
- package/dist/wrapper.d.ts +0 -11
- package/src/marshal/symbol.test.ts +0 -22
- package/src/marshal/symbol.ts +0 -20
- package/src/unmarshal/symbol.test.ts +0 -23
- package/src/unmarshal/symbol.ts +0 -12
package/src/vmutil.test.ts
CHANGED
|
@@ -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
|
|
15
|
-
const vm = quickjs.createVm();
|
|
39
|
+
const ctx = (await getQuickJS()).newContext();
|
|
16
40
|
|
|
17
41
|
expect(
|
|
18
|
-
|
|
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 =
|
|
24
|
-
|
|
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
|
-
|
|
50
|
+
ctx.dispose();
|
|
31
51
|
});
|
|
32
52
|
|
|
33
53
|
test("eq", async () => {
|
|
34
|
-
const
|
|
35
|
-
const vm = quickjs.createVm();
|
|
54
|
+
const ctx = (await getQuickJS()).newContext();
|
|
36
55
|
|
|
37
|
-
const math1 =
|
|
38
|
-
const math2 =
|
|
39
|
-
const obj =
|
|
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(
|
|
42
|
-
expect(eq(
|
|
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
|
-
|
|
66
|
+
ctx.dispose();
|
|
48
67
|
});
|
|
49
68
|
|
|
50
69
|
test("instanceOf", async () => {
|
|
51
|
-
const
|
|
52
|
-
const vm = quickjs.createVm();
|
|
70
|
+
const ctx = (await getQuickJS()).newContext();
|
|
53
71
|
|
|
54
|
-
const pr =
|
|
55
|
-
const func =
|
|
56
|
-
const p =
|
|
57
|
-
expect(instanceOf(
|
|
58
|
-
expect(instanceOf(
|
|
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
|
-
|
|
81
|
+
ctx.dispose();
|
|
64
82
|
});
|
|
65
83
|
|
|
66
84
|
test("isHandleObject", async () => {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
99
|
+
ctx.dispose();
|
|
83
100
|
});
|
|
84
101
|
|
|
85
102
|
test("json", async () => {
|
|
86
|
-
const
|
|
87
|
-
const vm = quickjs.createVm();
|
|
103
|
+
const ctx = (await getQuickJS()).newContext();
|
|
88
104
|
|
|
89
|
-
const handle = json(
|
|
105
|
+
const handle = json(ctx, {
|
|
90
106
|
hoge: { foo: ["bar"] },
|
|
91
107
|
});
|
|
92
|
-
expect(
|
|
93
|
-
|
|
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
|
-
|
|
112
|
+
ctx.dispose();
|
|
99
113
|
});
|
|
100
114
|
|
|
101
115
|
test("consumeAll", async () => {
|
|
102
|
-
const
|
|
103
|
-
const vm = quickjs.createVm();
|
|
116
|
+
const ctx = (await getQuickJS()).newContext();
|
|
104
117
|
|
|
105
118
|
const o = {};
|
|
106
119
|
|
|
107
|
-
const handles = [
|
|
120
|
+
const handles = [ctx.newObject(), ctx.newObject()];
|
|
108
121
|
expect(
|
|
109
122
|
consumeAll(
|
|
110
123
|
handles,
|
|
111
|
-
|
|
112
|
-
)
|
|
124
|
+
vi.fn(() => o),
|
|
125
|
+
),
|
|
113
126
|
).toBe(o);
|
|
114
|
-
expect(handles.every(
|
|
127
|
+
expect(handles.every(h => !h.alive)).toBe(true);
|
|
115
128
|
|
|
116
|
-
const handles2 = [
|
|
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(
|
|
135
|
+
expect(handles2.every(h => !h.alive)).toBe(true);
|
|
123
136
|
|
|
124
|
-
|
|
137
|
+
ctx.dispose();
|
|
125
138
|
});
|
|
126
139
|
|
|
127
140
|
test("mayConsume", async () => {
|
|
128
|
-
const
|
|
129
|
-
const vm = quickjs.createVm();
|
|
141
|
+
const ctx = (await getQuickJS()).newContext();
|
|
130
142
|
|
|
131
143
|
const o = {};
|
|
132
144
|
|
|
133
|
-
const handle =
|
|
145
|
+
const handle = ctx.newArray();
|
|
134
146
|
expect(
|
|
135
147
|
mayConsume(
|
|
136
148
|
[handle, false],
|
|
137
|
-
|
|
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 =
|
|
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
|
-
|
|
165
|
+
ctx.dispose();
|
|
154
166
|
});
|
|
155
167
|
|
|
156
168
|
test("mayConsumeAll", async () => {
|
|
157
|
-
const
|
|
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
|
-
[
|
|
164
|
-
[
|
|
174
|
+
[ctx.newObject(), false],
|
|
175
|
+
[ctx.newObject(), true],
|
|
165
176
|
];
|
|
166
177
|
expect(
|
|
167
178
|
mayConsumeAll(
|
|
168
179
|
handles,
|
|
169
|
-
|
|
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
|
-
[
|
|
177
|
-
[
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
25
|
+
ctx: QuickJSContext,
|
|
5
26
|
code: string,
|
|
6
27
|
thisArg?: QuickJSHandle,
|
|
7
28
|
...args: QuickJSHandle[]
|
|
8
29
|
): QuickJSHandle {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return
|
|
12
|
-
|
|
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(
|
|
18
|
-
return
|
|
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
|
-
|
|
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(
|
|
30
|
-
return
|
|
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(
|
|
52
|
+
export function json(ctx: QuickJSContext, target: any): QuickJSHandle {
|
|
41
53
|
const json = JSON.stringify(target);
|
|
42
|
-
if (!json) return
|
|
43
|
-
return call(
|
|
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(
|
|
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
|
+
}
|