@novolobos/nodevm 3.10.5

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.
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ const pa = require('path');
4
+ const fs = require('fs');
5
+
6
+ class DefaultFileSystem {
7
+
8
+ resolve(path) {
9
+ return pa.resolve(path);
10
+ }
11
+
12
+ isSeparator(char) {
13
+ return char === '/' || char === pa.sep;
14
+ }
15
+
16
+ isAbsolute(path) {
17
+ return pa.isAbsolute(path);
18
+ }
19
+
20
+ join(...paths) {
21
+ return pa.join(...paths);
22
+ }
23
+
24
+ basename(path) {
25
+ return pa.basename(path);
26
+ }
27
+
28
+ dirname(path) {
29
+ return pa.dirname(path);
30
+ }
31
+
32
+ statSync(path, options) {
33
+ return fs.statSync(path, options);
34
+ }
35
+
36
+ readFileSync(path, options) {
37
+ return fs.readFileSync(path, options);
38
+ }
39
+
40
+ }
41
+
42
+ class VMFileSystem {
43
+
44
+ constructor({fs: fsModule = fs, path: pathModule = pa} = {}) {
45
+ this.fs = fsModule;
46
+ this.path = pathModule;
47
+ }
48
+
49
+ resolve(path) {
50
+ return this.path.resolve(path);
51
+ }
52
+
53
+ isSeparator(char) {
54
+ return char === '/' || char === this.path.sep;
55
+ }
56
+
57
+ isAbsolute(path) {
58
+ return this.path.isAbsolute(path);
59
+ }
60
+
61
+ join(...paths) {
62
+ return this.path.join(...paths);
63
+ }
64
+
65
+ basename(path) {
66
+ return this.path.basename(path);
67
+ }
68
+
69
+ dirname(path) {
70
+ return this.path.dirname(path);
71
+ }
72
+
73
+ statSync(path, options) {
74
+ return this.fs.statSync(path, options);
75
+ }
76
+
77
+ readFileSync(path, options) {
78
+ return this.fs.readFileSync(path, options);
79
+ }
80
+
81
+ }
82
+
83
+ exports.DefaultFileSystem = DefaultFileSystem;
84
+ exports.VMFileSystem = VMFileSystem;
package/lib/main.js ADDED
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ VMError
5
+ } = require('./bridge');
6
+ const {
7
+ VMScript
8
+ } = require('./script');
9
+ const {
10
+ VM
11
+ } = require('./vm');
12
+ const {
13
+ NodeVM
14
+ } = require('./nodevm');
15
+ const {
16
+ VMFileSystem
17
+ } = require('./filesystem');
18
+ const {
19
+ Resolver
20
+ } = require('./resolver');
21
+ const {
22
+ makeResolverFromLegacyOptions
23
+ } = require('./resolver-compat');
24
+
25
+ exports.VMError = VMError;
26
+ exports.VMScript = VMScript;
27
+ exports.NodeVM = NodeVM;
28
+ exports.VM = VM;
29
+ exports.VMFileSystem = VMFileSystem;
30
+ exports.Resolver = Resolver;
31
+ exports.makeResolverFromLegacyOptions = makeResolverFromLegacyOptions;
package/lib/nodevm.js ADDED
@@ -0,0 +1,582 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * This callback will be called to resolve a module if it couldn't be found.
5
+ *
6
+ * @callback resolveCallback
7
+ * @param {string} moduleName - Name of the module used to resolve.
8
+ * @param {string} dirname - Name of the current directory.
9
+ * @return {(string|undefined)} The file or directory to use to load the requested module.
10
+ */
11
+
12
+ /**
13
+ * This callback will be called to require a module instead of node's require.
14
+ *
15
+ * @callback customRequire
16
+ * @param {string} moduleName - Name of the module requested.
17
+ * @return {*} The required module object.
18
+ */
19
+
20
+ /**
21
+ * This callback will be called to specify the context to use "per" module. Defaults to 'sandbox' if no return value provided.
22
+ *
23
+ * NOTE: many interoperating modules must live in the same context.
24
+ *
25
+ * @callback pathContextCallback
26
+ * @param {string} modulePath - The full path to the module filename being requested.
27
+ * @param {string} extensionType - The module type (node = native, js = cjs/esm module)
28
+ * @return {("host"|"sandbox")} The context for this module.
29
+ */
30
+
31
+ const fs = require('fs');
32
+ const pa = require('path');
33
+ const {
34
+ Script
35
+ } = require('vm');
36
+ const {
37
+ VMError
38
+ } = require('./bridge');
39
+ const {
40
+ VMScript,
41
+ MODULE_PREFIX,
42
+ STRICT_MODULE_PREFIX,
43
+ MODULE_SUFFIX
44
+ } = require('./script');
45
+ const {
46
+ transformer
47
+ } = require('./transformer');
48
+ const {
49
+ VM
50
+ } = require('./vm');
51
+ const {
52
+ makeResolverFromLegacyOptions
53
+ } = require('./resolver-compat');
54
+ const { Resolver } = require('./resolver');
55
+
56
+ const objectDefineProperty = Object.defineProperty;
57
+ const objectDefineProperties = Object.defineProperties;
58
+
59
+ /**
60
+ * Host objects
61
+ *
62
+ * @private
63
+ */
64
+ const HOST = Object.freeze({
65
+ __proto__: null,
66
+ version: parseInt(process.versions.node.split('.')[0]),
67
+ process,
68
+ console,
69
+ setTimeout,
70
+ setInterval,
71
+ setImmediate,
72
+ clearTimeout,
73
+ clearInterval,
74
+ clearImmediate
75
+ });
76
+
77
+ /**
78
+ * Compile a script.
79
+ *
80
+ * @private
81
+ * @param {string} filename - Filename of the script.
82
+ * @param {string} script - Script.
83
+ * @return {vm.Script} The compiled script.
84
+ */
85
+ function compileScript(filename, script) {
86
+ return new Script(script, {
87
+ __proto__: null,
88
+ filename,
89
+ displayErrors: false
90
+ });
91
+ }
92
+
93
+ let cacheSandboxScript = null;
94
+ let cacheMakeNestingScript = null;
95
+
96
+ const NESTING_OVERRIDE = Object.freeze({
97
+ __proto__: null,
98
+ vm2: vm2NestingLoader
99
+ });
100
+
101
+ function makeCustomExtensions(vm, resolver, sourceExtensions) {
102
+ const extensions = { __proto__: null };
103
+ const loadJS = resolver.makeExtensionHandler(vm, 'loadJS');
104
+
105
+ for (let i = 0; i < sourceExtensions.length; i++) {
106
+ extensions['.' + sourceExtensions[i]] = loadJS;
107
+ }
108
+
109
+ if (!extensions['.json']) extensions['.json'] = resolver.makeExtensionHandler(vm, 'loadJSON');
110
+ if (!extensions['.node']) extensions['.node'] = resolver.makeExtensionHandler(vm, 'loadNode');
111
+ return extensions;
112
+ }
113
+
114
+ function makeSafePaths(unsafePaths) {
115
+ if (unsafePaths === undefined) return undefined;
116
+ if (!Array.isArray(unsafePaths)) return true;
117
+ const paths = [...unsafePaths];
118
+ if (paths.some(path => typeof path !== 'string')) return true;
119
+ return paths;
120
+ }
121
+
122
+ function makeSafeOptions(unsafeOptions) {
123
+ if (unsafeOptions === undefined || unsafeOptions == null) return unsafeOptions;
124
+ if (typeof unsafeOptions !== 'object' && typeof unsafeOptions !== 'function') return unsafeOptions;
125
+ return {
126
+ unsafeOptions,
127
+ paths: makeSafePaths(unsafeOptions.paths)
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Event caused by a <code>console.debug</code> call if <code>options.console="redirect"</code> is specified.
133
+ *
134
+ * @public
135
+ * @event NodeVM."console.debug"
136
+ * @type {...*}
137
+ */
138
+
139
+ /**
140
+ * Event caused by a <code>console.log</code> call if <code>options.console="redirect"</code> is specified.
141
+ *
142
+ * @public
143
+ * @event NodeVM."console.log"
144
+ * @type {...*}
145
+ */
146
+
147
+ /**
148
+ * Event caused by a <code>console.info</code> call if <code>options.console="redirect"</code> is specified.
149
+ *
150
+ * @public
151
+ * @event NodeVM."console.info"
152
+ * @type {...*}
153
+ */
154
+
155
+ /**
156
+ * Event caused by a <code>console.warn</code> call if <code>options.console="redirect"</code> is specified.
157
+ *
158
+ * @public
159
+ * @event NodeVM."console.warn"
160
+ * @type {...*}
161
+ */
162
+
163
+ /**
164
+ * Event caused by a <code>console.error</code> call if <code>options.console="redirect"</code> is specified.
165
+ *
166
+ * @public
167
+ * @event NodeVM."console.error"
168
+ * @type {...*}
169
+ */
170
+
171
+ /**
172
+ * Event caused by a <code>console.dir</code> call if <code>options.console="redirect"</code> is specified.
173
+ *
174
+ * @public
175
+ * @event NodeVM."console.dir"
176
+ * @type {...*}
177
+ */
178
+
179
+ /**
180
+ * Event caused by a <code>console.trace</code> call if <code>options.console="redirect"</code> is specified.
181
+ *
182
+ * @public
183
+ * @event NodeVM."console.trace"
184
+ * @type {...*}
185
+ */
186
+
187
+ /**
188
+ * Class NodeVM.
189
+ *
190
+ * @public
191
+ * @extends {VM}
192
+ * @extends {EventEmitter}
193
+ */
194
+ class NodeVM extends VM {
195
+
196
+ /**
197
+ * Create a new NodeVM instance.<br>
198
+ *
199
+ * Unlike VM, NodeVM lets you use require same way like in regular node.<br>
200
+ *
201
+ * However, it does not use the timeout.
202
+ *
203
+ * @public
204
+ * @param {Object} [options] - VM options.
205
+ * @param {Object} [options.sandbox] - Objects that will be copied into the global object of the sandbox.
206
+ * @param {(string|compileCallback)} [options.compiler="javascript"] - The compiler to use.
207
+ * @param {boolean} [options.eval=true] - Allow the dynamic evaluation of code via eval(code) or Function(code)().<br>
208
+ * Only available for node v10+.
209
+ * @param {boolean} [options.wasm=true] - Allow to run wasm code.<br>
210
+ * Only available for node v10+.
211
+ * @param {("inherit"|"redirect"|"off")} [options.console="inherit"] - Sets the behavior of the console in the sandbox.
212
+ * <code>inherit</code> to enable console, <code>redirect</code> to redirect to events, <code>off</code> to disable console.
213
+ * @param {Object|boolean|Resolver} [options.require=false] - Allow require inside the sandbox.
214
+ * @param {(boolean|string[]|Object)} [options.require.external=false] - <b>WARNING: When allowing require the option <code>options.require.root</code>
215
+ * should be set to restrict the script from requiring any module. Values can be true, an array of allowed external modules or an object.
216
+ * @param {(string[])} [options.require.external.modules] - Array of allowed external modules. Also supports wildcards, so specifying ['@scope/*-ver-??],
217
+ * for instance, will allow using all modules having a name of the form @scope/something-ver-aa, @scope/other-ver-11, etc.
218
+ * @param {boolean} [options.require.external.transitive=false] - Boolean which indicates if transitive dependencies of external modules are allowed.
219
+ * @param {string[]} [options.require.builtin=[]] - Array of allowed built-in modules, accepts ["*"] for all.
220
+ * @param {(string|string[])} [options.require.root] - Restricted path(s) where local modules can be required. If omitted every path is allowed.
221
+ * @param {Object} [options.require.mock] - Collection of mock modules (both external or built-in).
222
+ * @param {("host"|"sandbox"|pathContextCallback)} [options.require.context="host"] -
223
+ * <code>host</code> to require modules in host and proxy them to sandbox.
224
+ * <code>sandbox</code> to load, compile and require modules in sandbox.
225
+ * <code>pathContext(modulePath, ext)</code> to choose a mode per module (full path provided).
226
+ * Builtin modules except <code>events</code> always required in host and proxied to sandbox.
227
+ * @param {string[]} [options.require.import] - Array of modules to be loaded into NodeVM on start.
228
+ * @param {resolveCallback} [options.require.resolve] - An additional lookup function in case a module wasn't
229
+ * found in one of the traditional node lookup paths.
230
+ * @param {customRequire} [options.require.customRequire=require] - Custom require to require host and built-in modules.
231
+ * @param {boolean} [options.require.strict=true] - Load required modules in strict mode.
232
+ * @param {boolean} [options.nesting=false] -
233
+ * <b>WARNING: Allowing this is a security risk as scripts can create a NodeVM which can require any host module.</b>
234
+ * Allow nesting of VMs.
235
+ * @param {("commonjs"|"none")} [options.wrapper="commonjs"] - <code>commonjs</code> to wrap script into CommonJS wrapper,
236
+ * <code>none</code> to retrieve value returned by the script.
237
+ * @param {string[]} [options.sourceExtensions=["js"]] - Array of file extensions to treat as source code.
238
+ * @param {string[]} [options.argv=[]] - Array of arguments passed to <code>process.argv</code>.
239
+ * This object will not be copied and the script can change this object.
240
+ * @param {Object} [options.env={}] - Environment map passed to <code>process.env</code>.
241
+ * This object will not be copied and the script can change this object.
242
+ * @param {boolean} [options.strict=false] - If modules should be loaded in strict mode.
243
+ * @throws {VMError} If the compiler is unknown.
244
+ */
245
+ constructor(options = {}) {
246
+ const {
247
+ compiler,
248
+ eval: allowEval,
249
+ wasm,
250
+ console: consoleType = 'inherit',
251
+ require: requireOpts = false,
252
+ nesting = false,
253
+ wrapper = 'commonjs',
254
+ sourceExtensions = ['js'],
255
+ argv,
256
+ env,
257
+ strict = false,
258
+ sandbox
259
+ } = options;
260
+
261
+ // Throw this early
262
+ if (sandbox && 'object' !== typeof sandbox) {
263
+ throw new VMError('Sandbox must be an object.');
264
+ }
265
+
266
+ super({__proto__: null, compiler: compiler, eval: allowEval, wasm});
267
+
268
+ const customResolver = requireOpts instanceof Resolver;
269
+ const resolver = customResolver ? requireOpts : makeResolverFromLegacyOptions(requireOpts, nesting && NESTING_OVERRIDE, this._compiler);
270
+
271
+ // This is only here for backwards compatibility.
272
+ objectDefineProperty(this, 'options', {__proto__: null, value: {
273
+ console: consoleType,
274
+ require: requireOpts,
275
+ nesting,
276
+ wrapper,
277
+ sourceExtensions,
278
+ strict
279
+ }});
280
+
281
+ objectDefineProperty(this, 'resolver', {__proto__: null, value: resolver, enumerable: true});
282
+
283
+ if (!cacheSandboxScript) {
284
+ cacheSandboxScript = compileScript(`${__dirname}/setup-node-sandbox.js`,
285
+ `(function (host, data) { ${fs.readFileSync(`${__dirname}/setup-node-sandbox.js`, 'utf8')}\n})`);
286
+ }
287
+
288
+ const closure = this._runScript(cacheSandboxScript);
289
+
290
+ const extensions = makeCustomExtensions(this, resolver, sourceExtensions);
291
+
292
+ this.readonly(HOST);
293
+
294
+ const {
295
+ Module,
296
+ jsonParse,
297
+ createRequireForModule,
298
+ requireImpl
299
+ } = closure(HOST, {
300
+ __proto__: null,
301
+ argv,
302
+ env,
303
+ console: consoleType,
304
+ extensions,
305
+ emitArgs: (event, args) => {
306
+ if (typeof event !== 'string' && typeof event !== 'symbol') throw new Error('Event is not a string');
307
+ return this.emit(event, ...args);
308
+ },
309
+ globalPaths: [...resolver.globalPaths],
310
+ getLookupPathsFor: (path) => {
311
+ if (typeof path !== 'string') return [];
312
+ return [...resolver.genLookupPaths(path)];
313
+ },
314
+ resolve: (mod, id, opt, ext, direct) => {
315
+ if (typeof id !== 'string') throw new Error('Id is not a string');
316
+ const extList = Object.getOwnPropertyNames(ext);
317
+ return resolver.resolve(mod, id, makeSafeOptions(opt), extList, !!direct);
318
+ },
319
+ lookupPaths: (mod, id) => {
320
+ if (typeof id !== 'string') throw new Error('Id is not a string');
321
+ return [...resolver.lookupPaths(mod, id)];
322
+ },
323
+ loadBuiltinModule: (id) => {
324
+ if (typeof id !== 'string') throw new Error('Id is not a string');
325
+ return resolver.loadBuiltinModule(this, id);
326
+ },
327
+ registerModule: (mod, filename, path, parent, direct) => {
328
+ return resolver.registerModule(mod, filename, path, parent, direct);
329
+ },
330
+ builtinModules: [...resolver.getBuiltinModulesList(this)],
331
+ dirname: (path) => {
332
+ if (typeof path !== 'string') return path;
333
+ return resolver.fs.dirname(path);
334
+ },
335
+ basename: (path) => {
336
+ if (typeof path !== 'string') return path;
337
+ return resolver.fs.basename(path);
338
+ }
339
+ });
340
+
341
+ objectDefineProperties(this, {
342
+ __proto__: null,
343
+ _Module: {__proto__: null, value: Module},
344
+ _jsonParse: {__proto__: null, value: jsonParse},
345
+ _createRequireForModule: {__proto__: null, value: createRequireForModule},
346
+ _requireImpl: {__proto__: null, value: requireImpl},
347
+ _cacheRequireModule: {__proto__: null, value: null, writable: true}
348
+ });
349
+
350
+
351
+ resolver.init(this);
352
+
353
+ // prepare global sandbox
354
+ if (sandbox) {
355
+ this.setGlobals(sandbox);
356
+ }
357
+
358
+ if (!customResolver && requireOpts && requireOpts.import) {
359
+ if (Array.isArray(requireOpts.import)) {
360
+ for (let i = 0, l = requireOpts.import.length; i < l; i++) {
361
+ this.require(requireOpts.import[i]);
362
+ }
363
+ } else {
364
+ this.require(requireOpts.import);
365
+ }
366
+ }
367
+ }
368
+
369
+ /**
370
+ * @ignore
371
+ * @deprecated
372
+ */
373
+ get _resolver() {
374
+ return this.resolver;
375
+ }
376
+
377
+ /**
378
+ * @ignore
379
+ * @deprecated Just call the method yourself like <code>method(args);</code>
380
+ * @param {function} method - Function to invoke.
381
+ * @param {...*} args - Arguments to pass to the function.
382
+ * @return {*} Return value of the function.
383
+ * @todo Can we remove this function? It even had a bug that would use args as this parameter.
384
+ * @throws {*} Rethrows anything the method throws.
385
+ * @throws {VMError} If method is not a function.
386
+ * @throws {Error} If method is a class.
387
+ */
388
+ call(method, ...args) {
389
+ if ('function' === typeof method) {
390
+ return method(...args);
391
+ } else {
392
+ throw new VMError('Unrecognized method type.');
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Require a module in VM and return it's exports.
398
+ *
399
+ * @public
400
+ * @param {string} module - Module name.
401
+ * @return {*} Exported module.
402
+ * @throws {*} If the module couldn't be found or loading it threw an error.
403
+ */
404
+ require(module) {
405
+ const path = this.resolver.fs.resolve('.');
406
+ let mod = this._cacheRequireModule;
407
+ if (!mod || mod.path !== path) {
408
+ const filename = this.resolver.fs.join(path, '/vm.js');
409
+ mod = new (this._Module)(filename, path);
410
+ this.resolver.registerModule(mod, filename, path, null, false);
411
+ this._cacheRequireModule = mod;
412
+ }
413
+ return this._requireImpl(mod, module, true);
414
+ }
415
+
416
+ /**
417
+ * Run the code in NodeVM.
418
+ *
419
+ * First time you run this method, code is executed same way like in node's regular `require` - it's executed with
420
+ * `module`, `require`, `exports`, `__dirname`, `__filename` variables and expect result in `module.exports'.
421
+ *
422
+ * @param {(string|VMScript)} code - Code to run.
423
+ * @param {(string|Object)} [options] - Options map or filename.
424
+ * @param {string} [options.filename="vm.js"] - Filename that shows up in any stack traces produced from this script.<br>
425
+ * This is only used if code is a String.
426
+ * @param {boolean} [options.strict] - If modules should be loaded in strict mode. Defaults to NodeVM options.
427
+ * @param {("commonjs"|"none")} [options.wrapper] - <code>commonjs</code> to wrap script into CommonJS wrapper,
428
+ * <code>none</code> to retrieve value returned by the script. Defaults to NodeVM options.
429
+ * @return {*} Result of executed code.
430
+ * @throws {SyntaxError} If there is a syntax error in the script.
431
+ * @throws {*} If the script execution terminated with an exception it is propagated.
432
+ * @fires NodeVM."console.debug"
433
+ * @fires NodeVM."console.log"
434
+ * @fires NodeVM."console.info"
435
+ * @fires NodeVM."console.warn"
436
+ * @fires NodeVM."console.error"
437
+ * @fires NodeVM."console.dir"
438
+ * @fires NodeVM."console.trace"
439
+ */
440
+ run(code, options) {
441
+ let script;
442
+ let filename;
443
+
444
+ if (typeof options === 'object') {
445
+ filename = options.filename;
446
+ } else {
447
+ filename = options;
448
+ options = {__proto__: null};
449
+ }
450
+
451
+ const {
452
+ strict = this.options.strict,
453
+ wrapper = this.options.wrapper,
454
+ module: customModule,
455
+ require: customRequire,
456
+ dirname: customDirname = null
457
+ } = options;
458
+
459
+ let sandboxModule = customModule;
460
+ let dirname = customDirname;
461
+
462
+ if (code instanceof VMScript) {
463
+ script = strict ? code._compileNodeVMStrict() : code._compileNodeVM();
464
+ if (!sandboxModule) {
465
+ const resolvedFilename = this.resolver.fs.resolve(code.filename);
466
+ dirname = this.resolver.fs.dirname(resolvedFilename);
467
+ sandboxModule = new (this._Module)(resolvedFilename, dirname);
468
+ this.resolver.registerModule(sandboxModule, resolvedFilename, dirname, null, false);
469
+ }
470
+ } else {
471
+ const unresolvedFilename = filename || 'vm.js';
472
+ if (!sandboxModule) {
473
+ if (filename) {
474
+ const resolvedFilename = this.resolver.fs.resolve(filename);
475
+ dirname = this.resolver.fs.dirname(resolvedFilename);
476
+ sandboxModule = new (this._Module)(resolvedFilename, dirname);
477
+ this.resolver.registerModule(sandboxModule, resolvedFilename, dirname, null, false);
478
+ } else {
479
+ sandboxModule = new (this._Module)(null, null);
480
+ sandboxModule.id = unresolvedFilename;
481
+ }
482
+ }
483
+ const prefix = strict ? STRICT_MODULE_PREFIX : MODULE_PREFIX;
484
+ let scriptCode = this._compiler(code, unresolvedFilename);
485
+ scriptCode = transformer(null, scriptCode, false, false, unresolvedFilename).code;
486
+ script = new Script(prefix + scriptCode + MODULE_SUFFIX, {
487
+ __proto__: null,
488
+ filename: unresolvedFilename,
489
+ displayErrors: false
490
+ });
491
+ }
492
+
493
+ const closure = this._runScript(script);
494
+
495
+ const usedRequire = customRequire || this._createRequireForModule(sandboxModule);
496
+
497
+ const ret = Reflect.apply(closure, this.sandbox, [sandboxModule.exports, usedRequire, sandboxModule, filename, dirname]);
498
+ return wrapper === 'commonjs' ? sandboxModule.exports : ret;
499
+ }
500
+
501
+ /**
502
+ * Create NodeVM and run code inside it.
503
+ *
504
+ * @public
505
+ * @static
506
+ * @param {string} script - Code to execute.
507
+ * @param {string} [filename] - File name (used in stack traces only).
508
+ * @param {Object} [options] - VM options.
509
+ * @param {string} [options.filename] - File name (used in stack traces only). Used if <code>filename</code> is omitted.
510
+ * @return {*} Result of executed code.
511
+ * @see {@link NodeVM} for the options.
512
+ * @throws {SyntaxError} If there is a syntax error in the script.
513
+ * @throws {*} If the script execution terminated with an exception it is propagated.
514
+ */
515
+ static code(script, filename, options) {
516
+ let unresolvedFilename;
517
+ if (filename != null) {
518
+ if ('object' === typeof filename) {
519
+ options = filename;
520
+ unresolvedFilename = options.filename;
521
+ } else if ('string' === typeof filename) {
522
+ unresolvedFilename = filename;
523
+ } else {
524
+ throw new VMError('Invalid arguments.');
525
+ }
526
+ } else if ('object' === typeof options) {
527
+ unresolvedFilename = options.filename;
528
+ }
529
+
530
+ if (arguments.length > 3) {
531
+ throw new VMError('Invalid number of arguments.');
532
+ }
533
+
534
+ const resolvedFilename = typeof unresolvedFilename === 'string' ? pa.resolve(unresolvedFilename) : undefined;
535
+
536
+ return new NodeVM(options).run(script, resolvedFilename);
537
+ }
538
+
539
+ /**
540
+ * Create NodeVM and run script from file inside it.
541
+ *
542
+ * @public
543
+ * @static
544
+ * @param {string} filename - Filename of file to load and execute in a NodeVM.
545
+ * @param {Object} [options] - NodeVM options.
546
+ * @return {*} Result of executed code.
547
+ * @see {@link NodeVM} for the options.
548
+ * @throws {Error} If filename is not a valid filename.
549
+ * @throws {SyntaxError} If there is a syntax error in the script.
550
+ * @throws {*} If the script execution terminated with an exception it is propagated.
551
+ */
552
+ static file(filename, options) {
553
+ const resolvedFilename = pa.resolve(filename);
554
+ const fileExtension = pa.extname(filename);
555
+
556
+ if (!fs.existsSync(resolvedFilename)) {
557
+ throw new VMError(`Script '${filename}' not found.`);
558
+ }
559
+
560
+ if (fs.statSync(resolvedFilename).isDirectory()) {
561
+ throw new VMError('Script must be file, got directory.');
562
+ }
563
+
564
+ if ((fileExtension === '.ts' || fileExtension === '.cs' || fileExtension === '.coffee') && (!options || !options.compiler)) {
565
+ options = Object.assign({}, options, {
566
+ compiler: fileExtension.substring(1)
567
+ });
568
+ }
569
+
570
+ return new NodeVM(options).run(fs.readFileSync(resolvedFilename, 'utf8'), resolvedFilename);
571
+ }
572
+ }
573
+
574
+ function vm2NestingLoader(vm) {
575
+ if (!cacheMakeNestingScript) {
576
+ cacheMakeNestingScript = compileScript('nesting.js', '(vm, nodevm) => ({VM: vm, NodeVM: nodevm})');
577
+ }
578
+ const makeNesting = vm._runScript(cacheMakeNestingScript);
579
+ return makeNesting(vm.readonly(VM), vm.readonly(NodeVM));
580
+ }
581
+
582
+ exports.NodeVM = NodeVM;