diff --git a/doc/api/errors.md b/doc/api/errors.md index 9778543c7f5fe2..c545e2ac072e46 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1811,7 +1811,7 @@ The module must be successfully linked before instantiation. ### ERR_VM_MODULE_NOT_MODULE -The fulfilled value of a linking promise is not a `vm.Module` object. +The fulfilled value of a linking promise is not a `vm.SourceTextModule` object. ### ERR_VM_MODULE_STATUS diff --git a/doc/api/vm.md b/doc/api/vm.md index 6c127786a71fef..e2e3eba0c12820 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -43,7 +43,7 @@ console.log(x); // 1; y is not defined. **The vm module is not a security mechanism. Do not use it to run untrusted code**. -## Class: vm.Module +## Class: vm.SourceTextModule @@ -53,20 +53,20 @@ added: v9.6.0 *This feature is only available with the `--experimental-vm-modules` command flag enabled.* -The `vm.Module` class provides a low-level interface for using ECMAScript -modules in VM contexts. It is the counterpart of the `vm.Script` class that -closely mirrors [Source Text Module Record][]s as defined in the ECMAScript -specification. +The `vm.SourceTextModule` class provides a low-level interface for using +ECMAScript modules in VM contexts. It is the counterpart of the `vm.Script` +class that closely mirrors [Source Text Module Record][]s as defined in the +ECMAScript specification. -Unlike `vm.Script` however, every `vm.Module` object is bound to a context from -its creation. Operations on `vm.Module` objects are intrinsically asynchronous, -in contrast with the synchronous nature of `vm.Script` objects. With the help -of async functions, however, manipulating `vm.Module` objects is fairly -straightforward. +Unlike `vm.Script` however, every `vm.SourceTextModule` object is bound to a +context from its creation. Operations on `vm.SourceTextModule` objects are +intrinsically asynchronous, in contrast with the synchronous nature of +`vm.Script` objects. With the help of async functions, however, manipulating +`vm.SourceTextModule` objects is fairly straightforward. -Using a `vm.Module` object requires four distinct steps: creation/parsing, -linking, instantiation, and evaluation. These four steps are illustrated in the -following example. +Using a `vm.SourceTextModule` object requires four distinct steps: +creation/parsing, linking, instantiation, and evaluation. These four steps are +illustrated in the following example. This implementation lies at a lower level than the [ECMAScript Module loader][]. There is also currently no way to interact with the Loader, though @@ -80,15 +80,15 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); (async () => { // Step 1 // - // Create a Module by constructing a new `vm.Module` object. This parses the - // provided source text, throwing a `SyntaxError` if anything goes wrong. By - // default, a Module is created in the top context. But here, we specify - // `contextifiedSandbox` as the context this Module belongs to. + // Create a Module by constructing a new `vm.SourceTextModule` object. This + // parses the provided source text, throwing a `SyntaxError` if anything goes + // wrong. By default, a Module is created in the top context. But here, we + // specify `contextifiedSandbox` as the context this Module belongs to. // // Here, we attempt to obtain the default export from the module "foo", and // put it into local binding "secret". - const bar = new vm.Module(` + const bar = new vm.SourceTextModule(` import s from 'foo'; s; `, { context: contextifiedSandbox }); @@ -118,7 +118,7 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); async function linker(specifier, referencingModule) { if (specifier === 'foo') { - return new vm.Module(` + return new vm.SourceTextModule(` // The "secret" variable refers to the global variable we added to // "contextifiedSandbox" when creating the context. export default secret; @@ -155,7 +155,7 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); })(); ``` -### Constructor: new vm.Module(code[, options]) +### Constructor: new vm.SourceTextModule(code[, options]) * `code` {string} JavaScript Module code to parse * `options` @@ -170,7 +170,7 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); * `initalizeImportMeta` {Function} Called during evaluation of this `Module` to initialize the `import.meta`. This function has the signature `(meta, module)`, where `meta` is the `import.meta` object in the `Module`, and - `module` is this `vm.Module` object. + `module` is this `vm.SourceTextModule` object. Creates a new ES `Module` object. @@ -185,7 +185,7 @@ const vm = require('vm'); const contextifiedSandbox = vm.createContext({ secret: 42 }); (async () => { - const module = new vm.Module( + const module = new vm.SourceTextModule( 'Object.getPrototypeOf(import.meta.prop).secret = secret;', { initializeImportMeta(meta) { diff --git a/lib/internal/process/esm_loader.js b/lib/internal/process/esm_loader.js index db28ca04b16cdc..c622084415f7a9 100644 --- a/lib/internal/process/esm_loader.js +++ b/lib/internal/process/esm_loader.js @@ -13,7 +13,7 @@ const { URL } = require('url'); const { initImportMetaMap, wrapToModuleMap -} = require('internal/vm/module'); +} = require('internal/vm/source_text_module'); function normalizeReferrerURL(referrer) { if (typeof referrer === 'string' && path.isAbsolute(referrer)) { @@ -30,8 +30,8 @@ function initializeImportMetaObject(wrap, meta) { } else { const initializeImportMeta = initImportMetaMap.get(vmModule); if (initializeImportMeta !== undefined) { - // This ModuleWrap belongs to vm.Module, initializer callback was - // provided. + // This ModuleWrap belongs to vm.SourceTextModule, + // initializer callback was provided. initializeImportMeta(meta, vmModule); } } diff --git a/lib/internal/vm/module.js b/lib/internal/vm/source_text_module.js similarity index 96% rename from lib/internal/vm/module.js rename to lib/internal/vm/source_text_module.js index a799cf2c3459b6..bea7d7c94aea04 100644 --- a/lib/internal/vm/module.js +++ b/lib/internal/vm/source_text_module.js @@ -44,15 +44,16 @@ const perContextModuleId = new WeakMap(); const wrapMap = new WeakMap(); const dependencyCacheMap = new WeakMap(); const linkingStatusMap = new WeakMap(); -// vm.Module -> function +// vm.SourceTextModule -> function const initImportMetaMap = new WeakMap(); -// ModuleWrap -> vm.Module +// ModuleWrap -> vm.SourceTextModule const wrapToModuleMap = new WeakMap(); const defaultModuleName = 'vm:module'; -class Module { +// TODO(devsnek): figure out AbstractModule class or protocol +class SourceTextModule { constructor(src, options = {}) { - emitExperimentalWarning('vm.Module'); + emitExperimentalWarning('vm.SourceTextModule'); if (typeof src !== 'string') throw new ERR_INVALID_ARG_TYPE('src', 'string', src); @@ -229,7 +230,7 @@ class Module { [customInspectSymbol](depth, options) { let ctor = getConstructorOf(this); - ctor = ctor === null ? Module : ctor; + ctor = ctor === null ? SourceTextModule : ctor; if (typeof depth === 'number' && depth < 0) return options.stylize(`[${ctor.name}]`, 'special'); @@ -244,7 +245,7 @@ class Module { } module.exports = { - Module, + SourceTextModule, initImportMetaMap, wrapToModuleMap }; diff --git a/lib/vm.js b/lib/vm.js index 3ab50c81580365..c813ca3049e3e0 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -296,5 +296,7 @@ module.exports = { isContext, }; -if (process.binding('config').experimentalVMModules) - module.exports.Module = require('internal/vm/module').Module; +if (process.binding('config').experimentalVMModules) { + const { SourceTextModule } = require('internal/vm/source_text_module'); + module.exports.SourceTextModule = SourceTextModule; +} diff --git a/node.gyp b/node.gyp index 0a8630cd1bff96..7460d73c0b578a 100644 --- a/node.gyp +++ b/node.gyp @@ -167,7 +167,7 @@ 'lib/internal/v8_prof_processor.js', 'lib/internal/validators.js', 'lib/internal/stream_base_commons.js', - 'lib/internal/vm/module.js', + 'lib/internal/vm/source_text_module.js', 'lib/internal/worker.js', 'lib/internal/streams/lazy_transform.js', 'lib/internal/streams/async_iterator.js', diff --git a/test/parallel/test-util-inspect-namespace.js b/test/parallel/test-util-inspect-namespace.js index e73f475cff55cc..f2b6e57178b041 100644 --- a/test/parallel/test-util-inspect-namespace.js +++ b/test/parallel/test-util-inspect-namespace.js @@ -5,11 +5,11 @@ require('../common'); const assert = require('assert'); -const { Module } = require('vm'); +const { SourceTextModule } = require('vm'); const { inspect } = require('util'); (async () => { - const m = new Module('export const a = 1; export var b = 2'); + const m = new SourceTextModule('export const a = 1; export var b = 2'); await m.link(() => 0); m.instantiate(); assert.strictEqual( diff --git a/test/parallel/test-util-types.js b/test/parallel/test-util-types.js index 59a9dcceb59d6a..740ac7f472dc1f 100644 --- a/test/parallel/test-util-types.js +++ b/test/parallel/test-util-types.js @@ -126,7 +126,7 @@ for (const [ value, _method ] of [ } (async () => { - const m = new vm.Module(''); + const m = new vm.SourceTextModule(''); await m.link(() => 0); m.instantiate(); await m.evaluate(); diff --git a/test/parallel/test-vm-module-basic.js b/test/parallel/test-vm-module-basic.js index 1f699ddf5b4334..ffe376ccc2b1b1 100644 --- a/test/parallel/test-vm-module-basic.js +++ b/test/parallel/test-vm-module-basic.js @@ -4,7 +4,7 @@ const common = require('../common'); const assert = require('assert'); -const { Module, createContext } = require('vm'); +const { SourceTextModule, createContext } = require('vm'); (async function test1() { const context = createContext({ @@ -12,7 +12,7 @@ const { Module, createContext } = require('vm'); baz: undefined, typeofProcess: undefined, }); - const m = new Module( + const m = new SourceTextModule( 'baz = foo; typeofProcess = typeof process; typeof Object;', { context } ); @@ -32,7 +32,7 @@ const { Module, createContext } = require('vm'); }()); (async () => { - const m = new Module( + const m = new SourceTextModule( 'global.vmResult = "foo"; Object.prototype.toString.call(process);' ); await m.link(common.mustNotCall()); @@ -44,7 +44,7 @@ const { Module, createContext } = require('vm'); })(); (async () => { - const m = new Module('while (true) {}'); + const m = new SourceTextModule('while (true) {}'); await m.link(common.mustNotCall()); m.instantiate(); await m.evaluate({ timeout: 500 }) diff --git a/test/parallel/test-vm-module-dynamic-import.js b/test/parallel/test-vm-module-dynamic-import.js index bb45337cf1a83c..35c57d8b3efcbe 100644 --- a/test/parallel/test-vm-module-dynamic-import.js +++ b/test/parallel/test-vm-module-dynamic-import.js @@ -5,12 +5,12 @@ const common = require('../common'); const assert = require('assert'); -const { Module, createContext } = require('vm'); +const { SourceTextModule, createContext } = require('vm'); const finished = common.mustCall(); (async function() { - const m = new Module('import("foo")', { context: createContext() }); + const m = new SourceTextModule('import("foo")', { context: createContext() }); await m.link(common.mustNotCall()); m.instantiate(); const { result } = await m.evaluate(); diff --git a/test/parallel/test-vm-module-errors.js b/test/parallel/test-vm-module-errors.js index 720f28525b4d35..6803e0d86b3ff4 100644 --- a/test/parallel/test-vm-module-errors.js +++ b/test/parallel/test-vm-module-errors.js @@ -6,7 +6,7 @@ const common = require('../common'); const assert = require('assert'); -const { Module, createContext } = require('vm'); +const { SourceTextModule, createContext } = require('vm'); async function expectsRejection(fn, settings) { const validateError = common.expectsError(settings); @@ -29,14 +29,14 @@ async function expectsRejection(fn, settings) { } async function createEmptyLinkedModule() { - const m = new Module(''); + const m = new SourceTextModule(''); await m.link(common.mustNotCall()); return m; } async function checkArgType() { common.expectsError(() => { - new Module(); + new SourceTextModule(); }, { code: 'ERR_INVALID_ARG_TYPE', type: TypeError @@ -46,7 +46,7 @@ async function checkArgType() { 0, 1, null, true, 'str', () => {}, { url: 0 }, Symbol.iterator ]) { common.expectsError(() => { - new Module('', invalidOptions); + new SourceTextModule('', invalidOptions); }, { code: 'ERR_INVALID_ARG_TYPE', type: TypeError @@ -57,7 +57,7 @@ async function checkArgType() { 0, 1, undefined, null, true, 'str', {}, Symbol.iterator ]) { await expectsRejection(async () => { - const m = new Module(''); + const m = new SourceTextModule(''); await m.link(invalidLinker); }, { code: 'ERR_INVALID_ARG_TYPE', @@ -69,7 +69,7 @@ async function checkArgType() { // Check methods/properties can only be used under a specific state. async function checkModuleState() { await expectsRejection(async () => { - const m = new Module(''); + const m = new SourceTextModule(''); await m.link(common.mustNotCall()); assert.strictEqual(m.linkingStatus, 'linked'); await m.link(common.mustNotCall()); @@ -78,7 +78,7 @@ async function checkModuleState() { }); await expectsRejection(async () => { - const m = new Module(''); + const m = new SourceTextModule(''); m.link(common.mustNotCall()); assert.strictEqual(m.linkingStatus, 'linking'); await m.link(common.mustNotCall()); @@ -87,14 +87,14 @@ async function checkModuleState() { }); common.expectsError(() => { - const m = new Module(''); + const m = new SourceTextModule(''); m.instantiate(); }, { code: 'ERR_VM_MODULE_NOT_LINKED' }); await expectsRejection(async () => { - const m = new Module('import "foo";'); + const m = new SourceTextModule('import "foo";'); try { await m.link(common.mustCall(() => ({}))); } catch (err) { @@ -107,7 +107,7 @@ async function checkModuleState() { }); { - const m = new Module('import "foo";'); + const m = new SourceTextModule('import "foo";'); await m.link(common.mustCall(async (specifier, module) => { assert.strictEqual(module, m); assert.strictEqual(specifier, 'foo'); @@ -117,14 +117,14 @@ async function checkModuleState() { }, { code: 'ERR_VM_MODULE_NOT_LINKED' }); - return new Module(''); + return new SourceTextModule(''); })); m.instantiate(); await m.evaluate(); } await expectsRejection(async () => { - const m = new Module(''); + const m = new SourceTextModule(''); await m.evaluate(); }, { code: 'ERR_VM_MODULE_STATUS', @@ -140,7 +140,7 @@ async function checkModuleState() { }); common.expectsError(() => { - const m = new Module(''); + const m = new SourceTextModule(''); m.error; }, { code: 'ERR_VM_MODULE_STATUS', @@ -158,7 +158,7 @@ async function checkModuleState() { }); common.expectsError(() => { - const m = new Module(''); + const m = new SourceTextModule(''); m.namespace; }, { code: 'ERR_VM_MODULE_STATUS', @@ -177,7 +177,7 @@ async function checkModuleState() { // Check link() fails when the returned module is not valid. async function checkLinking() { await expectsRejection(async () => { - const m = new Module('import "foo";'); + const m = new SourceTextModule('import "foo";'); try { await m.link(common.mustCall(() => ({}))); } catch (err) { @@ -191,9 +191,9 @@ async function checkLinking() { await expectsRejection(async () => { const c = createContext({ a: 1 }); - const foo = new Module('', { context: c }); + const foo = new SourceTextModule('', { context: c }); await foo.link(common.mustNotCall()); - const bar = new Module('import "foo";'); + const bar = new SourceTextModule('import "foo";'); try { await bar.link(common.mustCall(() => foo)); } catch (err) { @@ -206,7 +206,7 @@ async function checkLinking() { }); await expectsRejection(async () => { - const erroredModule = new Module('import "foo";'); + const erroredModule = new SourceTextModule('import "foo";'); try { await erroredModule.link(common.mustCall(() => ({}))); } catch (err) { @@ -215,7 +215,7 @@ async function checkLinking() { assert.strictEqual(erroredModule.linkingStatus, 'errored'); } - const rootModule = new Module('import "errored";'); + const rootModule = new SourceTextModule('import "errored";'); await rootModule.link(common.mustCall(() => erroredModule)); }, { code: 'ERR_VM_MODULE_LINKING_ERRORED' @@ -225,8 +225,8 @@ async function checkLinking() { // Check the JavaScript engine deals with exceptions correctly async function checkExecution() { await (async () => { - const m = new Module('import { nonexistent } from "module";'); - await m.link(common.mustCall(() => new Module(''))); + const m = new SourceTextModule('import { nonexistent } from "module";'); + await m.link(common.mustCall(() => new SourceTextModule(''))); // There is no code for this exception since it is thrown by the JavaScript // engine. @@ -236,7 +236,7 @@ async function checkExecution() { })(); await (async () => { - const m = new Module('throw new Error();'); + const m = new SourceTextModule('throw new Error();'); await m.link(common.mustNotCall()); m.instantiate(); const evaluatePromise = m.evaluate(); diff --git a/test/parallel/test-vm-module-import-meta.js b/test/parallel/test-vm-module-import-meta.js index 5e97f1ac541d54..f7bc82f9b272ad 100644 --- a/test/parallel/test-vm-module-import-meta.js +++ b/test/parallel/test-vm-module-import-meta.js @@ -4,10 +4,10 @@ const common = require('../common'); const assert = require('assert'); -const { Module } = require('vm'); +const { SourceTextModule } = require('vm'); async function testBasic() { - const m = new Module('import.meta;', { + const m = new SourceTextModule('import.meta;', { initializeImportMeta: common.mustCall((meta, module) => { assert.strictEqual(module, m); meta.prop = 42; @@ -27,7 +27,7 @@ async function testInvalid() { null, {}, 0, Symbol.iterator, [], 'string', false ]) { common.expectsError(() => { - new Module('', { + new SourceTextModule('', { initializeImportMeta: invalidValue }); }, { diff --git a/test/parallel/test-vm-module-link.js b/test/parallel/test-vm-module-link.js index ead6721bd4564f..20518c40540485 100644 --- a/test/parallel/test-vm-module-link.js +++ b/test/parallel/test-vm-module-link.js @@ -7,13 +7,13 @@ const common = require('../common'); const assert = require('assert'); const { URL } = require('url'); -const { Module } = require('vm'); +const { SourceTextModule } = require('vm'); async function simple() { - const foo = new Module('export default 5;'); + const foo = new SourceTextModule('export default 5;'); await foo.link(common.mustNotCall()); - const bar = new Module('import five from "foo"; five'); + const bar = new SourceTextModule('import five from "foo"; five'); assert.deepStrictEqual(bar.dependencySpecifiers, ['foo']); @@ -29,11 +29,11 @@ async function simple() { } async function depth() { - const foo = new Module('export default 5'); + const foo = new SourceTextModule('export default 5'); await foo.link(common.mustNotCall()); async function getProxy(parentName, parentModule) { - const mod = new Module(` + const mod = new SourceTextModule(` import ${parentName} from '${parentName}'; export default ${parentName}; `); @@ -56,12 +56,12 @@ async function depth() { } async function circular() { - const foo = new Module(` + const foo = new SourceTextModule(` import getFoo from 'bar'; export let foo = 42; export default getFoo(); `); - const bar = new Module(` + const bar = new SourceTextModule(` import { foo } from 'foo'; export default function getFoo() { return foo; @@ -109,12 +109,14 @@ async function circular2() { ` }; const moduleMap = new Map(); - const rootModule = new Module(sourceMap.root, { url: 'vm:root' }); + const rootModule = new SourceTextModule(sourceMap.root, { url: 'vm:root' }); async function link(specifier, referencingModule) { if (moduleMap.has(specifier)) { return moduleMap.get(specifier); } - const mod = new Module(sourceMap[specifier], { url: new URL(specifier, 'file:///').href }); + const mod = new SourceTextModule(sourceMap[specifier], { + url: new URL(specifier, 'file:///').href, + }); moduleMap.set(specifier, mod); return mod; } diff --git a/test/parallel/test-vm-module-reevaluate.js b/test/parallel/test-vm-module-reevaluate.js index e08ab734501ff2..c3914f362fa814 100644 --- a/test/parallel/test-vm-module-reevaluate.js +++ b/test/parallel/test-vm-module-reevaluate.js @@ -6,13 +6,13 @@ const common = require('../common'); const assert = require('assert'); -const { Module } = require('vm'); +const { SourceTextModule } = require('vm'); const finished = common.mustCall(); (async function main() { { - const m = new Module('1'); + const m = new SourceTextModule('1'); await m.link(common.mustNotCall()); m.instantiate(); assert.strictEqual((await m.evaluate()).result, 1); @@ -21,7 +21,7 @@ const finished = common.mustCall(); } { - const m = new Module('throw new Error()'); + const m = new SourceTextModule('throw new Error()'); await m.link(common.mustNotCall()); m.instantiate();