You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					505 lines
				
				16 KiB
			
		
		
			
		
	
	
					505 lines
				
				16 KiB
			| 
											3 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | /** | ||
|  |  * This callback will be called to resolve a module if it couldn't be found. | ||
|  |  * | ||
|  |  * @callback resolveCallback | ||
|  |  * @param {string} moduleName - Name of the module used to resolve. | ||
|  |  * @param {string} dirname - Name of the current directory. | ||
|  |  * @return {(string|undefined)} The file or directory to use to load the requested module. | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * This callback will be called to require a module instead of node's require. | ||
|  |  * | ||
|  |  * @callback customRequire | ||
|  |  * @param {string} moduleName - Name of the module requested. | ||
|  |  * @return {*} The required module object. | ||
|  |  */ | ||
|  | 
 | ||
|  | const fs = require('fs'); | ||
|  | const pa = require('path'); | ||
|  | const { | ||
|  | 	Script | ||
|  | } = require('vm'); | ||
|  | const { | ||
|  | 	VMError | ||
|  | } = require('./bridge'); | ||
|  | const { | ||
|  | 	VMScript, | ||
|  | 	MODULE_PREFIX, | ||
|  | 	STRICT_MODULE_PREFIX, | ||
|  | 	MODULE_SUFFIX | ||
|  | } = require('./script'); | ||
|  | const { | ||
|  | 	transformer | ||
|  | } = require('./transformer'); | ||
|  | const { | ||
|  | 	VM | ||
|  | } = require('./vm'); | ||
|  | const { | ||
|  | 	resolverFromOptions | ||
|  | } = require('./resolver-compat'); | ||
|  | 
 | ||
|  | const objectDefineProperty = Object.defineProperty; | ||
|  | const objectDefineProperties = Object.defineProperties; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Host objects | ||
|  |  * | ||
|  |  * @private | ||
|  |  */ | ||
|  | const HOST = Object.freeze({ | ||
|  | 	__proto__: null, | ||
|  | 	version: parseInt(process.versions.node.split('.')[0]), | ||
|  | 	process, | ||
|  | 	console, | ||
|  | 	setTimeout, | ||
|  | 	setInterval, | ||
|  | 	setImmediate, | ||
|  | 	clearTimeout, | ||
|  | 	clearInterval, | ||
|  | 	clearImmediate | ||
|  | }); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Compile a script. | ||
|  |  * | ||
|  |  * @private | ||
|  |  * @param {string} filename - Filename of the script. | ||
|  |  * @param {string} script - Script. | ||
|  |  * @return {vm.Script} The compiled script. | ||
|  |  */ | ||
|  | function compileScript(filename, script) { | ||
|  | 	return new Script(script, { | ||
|  | 		__proto__: null, | ||
|  | 		filename, | ||
|  | 		displayErrors: false | ||
|  | 	}); | ||
|  | } | ||
|  | 
 | ||
|  | let cacheSandboxScript = null; | ||
|  | let cacheMakeNestingScript = null; | ||
|  | 
 | ||
|  | const NESTING_OVERRIDE = Object.freeze({ | ||
|  | 	__proto__: null, | ||
|  | 	vm2: vm2NestingLoader | ||
|  | }); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.debug</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.debug" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.log</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.log" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.info</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.info" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.warn</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.warn" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.error</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.error" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.dir</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.dir" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Event caused by a <code>console.trace</code> call if <code>options.console="redirect"</code> is specified. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @event NodeVM."console.trace" | ||
|  |  * @type {...*} | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Class NodeVM. | ||
|  |  * | ||
|  |  * @public | ||
|  |  * @extends {VM} | ||
|  |  * @extends {EventEmitter} | ||
|  |  */ | ||
|  | class NodeVM extends VM { | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * Create a new NodeVM instance.<br> | ||
|  | 	 * | ||
|  | 	 * Unlike VM, NodeVM lets you use require same way like in regular node.<br> | ||
|  | 	 * | ||
|  | 	 * However, it does not use the timeout. | ||
|  | 	 * | ||
|  | 	 * @public | ||
|  | 	 * @param {Object} [options] - VM options. | ||
|  | 	 * @param {Object} [options.sandbox] - Objects that will be copied into the global object of the sandbox. | ||
|  | 	 * @param {(string|compileCallback)} [options.compiler="javascript"] - The compiler to use. | ||
|  | 	 * @param {boolean} [options.eval=true] - Allow the dynamic evaluation of code via eval(code) or Function(code)().<br> | ||
|  | 	 * Only available for node v10+. | ||
|  | 	 * @param {boolean} [options.wasm=true] - Allow to run wasm code.<br> | ||
|  | 	 * Only available for node v10+. | ||
|  | 	 * @param {("inherit"|"redirect"|"off")} [options.console="inherit"] - Sets the behavior of the console in the sandbox. | ||
|  | 	 * <code>inherit</code> to enable console, <code>redirect</code> to redirect to events, <code>off</code> to disable console. | ||
|  | 	 * @param {Object|boolean} [options.require=false] - Allow require inside the sandbox. | ||
|  | 	 * @param {(boolean|string[]|Object)} [options.require.external=false] - <b>WARNING: When allowing require the option <code>options.require.root</code> | ||
|  | 	 * should be set to restrict the script from requiring any module. Values can be true, an array of allowed external modules or an object. | ||
|  | 	 * @param {(string[])} [options.require.external.modules] - Array of allowed external modules. Also supports wildcards, so specifying ['@scope/*-ver-??], | ||
|  | 	 * for instance, will allow using all modules having a name of the form @scope/something-ver-aa, @scope/other-ver-11, etc. | ||
|  | 	 * @param {boolean} [options.require.external.transitive=false] - Boolean which indicates if transitive dependencies of external modules are allowed. | ||
|  | 	 * @param {string[]} [options.require.builtin=[]] - Array of allowed built-in modules, accepts ["*"] for all. | ||
|  | 	 * @param {(string|string[])} [options.require.root] - Restricted path(s) where local modules can be required. If omitted every path is allowed. | ||
|  | 	 * @param {Object} [options.require.mock] - Collection of mock modules (both external or built-in). | ||
|  | 	 * @param {("host"|"sandbox")} [options.require.context="host"] - <code>host</code> to require modules in host and proxy them to sandbox. | ||
|  | 	 * <code>sandbox</code> to load, compile and require modules in sandbox. | ||
|  | 	 * Builtin modules except <code>events</code> always required in host and proxied to sandbox. | ||
|  | 	 * @param {string[]} [options.require.import] - Array of modules to be loaded into NodeVM on start. | ||
|  | 	 * @param {resolveCallback} [options.require.resolve] - An additional lookup function in case a module wasn't | ||
|  | 	 * found in one of the traditional node lookup paths. | ||
|  | 	 * @param {customRequire} [options.require.customRequire=require] - Custom require to require host and built-in modules. | ||
|  | 	 * @param {boolean} [option.require.strict=true] - Load required modules in strict mode. | ||
|  | 	 * @param {boolean} [options.nesting=false] - | ||
|  | 	 * <b>WARNING: Allowing this is a security risk as scripts can create a NodeVM which can require any host module.</b> | ||
|  | 	 * Allow nesting of VMs. | ||
|  | 	 * @param {("commonjs"|"none")} [options.wrapper="commonjs"] - <code>commonjs</code> to wrap script into CommonJS wrapper, | ||
|  | 	 * <code>none</code> to retrieve value returned by the script. | ||
|  | 	 * @param {string[]} [options.sourceExtensions=["js"]] - Array of file extensions to treat as source code. | ||
|  | 	 * @param {string[]} [options.argv=[]] - Array of arguments passed to <code>process.argv</code>. | ||
|  | 	 * This object will not be copied and the script can change this object. | ||
|  | 	 * @param {Object} [options.env={}] - Environment map passed to <code>process.env</code>. | ||
|  | 	 * This object will not be copied and the script can change this object. | ||
|  | 	 * @param {boolean} [options.strict=false] - If modules should be loaded in strict mode. | ||
|  | 	 * @throws {VMError} If the compiler is unknown. | ||
|  | 	 */ | ||
|  | 	constructor(options = {}) { | ||
|  | 		const { | ||
|  | 			compiler, | ||
|  | 			eval: allowEval, | ||
|  | 			wasm, | ||
|  | 			console: consoleType = 'inherit', | ||
|  | 			require: requireOpts = false, | ||
|  | 			nesting = false, | ||
|  | 			wrapper = 'commonjs', | ||
|  | 			sourceExtensions = ['js'], | ||
|  | 			argv, | ||
|  | 			env, | ||
|  | 			strict = false, | ||
|  | 			sandbox | ||
|  | 		} = options; | ||
|  | 
 | ||
|  | 		// Throw this early
 | ||
|  | 		if (sandbox && 'object' !== typeof sandbox) { | ||
|  | 			throw new VMError('Sandbox must be an object.'); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		super({__proto__: null, compiler: compiler, eval: allowEval, wasm}); | ||
|  | 
 | ||
|  | 		// This is only here for backwards compatibility.
 | ||
|  | 		objectDefineProperty(this, 'options', {__proto__: null, value: { | ||
|  | 			console: consoleType, | ||
|  | 			require: requireOpts, | ||
|  | 			nesting, | ||
|  | 			wrapper, | ||
|  | 			sourceExtensions, | ||
|  | 			strict | ||
|  | 		}}); | ||
|  | 
 | ||
|  | 		const resolver = resolverFromOptions(this, requireOpts, nesting && NESTING_OVERRIDE, this._compiler); | ||
|  | 
 | ||
|  | 		objectDefineProperty(this, '_resolver', {__proto__: null, value: resolver}); | ||
|  | 
 | ||
|  | 		if (!cacheSandboxScript) { | ||
|  | 			cacheSandboxScript = compileScript(`${__dirname}/setup-node-sandbox.js`, | ||
|  | 				`(function (host, data) { ${fs.readFileSync(`${__dirname}/setup-node-sandbox.js`, 'utf8')}\n})`); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const closure = this._runScript(cacheSandboxScript); | ||
|  | 
 | ||
|  | 		const extensions = { | ||
|  | 			__proto__: null | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const loadJS = (mod, filename) => resolver.loadJS(this, mod, filename); | ||
|  | 
 | ||
|  | 		for (let i = 0; i < sourceExtensions.length; i++) { | ||
|  | 			extensions['.' + sourceExtensions[i]] = loadJS; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (!extensions['.json']) extensions['.json'] = (mod, filename) => resolver.loadJSON(this, mod, filename); | ||
|  | 		if (!extensions['.node']) extensions['.node'] = (mod, filename) => resolver.loadNode(this, mod, filename); | ||
|  | 
 | ||
|  | 
 | ||
|  | 		this.readonly(HOST); | ||
|  | 		this.readonly(resolver); | ||
|  | 		this.readonly(this); | ||
|  | 
 | ||
|  | 		const { | ||
|  | 			Module, | ||
|  | 			jsonParse, | ||
|  | 			createRequireForModule, | ||
|  | 			requireImpl | ||
|  | 		} = closure(HOST, { | ||
|  | 			__proto__: null, | ||
|  | 			argv, | ||
|  | 			env, | ||
|  | 			console: consoleType, | ||
|  | 			vm: this, | ||
|  | 			resolver, | ||
|  | 			extensions | ||
|  | 		}); | ||
|  | 
 | ||
|  | 		objectDefineProperties(this, { | ||
|  | 			__proto__: null, | ||
|  | 			_Module: {__proto__: null, value: Module}, | ||
|  | 			_jsonParse: {__proto__: null, value: jsonParse}, | ||
|  | 			_createRequireForModule: {__proto__: null, value: createRequireForModule}, | ||
|  | 			_requireImpl: {__proto__: null, value: requireImpl}, | ||
|  | 			_cacheRequireModule: {__proto__: null, value: null, writable: true} | ||
|  | 		}); | ||
|  | 
 | ||
|  | 
 | ||
|  | 		resolver.init(this); | ||
|  | 
 | ||
|  | 		// prepare global sandbox
 | ||
|  | 		if (sandbox) { | ||
|  | 			this.setGlobals(sandbox); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (requireOpts && requireOpts.import) { | ||
|  | 			if (Array.isArray(requireOpts.import)) { | ||
|  | 				for (let i = 0, l = requireOpts.import.length; i < l; i++) { | ||
|  | 					this.require(requireOpts.import[i]); | ||
|  | 				} | ||
|  | 			} else { | ||
|  | 				this.require(requireOpts.import); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @ignore | ||
|  | 	 * @deprecated Just call the method yourself like <code>method(args);</code> | ||
|  | 	 * @param {function} method - Function to invoke. | ||
|  | 	 * @param {...*} args - Arguments to pass to the function. | ||
|  | 	 * @return {*} Return value of the function. | ||
|  | 	 * @todo Can we remove this function? It even had a bug that would use args as this parameter. | ||
|  | 	 * @throws {*} Rethrows anything the method throws. | ||
|  | 	 * @throws {VMError} If method is not a function. | ||
|  | 	 * @throws {Error} If method is a class. | ||
|  | 	 */ | ||
|  | 	call(method, ...args) { | ||
|  | 		if ('function' === typeof method) { | ||
|  | 			return method(...args); | ||
|  | 		} else { | ||
|  | 			throw new VMError('Unrecognized method type.'); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * Require a module in VM and return it's exports. | ||
|  | 	 * | ||
|  | 	 * @public | ||
|  | 	 * @param {string} module - Module name. | ||
|  | 	 * @return {*} Exported module. | ||
|  | 	 * @throws {*} If the module couldn't be found or loading it threw an error. | ||
|  | 	 */ | ||
|  | 	require(module) { | ||
|  | 		const path = this._resolver.pathResolve('.'); | ||
|  | 		let mod = this._cacheRequireModule; | ||
|  | 		if (!mod || mod.path !== path) { | ||
|  | 			const filename = this._resolver.pathConcat(path, '/vm.js'); | ||
|  | 			mod = new (this._Module)(filename, path); | ||
|  | 			this._resolver.registerModule(mod, filename, path, null, false); | ||
|  | 			this._cacheRequireModule = mod; | ||
|  | 		} | ||
|  | 		return this._requireImpl(mod, module, true); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * Run the code in NodeVM. | ||
|  | 	 * | ||
|  | 	 * First time you run this method, code is executed same way like in node's regular `require` - it's executed with | ||
|  | 	 * `module`, `require`, `exports`, `__dirname`, `__filename` variables and expect result in `module.exports'.
 | ||
|  | 	 * | ||
|  | 	 * @param {(string|VMScript)} code - Code to run. | ||
|  | 	 * @param {(string|Object)} [options] - Options map or filename. | ||
|  | 	 * @param {string} [options.filename="vm.js"] - Filename that shows up in any stack traces produced from this script.<br> | ||
|  | 	 * This is only used if code is a String. | ||
|  | 	 * @param {boolean} [options.strict] - If modules should be loaded in strict mode. Defaults to NodeVM options. | ||
|  | 	 * @param {("commonjs"|"none")} [options.wrapper] - <code>commonjs</code> to wrap script into CommonJS wrapper, | ||
|  | 	 * <code>none</code> to retrieve value returned by the script. Defaults to NodeVM options. | ||
|  | 	 * @return {*} Result of executed code. | ||
|  | 	 * @throws {SyntaxError} If there is a syntax error in the script. | ||
|  | 	 * @throws {*} If the script execution terminated with an exception it is propagated. | ||
|  | 	 * @fires NodeVM."console.debug" | ||
|  | 	 * @fires NodeVM."console.log" | ||
|  | 	 * @fires NodeVM."console.info" | ||
|  | 	 * @fires NodeVM."console.warn" | ||
|  | 	 * @fires NodeVM."console.error" | ||
|  | 	 * @fires NodeVM."console.dir" | ||
|  | 	 * @fires NodeVM."console.trace" | ||
|  | 	 */ | ||
|  | 	run(code, options) { | ||
|  | 		let script; | ||
|  | 		let filename; | ||
|  | 
 | ||
|  | 		if (typeof options === 'object') { | ||
|  | 			filename = options.filename; | ||
|  | 		} else { | ||
|  | 			filename = options; | ||
|  | 			options = {__proto__: null}; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const { | ||
|  | 			strict = this.options.strict, | ||
|  | 			wrapper = this.options.wrapper, | ||
|  | 			module: customModule, | ||
|  | 			require: customRequire, | ||
|  | 			dirname: customDirname = null | ||
|  | 		} = options; | ||
|  | 
 | ||
|  | 		let sandboxModule = customModule; | ||
|  | 		let dirname = customDirname; | ||
|  | 
 | ||
|  | 		if (code instanceof VMScript) { | ||
|  | 			script = strict ? code._compileNodeVMStrict() : code._compileNodeVM(); | ||
|  | 			if (!sandboxModule) { | ||
|  | 				const resolvedFilename = this._resolver.pathResolve(code.filename); | ||
|  | 				dirname = this._resolver.pathDirname(resolvedFilename); | ||
|  | 				sandboxModule = new (this._Module)(resolvedFilename, dirname); | ||
|  | 				this._resolver.registerModule(sandboxModule, resolvedFilename, dirname, null, false); | ||
|  | 			} | ||
|  | 		} else { | ||
|  | 			const unresolvedFilename = filename || 'vm.js'; | ||
|  | 			if (!sandboxModule) { | ||
|  | 				if (filename) { | ||
|  | 					const resolvedFilename = this._resolver.pathResolve(filename); | ||
|  | 					dirname = this._resolver.pathDirname(resolvedFilename); | ||
|  | 					sandboxModule = new (this._Module)(resolvedFilename, dirname); | ||
|  | 					this._resolver.registerModule(sandboxModule, resolvedFilename, dirname, null, false); | ||
|  | 				} else { | ||
|  | 					sandboxModule = new (this._Module)(null, null); | ||
|  | 					sandboxModule.id = unresolvedFilename; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			const prefix = strict ? STRICT_MODULE_PREFIX : MODULE_PREFIX; | ||
|  | 			let scriptCode = this._compiler(code, unresolvedFilename); | ||
|  | 			scriptCode = transformer(null, scriptCode, false, false, unresolvedFilename).code; | ||
|  | 			script = new Script(prefix + scriptCode + MODULE_SUFFIX, { | ||
|  | 				__proto__: null, | ||
|  | 				filename: unresolvedFilename, | ||
|  | 				displayErrors: false | ||
|  | 			}); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const closure = this._runScript(script); | ||
|  | 
 | ||
|  | 		const usedRequire = customRequire || this._createRequireForModule(sandboxModule); | ||
|  | 
 | ||
|  | 		const ret = Reflect.apply(closure, this.sandbox, [sandboxModule.exports, usedRequire, sandboxModule, filename, dirname]); | ||
|  | 		return wrapper === 'commonjs' ? sandboxModule.exports : ret; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * Create NodeVM and run code inside it. | ||
|  | 	 * | ||
|  | 	 * @public | ||
|  | 	 * @static | ||
|  | 	 * @param {string} script - Code to execute. | ||
|  | 	 * @param {string} [filename] - File name (used in stack traces only). | ||
|  | 	 * @param {Object} [options] - VM options. | ||
|  | 	 * @param {string} [options.filename] - File name (used in stack traces only). Used if <code>filename</code> is omitted. | ||
|  | 	 * @return {*} Result of executed code. | ||
|  | 	 * @see {@link NodeVM} for the options. | ||
|  | 	 * @throws {SyntaxError} If there is a syntax error in the script. | ||
|  | 	 * @throws {*} If the script execution terminated with an exception it is propagated. | ||
|  | 	 */ | ||
|  | 	static code(script, filename, options) { | ||
|  | 		let unresolvedFilename; | ||
|  | 		if (filename != null) { | ||
|  | 			if ('object' === typeof filename) { | ||
|  | 				options = filename; | ||
|  | 				unresolvedFilename = options.filename; | ||
|  | 			} else if ('string' === typeof filename) { | ||
|  | 				unresolvedFilename = filename; | ||
|  | 			} else { | ||
|  | 				throw new VMError('Invalid arguments.'); | ||
|  | 			} | ||
|  | 		} else if ('object' === typeof options) { | ||
|  | 			unresolvedFilename = options.filename; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (arguments.length > 3) { | ||
|  | 			throw new VMError('Invalid number of arguments.'); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const resolvedFilename = typeof unresolvedFilename === 'string' ? pa.resolve(unresolvedFilename) : undefined; | ||
|  | 
 | ||
|  | 		return new NodeVM(options).run(script, resolvedFilename); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * Create NodeVM and run script from file inside it. | ||
|  | 	 * | ||
|  | 	 * @public | ||
|  | 	 * @static | ||
|  | 	 * @param {string} filename - Filename of file to load and execute in a NodeVM. | ||
|  | 	 * @param {Object} [options] - NodeVM options. | ||
|  | 	 * @return {*} Result of executed code. | ||
|  | 	 * @see {@link NodeVM} for the options. | ||
|  | 	 * @throws {Error} If filename is not a valid filename. | ||
|  | 	 * @throws {SyntaxError} If there is a syntax error in the script. | ||
|  | 	 * @throws {*} If the script execution terminated with an exception it is propagated. | ||
|  | 	 */ | ||
|  | 	static file(filename, options) { | ||
|  | 		const resolvedFilename = pa.resolve(filename); | ||
|  | 
 | ||
|  | 		if (!fs.existsSync(resolvedFilename)) { | ||
|  | 			throw new VMError(`Script '${filename}' not found.`); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (fs.statSync(resolvedFilename).isDirectory()) { | ||
|  | 			throw new VMError('Script must be file, got directory.'); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return new NodeVM(options).run(fs.readFileSync(resolvedFilename, 'utf8'), resolvedFilename); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | function vm2NestingLoader(resolver, vm, id) { | ||
|  | 	if (!cacheMakeNestingScript) { | ||
|  | 		cacheMakeNestingScript = compileScript('nesting.js', '(vm, nodevm) => ({VM: vm, NodeVM: nodevm})'); | ||
|  | 	} | ||
|  | 	const makeNesting = vm._runScript(cacheMakeNestingScript); | ||
|  | 	return makeNesting(vm.readonly(VM), vm.readonly(NodeVM)); | ||
|  | } | ||
|  | 
 | ||
|  | exports.NodeVM = NodeVM; |