@jsii/kernel 1.60.1 → 1.63.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/jest.config.mjs +3 -0
- package/lib/kernel.d.ts +6 -17
- package/lib/kernel.js +111 -150
- package/lib/objects.d.ts +2 -2
- package/lib/objects.js +15 -11
- package/lib/recording.js +1 -1
- package/lib/serialization.d.ts +9 -1
- package/lib/serialization.js +170 -90
- package/package.json +6 -6
package/jest.config.mjs
ADDED
package/lib/kernel.d.ts
CHANGED
|
@@ -5,15 +5,16 @@ export declare class Kernel {
|
|
|
5
5
|
* Set to true for verbose debugging.
|
|
6
6
|
*/
|
|
7
7
|
traceEnabled: boolean;
|
|
8
|
-
private assemblies;
|
|
8
|
+
private readonly assemblies;
|
|
9
9
|
private readonly objects;
|
|
10
|
-
private cbs;
|
|
11
|
-
private waiting;
|
|
12
|
-
private promises;
|
|
10
|
+
private readonly cbs;
|
|
11
|
+
private readonly waiting;
|
|
12
|
+
private readonly promises;
|
|
13
13
|
private nextid;
|
|
14
14
|
private syncInProgress?;
|
|
15
15
|
private installDir?;
|
|
16
|
-
|
|
16
|
+
/** The internal require function, used instead of the global "require" so that webpack does not transform it... */
|
|
17
|
+
private require?;
|
|
17
18
|
/**
|
|
18
19
|
* Creates a jsii kernel object.
|
|
19
20
|
*
|
|
@@ -74,17 +75,5 @@ export declare class Kernel {
|
|
|
74
75
|
private _findPropertyTarget;
|
|
75
76
|
private _makecbid;
|
|
76
77
|
private _makeprid;
|
|
77
|
-
private _wrapSandboxCode;
|
|
78
|
-
/**
|
|
79
|
-
* Executes arbitrary code in a VM sandbox.
|
|
80
|
-
*
|
|
81
|
-
* @param code JavaScript code to be executed in the VM
|
|
82
|
-
* @param sandbox a VM context to use for running the code
|
|
83
|
-
* @param sourceMaps source maps to be used in case an exception is thrown
|
|
84
|
-
* @param filename the file name to use for the executed code
|
|
85
|
-
*
|
|
86
|
-
* @returns the result of evaluating the code
|
|
87
|
-
*/
|
|
88
|
-
private _execute;
|
|
89
78
|
}
|
|
90
79
|
//# sourceMappingURL=kernel.d.ts.map
|
package/lib/kernel.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Kernel = void 0;
|
|
4
4
|
const spec = require("@jsii/spec");
|
|
5
|
+
const spec_1 = require("@jsii/spec");
|
|
5
6
|
const cp = require("child_process");
|
|
6
7
|
const fs = require("fs-extra");
|
|
8
|
+
const module_1 = require("module");
|
|
7
9
|
const os = require("os");
|
|
8
10
|
const path = require("path");
|
|
9
11
|
const tar = require("tar");
|
|
10
|
-
const vm = require("vm");
|
|
11
12
|
const api = require("./api");
|
|
12
13
|
const api_1 = require("./api");
|
|
13
14
|
const objects_1 = require("./objects");
|
|
@@ -22,35 +23,20 @@ class Kernel {
|
|
|
22
23
|
* result (or throw an error).
|
|
23
24
|
*/
|
|
24
25
|
constructor(callbackHandler) {
|
|
25
|
-
// `setImmediate` is required for tests to pass (it is otherwise
|
|
26
|
-
// impossible to wait for in-VM promises to complete)
|
|
27
26
|
this.callbackHandler = callbackHandler;
|
|
28
27
|
/**
|
|
29
28
|
* Set to true for verbose debugging.
|
|
30
29
|
*/
|
|
31
30
|
this.traceEnabled = false;
|
|
32
|
-
this.assemblies =
|
|
31
|
+
this.assemblies = new Map();
|
|
33
32
|
this.objects = new objects_1.ObjectTable(this._typeInfoForFqn.bind(this));
|
|
34
|
-
this.cbs =
|
|
35
|
-
this.waiting =
|
|
36
|
-
this.promises =
|
|
33
|
+
this.cbs = new Map();
|
|
34
|
+
this.waiting = new Map();
|
|
35
|
+
this.promises = new Map();
|
|
37
36
|
this.nextid = 20000; // incrementing counter for objid, cbid, promiseid
|
|
38
|
-
// `Buffer` is required when using simple-resource-bundler.
|
|
39
|
-
// HACK: when we webpack @jsii/runtime, all "require" statements get transpiled,
|
|
40
|
-
// so modules can be resolved within the pack. However, here we actually want to
|
|
41
|
-
// let loaded modules to use the native node "require" method.
|
|
42
|
-
// I wonder if webpack has some pragma that allows opting-out at certain points
|
|
43
|
-
// in the code.
|
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires
|
|
45
|
-
const moduleLoad = require('module').Module._load;
|
|
46
|
-
const nodeRequire = (p) => moduleLoad(p, module, false);
|
|
47
|
-
this.sandbox = vm.createContext({
|
|
48
|
-
Buffer,
|
|
49
|
-
setImmediate,
|
|
50
|
-
require: nodeRequire, // modules need to "require"
|
|
51
|
-
});
|
|
52
37
|
}
|
|
53
38
|
load(req) {
|
|
39
|
+
var _a, _b;
|
|
54
40
|
this._debug('load', req);
|
|
55
41
|
if ('assembly' in req) {
|
|
56
42
|
throw new Error('`assembly` field is deprecated for "load", use `name`, `version` and `tarball` instead');
|
|
@@ -69,10 +55,10 @@ class Kernel {
|
|
|
69
55
|
}
|
|
70
56
|
// same version, no-op
|
|
71
57
|
this._debug('look up already-loaded assembly', pkgname);
|
|
72
|
-
const assm = this.assemblies
|
|
58
|
+
const assm = this.assemblies.get(pkgname);
|
|
73
59
|
return {
|
|
74
60
|
assembly: assm.metadata.name,
|
|
75
|
-
types: Object.keys(assm.metadata.types
|
|
61
|
+
types: Object.keys((_a = assm.metadata.types) !== null && _a !== void 0 ? _a : {}).length,
|
|
76
62
|
};
|
|
77
63
|
}
|
|
78
64
|
// Create the install directory (there may be several path components for @scoped/packages)
|
|
@@ -95,21 +81,24 @@ class Kernel {
|
|
|
95
81
|
process.umask(originalUmask);
|
|
96
82
|
}
|
|
97
83
|
// read .jsii metadata from the root of the package
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
let assmSpec;
|
|
85
|
+
try {
|
|
86
|
+
assmSpec = (0, spec_1.loadAssemblyFromPath)(packageDir);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
throw new Error(`Error for package tarball ${req.tarball}: ${e.message}`);
|
|
101
90
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const closure = this._execute(`require(String.raw\`${packageDir}\`)`, packageDir);
|
|
91
|
+
// load the module and capture its closure
|
|
92
|
+
const closure = this.require(packageDir);
|
|
105
93
|
const assm = new Assembly(assmSpec, closure);
|
|
106
94
|
this._addAssembly(assm);
|
|
107
95
|
return {
|
|
108
96
|
assembly: assmSpec.name,
|
|
109
|
-
types: Object.keys(assmSpec.types
|
|
97
|
+
types: Object.keys((_b = assmSpec.types) !== null && _b !== void 0 ? _b : {}).length,
|
|
110
98
|
};
|
|
111
99
|
}
|
|
112
100
|
invokeBinScript(req) {
|
|
101
|
+
var _a;
|
|
113
102
|
const packageDir = this._getPackageDir(req.assembly);
|
|
114
103
|
if (fs.pathExistsSync(packageDir)) {
|
|
115
104
|
// module exists, verify version
|
|
@@ -121,7 +110,7 @@ class Kernel {
|
|
|
121
110
|
if (!epkg.bin) {
|
|
122
111
|
throw new Error(`Script with name ${req.script} was not defined.`);
|
|
123
112
|
}
|
|
124
|
-
const result = cp.spawnSync(path.join(packageDir, scriptPath), req.args
|
|
113
|
+
const result = cp.spawnSync(path.join(packageDir, scriptPath), (_a = req.args) !== null && _a !== void 0 ? _a : [], {
|
|
125
114
|
encoding: 'utf-8',
|
|
126
115
|
env: {
|
|
127
116
|
...process.env,
|
|
@@ -159,9 +148,9 @@ class Kernel {
|
|
|
159
148
|
throw new Error(`property ${symbol} is not static`);
|
|
160
149
|
}
|
|
161
150
|
const prototype = this._findSymbol(fqn);
|
|
162
|
-
const value = this._ensureSync(`property ${property}`, () =>
|
|
151
|
+
const value = this._ensureSync(`property ${property}`, () => prototype[property]);
|
|
163
152
|
this._debug('value:', value);
|
|
164
|
-
const ret = this._fromSandbox(value, ti);
|
|
153
|
+
const ret = this._fromSandbox(value, ti, `of static property ${symbol}`);
|
|
165
154
|
this._debug('ret', ret);
|
|
166
155
|
return { value: ret };
|
|
167
156
|
}
|
|
@@ -177,7 +166,7 @@ class Kernel {
|
|
|
177
166
|
throw new Error(`static property ${symbol} is readonly`);
|
|
178
167
|
}
|
|
179
168
|
const prototype = this._findSymbol(fqn);
|
|
180
|
-
this._ensureSync(`property ${property}`, () =>
|
|
169
|
+
this._ensureSync(`property ${property}`, () => (prototype[property] = this._toSandbox(value, ti, `assigned to static property ${symbol}`)));
|
|
181
170
|
return {};
|
|
182
171
|
}
|
|
183
172
|
get(req) {
|
|
@@ -193,9 +182,9 @@ class Kernel {
|
|
|
193
182
|
const propertyToGet = this._findPropertyTarget(instance, property);
|
|
194
183
|
// make the actual "get", and block any async calls that might be performed
|
|
195
184
|
// by jsii overrides.
|
|
196
|
-
const value = this._ensureSync(`property '${objref[api_1.TOKEN_REF]}.${propertyToGet}'`, () =>
|
|
185
|
+
const value = this._ensureSync(`property '${objref[api_1.TOKEN_REF]}.${propertyToGet}'`, () => instance[propertyToGet]);
|
|
197
186
|
this._debug('value:', value);
|
|
198
|
-
const ret = this._fromSandbox(value, ti);
|
|
187
|
+
const ret = this._fromSandbox(value, ti, `of property ${fqn}.${property}`);
|
|
199
188
|
this._debug('ret:', ret);
|
|
200
189
|
return { value: ret };
|
|
201
190
|
}
|
|
@@ -208,28 +197,31 @@ class Kernel {
|
|
|
208
197
|
throw new Error(`Cannot set value of immutable property ${req.property} to ${req.value}`);
|
|
209
198
|
}
|
|
210
199
|
const propertyToSet = this._findPropertyTarget(instance, property);
|
|
211
|
-
this._ensureSync(`property '${objref[api_1.TOKEN_REF]}.${propertyToSet}'`, () =>
|
|
200
|
+
this._ensureSync(`property '${objref[api_1.TOKEN_REF]}.${propertyToSet}'`, () => (instance[propertyToSet] = this._toSandbox(value, propInfo, `assigned to property ${fqn}.${property}`)));
|
|
212
201
|
return {};
|
|
213
202
|
}
|
|
214
203
|
invoke(req) {
|
|
204
|
+
var _a, _b;
|
|
215
205
|
const { objref, method } = req;
|
|
216
|
-
const args = req.args
|
|
206
|
+
const args = (_a = req.args) !== null && _a !== void 0 ? _a : [];
|
|
217
207
|
this._debug('invoke', objref, method, args);
|
|
218
208
|
const { ti, obj, fn } = this._findInvokeTarget(objref, method, args);
|
|
219
209
|
// verify this is not an async method
|
|
220
210
|
if (ti.async) {
|
|
221
211
|
throw new Error(`${method} is an async method, use "begin" instead`);
|
|
222
212
|
}
|
|
213
|
+
const fqn = (0, objects_1.jsiiTypeFqn)(obj);
|
|
223
214
|
const ret = this._ensureSync(`method '${objref[api_1.TOKEN_REF]}.${method}'`, () => {
|
|
224
|
-
return
|
|
215
|
+
return fn.apply(obj, this._toSandboxValues(args, `method ${fqn ? `${fqn}#` : ''}${method}`, ti.parameters));
|
|
225
216
|
});
|
|
226
|
-
const result = this._fromSandbox(ret, ti.returns
|
|
217
|
+
const result = this._fromSandbox(ret, (_b = ti.returns) !== null && _b !== void 0 ? _b : 'void', `returned by method ${fqn ? `${fqn}#` : ''}${method}`);
|
|
227
218
|
this._debug('invoke result', result);
|
|
228
219
|
return { result };
|
|
229
220
|
}
|
|
230
221
|
sinvoke(req) {
|
|
222
|
+
var _a, _b;
|
|
231
223
|
const { fqn, method } = req;
|
|
232
|
-
const args = req.args
|
|
224
|
+
const args = (_a = req.args) !== null && _a !== void 0 ? _a : [];
|
|
233
225
|
this._debug('sinvoke', fqn, method, args);
|
|
234
226
|
const ti = this._typeInfoForMethod(method, fqn);
|
|
235
227
|
if (!ti.static) {
|
|
@@ -242,14 +234,17 @@ class Kernel {
|
|
|
242
234
|
const prototype = this._findSymbol(fqn);
|
|
243
235
|
const fn = prototype[method];
|
|
244
236
|
const ret = this._ensureSync(`method '${fqn}.${method}'`, () => {
|
|
245
|
-
return
|
|
237
|
+
return fn.apply(prototype, this._toSandboxValues(args, `static method ${fqn}.${method}`, ti.parameters));
|
|
246
238
|
});
|
|
247
239
|
this._debug('method returned:', ret);
|
|
248
|
-
return {
|
|
240
|
+
return {
|
|
241
|
+
result: this._fromSandbox(ret, (_b = ti.returns) !== null && _b !== void 0 ? _b : 'void', `returned by static method ${fqn}.${method}`),
|
|
242
|
+
};
|
|
249
243
|
}
|
|
250
244
|
begin(req) {
|
|
245
|
+
var _a;
|
|
251
246
|
const { objref, method } = req;
|
|
252
|
-
const args = req.args
|
|
247
|
+
const args = (_a = req.args) !== null && _a !== void 0 ? _a : [];
|
|
253
248
|
this._debug('begin', objref, method, args);
|
|
254
249
|
if (this.syncInProgress) {
|
|
255
250
|
throw new Error(`Cannot invoke async method '${req.objref[api_1.TOKEN_REF]}.${req.method}' while sync ${this.syncInProgress} is being processed`);
|
|
@@ -259,25 +254,28 @@ class Kernel {
|
|
|
259
254
|
if (!ti.async) {
|
|
260
255
|
throw new Error(`Method ${method} is expected to be an async method`);
|
|
261
256
|
}
|
|
262
|
-
const
|
|
257
|
+
const fqn = (0, objects_1.jsiiTypeFqn)(obj);
|
|
258
|
+
const promise = fn.apply(obj, this._toSandboxValues(args, `async method ${fqn ? `${fqn}#` : ''}${method}`, ti.parameters));
|
|
263
259
|
// since we are planning to resolve this promise in a different scope
|
|
264
260
|
// we need to handle rejections here [1]
|
|
265
261
|
// [1]: https://stackoverflow.com/questions/40920179/should-i-refrain-from-handling-promise-rejection-asynchronously/40921505
|
|
266
262
|
promise.catch((_) => undefined);
|
|
267
263
|
const prid = this._makeprid();
|
|
268
|
-
this.promises
|
|
264
|
+
this.promises.set(prid, {
|
|
269
265
|
promise,
|
|
270
266
|
method: ti,
|
|
271
|
-
};
|
|
267
|
+
});
|
|
272
268
|
return { promiseid: prid };
|
|
273
269
|
}
|
|
274
270
|
async end(req) {
|
|
271
|
+
var _a;
|
|
275
272
|
const { promiseid } = req;
|
|
276
273
|
this._debug('end', promiseid);
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
274
|
+
const storedPromise = this.promises.get(promiseid);
|
|
275
|
+
if (storedPromise == null) {
|
|
279
276
|
throw new Error(`Cannot find promise with ID: ${promiseid}`);
|
|
280
277
|
}
|
|
278
|
+
const { promise, method } = storedPromise;
|
|
281
279
|
let result;
|
|
282
280
|
try {
|
|
283
281
|
result = await promise;
|
|
@@ -287,13 +285,15 @@ class Kernel {
|
|
|
287
285
|
this._debug('promise error:', e);
|
|
288
286
|
throw e;
|
|
289
287
|
}
|
|
290
|
-
return {
|
|
288
|
+
return {
|
|
289
|
+
result: this._fromSandbox(result, (_a = method.returns) !== null && _a !== void 0 ? _a : 'void', `returned by async method ${method.name}`),
|
|
290
|
+
};
|
|
291
291
|
}
|
|
292
292
|
callbacks(_req) {
|
|
293
293
|
this._debug('callbacks');
|
|
294
|
-
const ret =
|
|
295
|
-
|
|
296
|
-
this.
|
|
294
|
+
const ret = Array.from(this.cbs.entries()).map(([cbid, cb]) => {
|
|
295
|
+
this.waiting.set(cbid, cb); // move to waiting
|
|
296
|
+
this.cbs.delete(cbid); // remove from created
|
|
297
297
|
const callback = {
|
|
298
298
|
cbid,
|
|
299
299
|
cookie: cb.override.cookie,
|
|
@@ -305,27 +305,26 @@ class Kernel {
|
|
|
305
305
|
};
|
|
306
306
|
return callback;
|
|
307
307
|
});
|
|
308
|
-
// move all callbacks to the wait queue and clean the callback queue.
|
|
309
|
-
this.cbs = {};
|
|
310
308
|
return { callbacks: ret };
|
|
311
309
|
}
|
|
312
310
|
complete(req) {
|
|
311
|
+
var _a;
|
|
313
312
|
const { cbid, err, result } = req;
|
|
314
313
|
this._debug('complete', cbid, err, result);
|
|
315
|
-
|
|
314
|
+
const cb = this.waiting.get(cbid);
|
|
315
|
+
if (!cb) {
|
|
316
316
|
throw new Error(`Callback ${cbid} not found`);
|
|
317
317
|
}
|
|
318
|
-
const cb = this.waiting[cbid];
|
|
319
318
|
if (err) {
|
|
320
319
|
this._debug('completed with error:', err);
|
|
321
320
|
cb.fail(new Error(err));
|
|
322
321
|
}
|
|
323
322
|
else {
|
|
324
|
-
const sandoxResult = this._toSandbox(result, cb.expectedReturnType
|
|
323
|
+
const sandoxResult = this._toSandbox(result, (_a = cb.expectedReturnType) !== null && _a !== void 0 ? _a : 'void', `returned by callback ${cb.toString()}`);
|
|
325
324
|
this._debug('completed with result:', sandoxResult);
|
|
326
325
|
cb.succeed(sandoxResult);
|
|
327
326
|
}
|
|
328
|
-
|
|
327
|
+
this.waiting.delete(cbid);
|
|
329
328
|
return { cbid };
|
|
330
329
|
}
|
|
331
330
|
/**
|
|
@@ -348,10 +347,11 @@ class Kernel {
|
|
|
348
347
|
};
|
|
349
348
|
}
|
|
350
349
|
_addAssembly(assm) {
|
|
351
|
-
|
|
350
|
+
var _a;
|
|
351
|
+
this.assemblies.set(assm.metadata.name, assm);
|
|
352
352
|
// add the __jsii__.fqn property on every constructor. this allows
|
|
353
353
|
// traversing between the javascript and jsii worlds given any object.
|
|
354
|
-
for (const fqn of Object.keys(assm.metadata.types
|
|
354
|
+
for (const fqn of Object.keys((_a = assm.metadata.types) !== null && _a !== void 0 ? _a : {})) {
|
|
355
355
|
const typedef = assm.metadata.types[fqn];
|
|
356
356
|
switch (typedef.kind) {
|
|
357
357
|
case spec.TypeKind.Interface:
|
|
@@ -386,6 +386,7 @@ class Kernel {
|
|
|
386
386
|
_getPackageDir(pkgname) {
|
|
387
387
|
if (!this.installDir) {
|
|
388
388
|
this.installDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsii-kernel-'));
|
|
389
|
+
this.require = (0, module_1.createRequire)(this.installDir);
|
|
389
390
|
fs.mkdirpSync(path.join(this.installDir, 'node_modules'));
|
|
390
391
|
this._debug('creating jsii-kernel modules workdir:', this.installDir);
|
|
391
392
|
onExit.removeSync(this.installDir);
|
|
@@ -395,13 +396,14 @@ class Kernel {
|
|
|
395
396
|
// prefixed with _ to allow calling this method internally without
|
|
396
397
|
// getting it recorded for testing.
|
|
397
398
|
_create(req) {
|
|
399
|
+
var _a, _b;
|
|
398
400
|
this._debug('create', req);
|
|
399
401
|
const { fqn, interfaces, overrides } = req;
|
|
400
|
-
const requestArgs = req.args
|
|
402
|
+
const requestArgs = (_a = req.args) !== null && _a !== void 0 ? _a : [];
|
|
401
403
|
const ctorResult = this._findCtor(fqn, requestArgs);
|
|
402
404
|
const ctor = ctorResult.ctor;
|
|
403
|
-
const obj =
|
|
404
|
-
const objref = this.objects.registerObject(obj, fqn, req.interfaces
|
|
405
|
+
const obj = new ctor(...this._toSandboxValues(requestArgs, `new ${fqn}`, ctorResult.parameters));
|
|
406
|
+
const objref = this.objects.registerObject(obj, fqn, (_b = req.interfaces) !== null && _b !== void 0 ? _b : []);
|
|
405
407
|
// overrides: for each one of the override method names, installs a
|
|
406
408
|
// method on the newly created object which represents the remote "reverse proxy".
|
|
407
409
|
if (overrides) {
|
|
@@ -466,11 +468,12 @@ class Kernel {
|
|
|
466
468
|
this._defineOverridenProperty(obj, objref, override, propInfo);
|
|
467
469
|
}
|
|
468
470
|
_defineOverridenProperty(obj, objref, override, propInfo) {
|
|
471
|
+
var _a;
|
|
469
472
|
const propertyName = override.property;
|
|
470
473
|
this._debug('apply override', propertyName);
|
|
471
474
|
// save the old property under $jsii$super$<prop>$ so that property overrides
|
|
472
475
|
// can still access it via `super.<prop>`.
|
|
473
|
-
const prev = getPropertyDescriptor(obj, propertyName)
|
|
476
|
+
const prev = (_a = getPropertyDescriptor(obj, propertyName)) !== null && _a !== void 0 ? _a : {
|
|
474
477
|
value: obj[propertyName],
|
|
475
478
|
writable: true,
|
|
476
479
|
enumerable: true,
|
|
@@ -495,7 +498,7 @@ class Kernel {
|
|
|
495
498
|
get: { objref, property: propertyName },
|
|
496
499
|
});
|
|
497
500
|
this._debug('callback returned', result);
|
|
498
|
-
return this._toSandbox(result, propInfo);
|
|
501
|
+
return this._toSandbox(result, propInfo, `returned by callback property ${propertyName}`);
|
|
499
502
|
},
|
|
500
503
|
set: (value) => {
|
|
501
504
|
this._debug('virtual set', objref, propertyName, {
|
|
@@ -507,7 +510,7 @@ class Kernel {
|
|
|
507
510
|
set: {
|
|
508
511
|
objref,
|
|
509
512
|
property: propertyName,
|
|
510
|
-
value: this._fromSandbox(value, propInfo),
|
|
513
|
+
value: this._fromSandbox(value, propInfo, `assigned to callback property ${propertyName}`),
|
|
511
514
|
},
|
|
512
515
|
});
|
|
513
516
|
},
|
|
@@ -558,6 +561,8 @@ class Kernel {
|
|
|
558
561
|
}
|
|
559
562
|
_defineOverridenMethod(obj, objref, override, methodInfo) {
|
|
560
563
|
const methodName = override.method;
|
|
564
|
+
const fqn = (0, objects_1.jsiiTypeFqn)(obj);
|
|
565
|
+
const methodContext = `${methodInfo.async ? 'async ' : ''}method${fqn ? `${fqn}#` : methodName}`;
|
|
561
566
|
if (methodInfo.async) {
|
|
562
567
|
// async method override
|
|
563
568
|
Object.defineProperty(obj, methodName, {
|
|
@@ -566,18 +571,19 @@ class Kernel {
|
|
|
566
571
|
writable: false,
|
|
567
572
|
value: (...methodArgs) => {
|
|
568
573
|
this._debug('invoke async method override', override);
|
|
569
|
-
const args = this._toSandboxValues(methodArgs, methodInfo.parameters);
|
|
574
|
+
const args = this._toSandboxValues(methodArgs, methodContext, methodInfo.parameters);
|
|
570
575
|
return new Promise((succeed, fail) => {
|
|
576
|
+
var _a;
|
|
571
577
|
const cbid = this._makecbid();
|
|
572
578
|
this._debug('adding callback to queue', cbid);
|
|
573
|
-
this.cbs
|
|
579
|
+
this.cbs.set(cbid, {
|
|
574
580
|
objref,
|
|
575
581
|
override,
|
|
576
582
|
args,
|
|
577
|
-
expectedReturnType: methodInfo.returns
|
|
583
|
+
expectedReturnType: (_a = methodInfo.returns) !== null && _a !== void 0 ? _a : 'void',
|
|
578
584
|
succeed,
|
|
579
585
|
fail,
|
|
580
|
-
};
|
|
586
|
+
});
|
|
581
587
|
});
|
|
582
588
|
},
|
|
583
589
|
});
|
|
@@ -589,6 +595,7 @@ class Kernel {
|
|
|
589
595
|
configurable: false,
|
|
590
596
|
writable: false,
|
|
591
597
|
value: (...methodArgs) => {
|
|
598
|
+
var _a;
|
|
592
599
|
this._debug('invoke sync method override', override, 'args', methodArgs);
|
|
593
600
|
// We should be validating the actual arguments according to the
|
|
594
601
|
// declared parameters here, but let's just assume the JSII runtime on the
|
|
@@ -599,11 +606,11 @@ class Kernel {
|
|
|
599
606
|
invoke: {
|
|
600
607
|
objref,
|
|
601
608
|
method: methodName,
|
|
602
|
-
args: this._fromSandboxValues(methodArgs, methodInfo.parameters),
|
|
609
|
+
args: this._fromSandboxValues(methodArgs, methodContext, methodInfo.parameters),
|
|
603
610
|
},
|
|
604
611
|
});
|
|
605
612
|
this._debug('Result', result);
|
|
606
|
-
return this._toSandbox(result, methodInfo.returns
|
|
613
|
+
return this._toSandbox(result, (_a = methodInfo.returns) !== null && _a !== void 0 ? _a : 'void', `returned by callback method ${methodName}`);
|
|
607
614
|
},
|
|
608
615
|
});
|
|
609
616
|
}
|
|
@@ -629,7 +636,8 @@ class Kernel {
|
|
|
629
636
|
return { ti, obj: instance, fn };
|
|
630
637
|
}
|
|
631
638
|
_validateMethodArguments(method, args) {
|
|
632
|
-
|
|
639
|
+
var _a;
|
|
640
|
+
const params = (_a = method === null || method === void 0 ? void 0 : method.parameters) !== null && _a !== void 0 ? _a : [];
|
|
633
641
|
// error if args > params
|
|
634
642
|
if (args.length > params.length && !(method && method.variadic)) {
|
|
635
643
|
throw new Error(`Too many arguments (method accepts ${params.length} parameters, got ${args.length} arguments)`);
|
|
@@ -653,7 +661,7 @@ class Kernel {
|
|
|
653
661
|
}
|
|
654
662
|
}
|
|
655
663
|
_assemblyFor(assemblyName) {
|
|
656
|
-
const assembly = this.assemblies
|
|
664
|
+
const assembly = this.assemblies.get(assemblyName);
|
|
657
665
|
if (!assembly) {
|
|
658
666
|
throw new Error(`Could not find assembly: ${assemblyName}`);
|
|
659
667
|
}
|
|
@@ -676,13 +684,14 @@ class Kernel {
|
|
|
676
684
|
return curr;
|
|
677
685
|
}
|
|
678
686
|
_typeInfoForFqn(fqn) {
|
|
687
|
+
var _a;
|
|
679
688
|
const components = fqn.split('.');
|
|
680
689
|
const moduleName = components[0];
|
|
681
|
-
const assembly = this.assemblies
|
|
690
|
+
const assembly = this.assemblies.get(moduleName);
|
|
682
691
|
if (!assembly) {
|
|
683
692
|
throw new Error(`Module '${moduleName}' not found`);
|
|
684
693
|
}
|
|
685
|
-
const types = assembly.metadata.types
|
|
694
|
+
const types = (_a = assembly.metadata.types) !== null && _a !== void 0 ? _a : {};
|
|
686
695
|
const fqnInfo = types[fqn];
|
|
687
696
|
if (!fqnInfo) {
|
|
688
697
|
throw new Error(`Type '${fqn}' not found`);
|
|
@@ -700,12 +709,13 @@ class Kernel {
|
|
|
700
709
|
return ti;
|
|
701
710
|
}
|
|
702
711
|
_tryTypeInfoForMethod(methodName, classFqn, interfaces = []) {
|
|
712
|
+
var _a, _b;
|
|
703
713
|
for (const fqn of [classFqn, ...interfaces]) {
|
|
704
714
|
if (fqn === wire.EMPTY_OBJECT_FQN) {
|
|
705
715
|
continue;
|
|
706
716
|
}
|
|
707
717
|
const typeinfo = this._typeInfoForFqn(fqn);
|
|
708
|
-
const methods = typeinfo.methods
|
|
718
|
+
const methods = (_a = typeinfo.methods) !== null && _a !== void 0 ? _a : [];
|
|
709
719
|
for (const m of methods) {
|
|
710
720
|
if (m.name === methodName) {
|
|
711
721
|
return m;
|
|
@@ -714,7 +724,7 @@ class Kernel {
|
|
|
714
724
|
// recursion to parent type (if exists)
|
|
715
725
|
const bases = [
|
|
716
726
|
typeinfo.base,
|
|
717
|
-
...(typeinfo.interfaces
|
|
727
|
+
...((_b = typeinfo.interfaces) !== null && _b !== void 0 ? _b : []),
|
|
718
728
|
];
|
|
719
729
|
for (const base of bases) {
|
|
720
730
|
if (!base) {
|
|
@@ -729,6 +739,7 @@ class Kernel {
|
|
|
729
739
|
return undefined;
|
|
730
740
|
}
|
|
731
741
|
_tryTypeInfoForProperty(property, classFqn, interfaces = []) {
|
|
742
|
+
var _a;
|
|
732
743
|
for (const fqn of [classFqn, ...interfaces]) {
|
|
733
744
|
if (fqn === wire.EMPTY_OBJECT_FQN) {
|
|
734
745
|
continue;
|
|
@@ -744,12 +755,12 @@ class Kernel {
|
|
|
744
755
|
else if (spec.isInterfaceType(typeInfo)) {
|
|
745
756
|
const interfaceTypeInfo = typeInfo;
|
|
746
757
|
properties = interfaceTypeInfo.properties;
|
|
747
|
-
bases = interfaceTypeInfo.interfaces
|
|
758
|
+
bases = (_a = interfaceTypeInfo.interfaces) !== null && _a !== void 0 ? _a : [];
|
|
748
759
|
}
|
|
749
760
|
else {
|
|
750
761
|
throw new Error(`Type of kind ${typeInfo.kind} does not have properties`);
|
|
751
762
|
}
|
|
752
|
-
for (const p of properties
|
|
763
|
+
for (const p of properties !== null && properties !== void 0 ? properties : []) {
|
|
753
764
|
if (p.name === property) {
|
|
754
765
|
return p;
|
|
755
766
|
}
|
|
@@ -774,73 +785,40 @@ class Kernel {
|
|
|
774
785
|
}
|
|
775
786
|
return typeInfo;
|
|
776
787
|
}
|
|
777
|
-
_toSandbox(v, expectedType) {
|
|
778
|
-
|
|
779
|
-
this._debug('toSandbox', v, JSON.stringify(serTypes));
|
|
780
|
-
const host = {
|
|
788
|
+
_toSandbox(v, expectedType, context) {
|
|
789
|
+
return wire.process({
|
|
781
790
|
objects: this.objects,
|
|
782
791
|
debug: this._debug.bind(this),
|
|
783
792
|
findSymbol: this._findSymbol.bind(this),
|
|
784
793
|
lookupType: this._typeInfoForFqn.bind(this),
|
|
785
|
-
|
|
786
|
-
};
|
|
787
|
-
const errors = new Array();
|
|
788
|
-
for (const { serializationClass, typeRef } of serTypes) {
|
|
789
|
-
try {
|
|
790
|
-
return wire.SERIALIZERS[serializationClass].deserialize(v, typeRef, host);
|
|
791
|
-
}
|
|
792
|
-
catch (e) {
|
|
793
|
-
// If no union (99% case), rethrow immediately to preserve stack trace
|
|
794
|
-
if (serTypes.length === 1) {
|
|
795
|
-
throw e;
|
|
796
|
-
}
|
|
797
|
-
errors.push(e.message);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
throw new Error(`Value did not match any type in union: ${errors.join(', ')}`);
|
|
794
|
+
}, 'deserialize', v, expectedType, context);
|
|
801
795
|
}
|
|
802
|
-
_fromSandbox(v, targetType) {
|
|
803
|
-
|
|
804
|
-
this._debug('fromSandbox', v, JSON.stringify(serTypes));
|
|
805
|
-
const host = {
|
|
796
|
+
_fromSandbox(v, targetType, context) {
|
|
797
|
+
return wire.process({
|
|
806
798
|
objects: this.objects,
|
|
807
799
|
debug: this._debug.bind(this),
|
|
808
800
|
findSymbol: this._findSymbol.bind(this),
|
|
809
801
|
lookupType: this._typeInfoForFqn.bind(this),
|
|
810
|
-
|
|
811
|
-
};
|
|
812
|
-
const errors = new Array();
|
|
813
|
-
for (const { serializationClass, typeRef } of serTypes) {
|
|
814
|
-
try {
|
|
815
|
-
return wire.SERIALIZERS[serializationClass].serialize(v, typeRef, host);
|
|
816
|
-
}
|
|
817
|
-
catch (e) {
|
|
818
|
-
// If no union (99% case), rethrow immediately to preserve stack trace
|
|
819
|
-
if (serTypes.length === 1) {
|
|
820
|
-
throw e;
|
|
821
|
-
}
|
|
822
|
-
errors.push(e.message);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
throw new Error(`Value did not match any type in union: ${errors.join(', ')}`);
|
|
802
|
+
}, 'serialize', v, targetType, context);
|
|
826
803
|
}
|
|
827
|
-
_toSandboxValues(xs, parameters) {
|
|
828
|
-
return this._boxUnboxParameters(xs, parameters, this._toSandbox.bind(this));
|
|
804
|
+
_toSandboxValues(xs, methodContext, parameters) {
|
|
805
|
+
return this._boxUnboxParameters(xs, methodContext, parameters, this._toSandbox.bind(this));
|
|
829
806
|
}
|
|
830
|
-
_fromSandboxValues(xs, parameters) {
|
|
831
|
-
return this._boxUnboxParameters(xs, parameters, this._fromSandbox.bind(this));
|
|
807
|
+
_fromSandboxValues(xs, methodContext, parameters) {
|
|
808
|
+
return this._boxUnboxParameters(xs, methodContext, parameters, this._fromSandbox.bind(this));
|
|
832
809
|
}
|
|
833
|
-
_boxUnboxParameters(xs, parameters, boxUnbox) {
|
|
834
|
-
|
|
835
|
-
const variadic =
|
|
810
|
+
_boxUnboxParameters(xs, methodContext, parameters = [], boxUnbox) {
|
|
811
|
+
const parametersCopy = [...parameters];
|
|
812
|
+
const variadic = parametersCopy.length > 0 &&
|
|
813
|
+
!!parametersCopy[parametersCopy.length - 1].variadic;
|
|
836
814
|
// Repeat the last (variadic) type to match the number of actual arguments
|
|
837
|
-
while (variadic &&
|
|
838
|
-
|
|
815
|
+
while (variadic && parametersCopy.length < xs.length) {
|
|
816
|
+
parametersCopy.push(parametersCopy[parametersCopy.length - 1]);
|
|
839
817
|
}
|
|
840
|
-
if (xs.length >
|
|
841
|
-
throw new Error(`Argument list (${JSON.stringify(xs)}) not same size as expected argument list (length ${
|
|
818
|
+
if (xs.length > parametersCopy.length) {
|
|
819
|
+
throw new Error(`Argument list (${JSON.stringify(xs)}) not same size as expected argument list (length ${parametersCopy.length})`);
|
|
842
820
|
}
|
|
843
|
-
return xs.map((x, i) => boxUnbox(x,
|
|
821
|
+
return xs.map((x, i) => boxUnbox(x, parametersCopy[i], `passed to parameter ${parametersCopy[i].name} of ${methodContext}`));
|
|
844
822
|
}
|
|
845
823
|
_debug(...args) {
|
|
846
824
|
if (this.traceEnabled) {
|
|
@@ -876,23 +854,6 @@ class Kernel {
|
|
|
876
854
|
_makeprid() {
|
|
877
855
|
return `jsii::promise::${this.nextid++}`;
|
|
878
856
|
}
|
|
879
|
-
_wrapSandboxCode(fn) {
|
|
880
|
-
return fn();
|
|
881
|
-
}
|
|
882
|
-
/**
|
|
883
|
-
* Executes arbitrary code in a VM sandbox.
|
|
884
|
-
*
|
|
885
|
-
* @param code JavaScript code to be executed in the VM
|
|
886
|
-
* @param sandbox a VM context to use for running the code
|
|
887
|
-
* @param sourceMaps source maps to be used in case an exception is thrown
|
|
888
|
-
* @param filename the file name to use for the executed code
|
|
889
|
-
*
|
|
890
|
-
* @returns the result of evaluating the code
|
|
891
|
-
*/
|
|
892
|
-
_execute(code, filename) {
|
|
893
|
-
const script = new vm.Script(code, { filename });
|
|
894
|
-
return script.runInContext(this.sandbox, { displayErrors: true });
|
|
895
|
-
}
|
|
896
857
|
}
|
|
897
858
|
exports.Kernel = Kernel;
|
|
898
859
|
class Assembly {
|
package/lib/objects.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare function tagJsiiConstructor(constructor: any, fqn: string): void;
|
|
|
26
26
|
*/
|
|
27
27
|
export declare class ObjectTable {
|
|
28
28
|
private readonly resolveType;
|
|
29
|
-
private objects;
|
|
29
|
+
private readonly objects;
|
|
30
30
|
private nextid;
|
|
31
31
|
constructor(resolveType: (fqn: string) => spec.Type);
|
|
32
32
|
/**
|
|
@@ -42,7 +42,7 @@ export declare class ObjectTable {
|
|
|
42
42
|
/**
|
|
43
43
|
* Delete the registration with the given objref
|
|
44
44
|
*/
|
|
45
|
-
deleteObject(
|
|
45
|
+
deleteObject({ [api.TOKEN_REF]: objid }: api.ObjRef): void;
|
|
46
46
|
get count(): number;
|
|
47
47
|
private makeId;
|
|
48
48
|
private removeRedundant;
|