diff --git a/.eslintrc.js b/.eslintrc.js index 7333382fe3..a38335ee21 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -39,7 +39,6 @@ module.exports = { files: [ 'doc/api/esm.md', '*.mjs', - 'test/es-module/test-esm-example-loader.js', ], parserOptions: { sourceType: 'module' }, }, diff --git a/doc/api/cli.md b/doc/api/cli.md index 977a0fd1f5..46b5295ccb 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -97,13 +97,6 @@ added: v10.0.0 Enable experimental top-level `await` keyword support in REPL. -### `--experimental-vm-modules` - - -Enable experimental ES Module support in the `vm` module. - ### `--force-fips` - -Specify the `file` of the custom [experimental ECMAScript Module][] loader. - ### `--max-http-header-size=size` Node.js contains support for ES Modules based upon the -[Node.js EP for ES Modules][]. +[Node.js EP for ES Modules][] and the [ESM Minimal Kernel][]. -Not all features of the EP are complete and will be landing as both VM support -and implementation is ready. Error messages are still being polished. +The minimal feature set is designed to be compatible with all potential +future implementations. Expect major changes in the implementation including +interoperability support, specifier resolution, and default behavior. ## Enabling -The `--experimental-modules` flag can be used to enable features for loading -ESM modules. - -Once this has been set, files ending with `.mjs` will be able to be loaded -as ES Modules. +Modules are enabled by default for files ending with `.mjs`: ```sh -node --experimental-modules my-app.mjs +node my-app.mjs ``` ## Features @@ -54,6 +51,10 @@ property: ## Notable differences between `import` and `require` +### Mandatory file extensions + +You must provide a file extension when using the `import` keyword. + ### No NODE_PATH `NODE_PATH` is not part of resolving `import` specifiers. Please use symlinks @@ -78,31 +79,32 @@ Modules will be loaded multiple times if the `import` specifier used to resolve them have a different query or fragment. ```js -import './foo?query=1'; // loads ./foo with query of "?query=1" -import './foo?query=2'; // loads ./foo with query of "?query=2" +import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1" +import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2" ``` For now, only modules using the `file:` protocol can be loaded. -## Interop with existing modules +## CommonJS, JSON, and Native Modules -All CommonJS, JSON, and C++ modules can be used with `import`. +CommonJS, JSON, and Native modules can be used with [`module.createRequireFromPath()`][]. -Modules loaded this way will only be loaded once, even if their query -or fragment string differs between `import` statements. +```js +// cjs.js +module.exports = 'cjs'; -When loaded via `import` these modules will provide a single `default` export -representing the value of `module.exports` at the time they finished evaluating. +// esm.mjs +import { createRequireFromPath as createRequire } from 'module'; +import { fileURLToPath as fromPath } from 'url'; -```js -// foo.js -module.exports = { one: 1 }; +const require = createRequire(fromPath(import.meta.url)); -// bar.js -import foo from './foo.js'; -foo.one === 1; // true +const cjs = require('./cjs'); +cjs === 'cjs'; // true ``` +## Builtin modules + Builtin modules will provide named exports of their public API, as well as a default export which can be used for, among other things, modifying the named exports. Named exports of builtin modules are updated when the corresponding @@ -132,127 +134,194 @@ fs.readFileSync = () => Buffer.from('Hello, ESM'); fs.readFileSync === readFileSync; ``` -## Loader hooks - - - -To customize the default module resolution, loader hooks can optionally be -provided via a `--loader ./loader-name.mjs` argument to Node.js. - -When hooks are used they only apply to ES module loading and not to any -CommonJS modules loaded. - -### Resolve hook - -The resolve hook returns the resolved file URL and module format for a -given module specifier and parent file URL: - -```js -const baseURL = new URL('file://'); -baseURL.pathname = `${process.cwd()}/`; - -export async function resolve(specifier, - parentModuleURL = baseURL, - defaultResolver) { - return { - url: new URL(specifier, parentModuleURL).href, - format: 'esm' - }; -} -``` - -The `parentModuleURL` is provided as `undefined` when performing main Node.js -load itself. - -The default Node.js ES module resolution function is provided as a third -argument to the resolver for easy compatibility workflows. - -In addition to returning the resolved file URL value, the resolve hook also -returns a `format` property specifying the module format of the resolved -module. This can be one of the following: - -| `format` | Description | -| --- | --- | -| `'esm'` | Load a standard JavaScript module | -| `'cjs'` | Load a node-style CommonJS module | -| `'builtin'` | Load a node builtin CommonJS module | -| `'json'` | Load a JSON file | -| `'addon'` | Load a [C++ Addon][addons] | -| `'dynamic'` | Use a [dynamic instantiate hook][] | - -For example, a dummy loader to load JavaScript restricted to browser resolution -rules with only JS file extension and Node.js builtin modules support could -be written: - -```js -import path from 'path'; -import process from 'process'; -import Module from 'module'; - -const builtins = Module.builtinModules; -const JS_EXTENSIONS = new Set(['.js', '.mjs']); - -const baseURL = new URL('file://'); -baseURL.pathname = `${process.cwd()}/`; - -export function resolve(specifier, parentModuleURL = baseURL, defaultResolve) { - if (builtins.includes(specifier)) { - return { - url: specifier, - format: 'builtin' - }; - } - if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) { - // For node_modules support: - // return defaultResolve(specifier, parentModuleURL); - throw new Error( - `imports must begin with '/', './', or '../'; '${specifier}' does not`); - } - const resolved = new URL(specifier, parentModuleURL); - const ext = path.extname(resolved.pathname); - if (!JS_EXTENSIONS.has(ext)) { - throw new Error( - `Cannot load file with non-JavaScript file extension ${ext}.`); - } - return { - url: resolved.href, - format: 'esm' - }; -} -``` - -With this loader, running: - -```console -NODE_OPTIONS='--experimental-modules --loader ./custom-loader.mjs' node x.js -``` - -would load the module `x.js` as an ES module with relative resolution support -(with `node_modules` loading skipped in this example). - -### Dynamic instantiate hook - -To create a custom dynamic module that doesn't correspond to one of the -existing `format` interpretations, the `dynamicInstantiate` hook can be used. -This hook is called only for modules that return `format: 'dynamic'` from -the `resolve` hook. - -```js -export async function dynamicInstantiate(url) { - return { - exports: ['customExportName'], - execute: (exports) => { - // Get and set functions provided for pre-allocated export names - exports.customExportName.set('value'); - } - }; -} -``` - -With the list of module exports provided upfront, the `execute` function will -then be called at the exact point of module evaluation order for that module -in the import tree. +## Resolution Algorithm + +### Features + +The resolver has the following properties: + +* FileURL-based resolution as is used by ES modules +* Support for builtin module loading +* Relative and absolute URL resolution +* No default extensions +* No folder mains +* Bare specifier package resolution lookup through node_modules + +### Resolver Algorithm + +The algorithm to load an ES module specifier is given through the +**ESM_RESOLVE** method below. It returns the resolved URL for a +module specifier relative to a parentURL, in addition to the unique module +format for that resolved URL given by the **ESM_FORMAT** routine. + +The _"esm"_ format is returned for an ECMAScript Module, while the +_"legacy"_ format is used to indicate loading through the legacy +CommonJS loader. Additional formats such as _"wasm"_ or _"addon"_ can be +extended in future updates. + +In the following algorithms, all subroutine errors are propogated as errors +of these top-level routines. + +_isMain_ is **true** when resolving the Node.js application entry point. + +**ESM_RESOLVE(_specifier_, _parentURL_, _isMain_)** +> 1. Let _resolvedURL_ be **undefined**. +> 1. If _specifier_ is a valid URL, then +> 1. Set _resolvedURL_ to the result of parsing and reserializing +> _specifier_ as a URL. +> 1. Otherwise, if _specifier_ starts with _"/"_, then +> 1. Throw an _Invalid Specifier_ error. +> 1. Otherwise, if _specifier_ starts with _"./"_ or _"../"_, then +> 1. Set _resolvedURL_ to the URL resolution of _specifier_ relative to +> _parentURL_. +> 1. Otherwise, +> 1. Note: _specifier_ is now a bare specifier. +> 1. Set _resolvedURL_ the result of +> **PACKAGE_RESOLVE**(_specifier_, _parentURL_). +> 1. If the file at _resolvedURL_ does not exist, then +> 1. Throw a _Module Not Found_ error. +> 1. Let _format_ be the result of **ESM_FORMAT**(_url_, _isMain_). +> 1. Load _resolvedURL_ as module format, _format_. + +PACKAGE_RESOLVE(_packageSpecifier_, _parentURL_) +> 1. Let _packageName_ be *undefined*. +> 1. Let _packageSubpath_ be *undefined*. +> 1. If _packageSpecifier_ is an empty string, then +> 1. Throw an _Invalid Specifier_ error. +> 1. If _packageSpecifier_ does not start with _"@"_, then +> 1. Set _packageName_ to the substring of _packageSpecifier_ until the +> first _"/"_ separator or the end of the string. +> 1. Otherwise, +> 1. If _packageSpecifier_ does not contain a _"/"_ separator, then +> 1. Throw an _Invalid Specifier_ error. +> 1. Set _packageName_ to the substring of _packageSpecifier_ +> until the second _"/"_ separator or the end of the string. +> 1. Let _packageSubpath_ be the substring of _packageSpecifier_ from the +> position at the length of _packageName_ plus one, if any. +> 1. Assert: _packageName_ is a valid package name or scoped package name. +> 1. Assert: _packageSubpath_ is either empty, or a path without a leading +> separator. +> 1. If _packageSubpath_ contains any _"."_ or _".."_ segments or percent +> encoded strings for _"/"_ or _"\"_ then, +> 1. Throw an _Invalid Specifier_ error. +> 1. If _packageSubpath_ is empty and _packageName_ is a Node.js builtin +> module, then +> 1. Return the string _"node:"_ concatenated with _packageSpecifier_. +> 1. While _parentURL_ is not the file system root, +> 1. Set _parentURL_ to the parent folder URL of _parentURL_. +> 1. Let _packageURL_ be the URL resolution of the string concatenation of +> _parentURL_, _"/node_modules/"_ and _packageSpecifier_. +> 1. If the folder at _packageURL_ does not exist, then +> 1. Set _parentURL_ to the parent URL path of _parentURL_. +> 1. Continue the next loop iteration. +> 1. Let _pjson_be the result of **READ_PACKAGE_JSON**(_packageURL_). +> 1. If _packageSubpath_ is empty, then +> 1. Return the result of **PACKAGE_MAIN_RESOLVE**(_packageURL_, +> _pjson_). +> 1. Otherwise, +> 1. If **HAS_ESM_PROPERTIES**(_pjson_) is *true*, then +> 1. Return **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _packagePath_, +> _pjson_). +> 1. Return the URL resolution of _packagePath_ in _packageURL_. +> 1. Throw a _Module Not Found_ error. + +PACKAGE_MAIN_RESOLVE(_packageURL_, _pjson_) +> 1. Let _pjsonURL_ be the URL of the file _"package.json"_ within the parent +> path _packageURL_. +> 1. If **HAS_ESM_PROPERTIES**(_pjson_) is **false**, then +> 1. Let _mainURL_ be the result applying the legacy +> **LOAD_AS_DIRECTORY** CommonJS resolver to _packageURL_, throwing a +> _Module Not Found_ error for no resolution. +> 1. Return _mainURL_. +> 1. If _pjson.exports_ is a String, then +> 1. Return the URL of _pjson.exports_ within the parent path _packageURL_. +> 1. Assert: _pjson.exports_ is an Object. +> 1. If _pjson.exports["."]_ is a String, then +> 1. Let _target_ be _pjson.exports["."]_. +> 1. If **IS_VALID_EXPORTS_TARGET**(_target_) is **false**, then +> 1. Emit an _"Invalid Exports Target"_ warning. +> 1. Otherwise, +> 1. Return the URL of _pjson.exports.default_ within the parent path +> _packageURL_. +> 1. Return **null**. + +PACKAGE_EXPORTS_RESOLVE(_packageURL_, _packagePath_, _pjson_) +> 1. Assert: _pjson_ is not **null**. +> 1. If _pjson.exports_ is a String, then +> 1. Throw a _Module Not Found_ error. +> 1. Assert: _pjson.exports_ is an Object. +> 1. Set _packagePath_ to _"./"_ concatenated with _packagePath_. +> 1. If _packagePath_ is a key of _pjson.exports_, then +> 1. Let _target_ be the value of _pjson.exports[packagePath]_. +> 1. If **IS_VALID_EXPORTS_TARGET**(_target_) is **false**, then +> 1. Emit an _"Invalid Exports Target"_ warning. +> 1. Throw a _Module Not Found_ error. +> 1. Return the URL resolution of the concatenation of _packageURL_ and +> _target_. +> 1. Let _directoryKeys_ be the list of keys of _pjson.exports_ ending in +> _"/"_, sorted by length descending. +> 1. For each key _directory_ in _directoryKeys_, do +> 1. If _packagePath_ starts with _directory_, then +> 1. Let _target_ be the value of _pjson.exports[directory]_. +> 1. If **IS_VALID_EXPORTS_TARGET**(_target_) is **false** or _target_ +> does not end in _"/"_, then +> 1. Emit an _"Invalid Exports Target"_ warning. +> 1. Continue the loop. +> 1. Let _subpath_ be the substring of _target_ starting at the index of +> the length of _directory_. +> 1. Return the URL resolution of the concatenation of _packageURL_, +> _target_ and _subpath_. +> 1. Throw a _Module Not Found_ error. + +IS_VALID_EXPORTS_TARGET(_target_) +> 1. If _target_ is not a valid String, then +> 1. Return **false**. +> 1. If _target_ does not start with _"./"_, then +> 1. Return **false**. +> 1. If _target_ contains any _".."_ or _"."_ path segments, then +> 1. Return **false**. +> 1. If _target_ contains any percent-encoded characters for _"/"_ or _"\"_, +> then +> 1. Return **false**. +> 1. Return **true**. + +**ESM_FORMAT(_url_, _isMain_)** +> 1. Assert: _url_ corresponds to an existing file. +> 1. Let _pjson_ be the result of **READ_PACKAGE_BOUNDARY**(_url_). +> 1. If _pjson_ is **null** and _isMain_ is **true**, then +> 1. Return _"legacy"_. +> 1. If **HAS_ESM_PROPERTIES**(_pjson_) is **true**, then +> 1. If _url_ does not end in _".js"_ or _".mjs"_, then +> 1. Throw an _Unsupported File Extension_ error. +> 1. Return _"esm"_. +> 1. Otherwise, +> 1. If _url_ ends in _".mjs"_, then +> 1. Return _"esm"_. +> 1. Otherwise, +> 1. Return _"legacy"_. + +READ_PACKAGE_BOUNDARY(_url_) +> 1. Let _boundaryURL_ be _url_. +> 1. While _boundaryURL_ is not the file system root, +> 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_boundaryURL_). +> 1. If _pjson_ is not **null**, then +> 1. Return _pjson_. +> 1. Set _boundaryURL_ to the parent URL of _boundaryURL_. +> 1. Return **null**. + +READ_PACKAGE_JSON(_packageURL_) +> 1. Let _pjsonURL_ be the resolution of _"package.json"_ within _packageURL_. +> 1. If the file at _pjsonURL_ does not exist, then +> 1. Return **null**. +> 1. If the file at _packageURL_ does not parse as valid JSON, then +> 1. Throw an _Invalid Package Configuration_ error. +> 1. Return the parsed JSON source of the file at _url_. + +HAS_ESM_PROPERTIES(_pjson_) +> 1. If _pjson_ is not **null** and _pjson.exports_ is a String or Object, then +> 1. Return *true*. +> 1. Return *false*. [Node.js EP for ES Modules]: https://github.com/nodejs/node-eps/blob/master/002-es-modules.md -[addons]: addons.html -[dynamic instantiate hook]: #esm_dynamic_instantiate_hook +[`module.createRequireFromPath()`]: modules.html#modules_module_createrequirefrompath_filename +[ESM Minimal Kernel]: https://github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md diff --git a/doc/api/vm.md b/doc/api/vm.md index 808ed2f00d..853ac7c015 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -85,18 +85,6 @@ changes: depending on whether code cache data is produced successfully. This option is **deprecated** in favor of `script.createCachedData()`. **Default:** `false`. - * `importModuleDynamically` {Function} Called during evaluation of this module - when `import()` is called. If this option is not specified, calls to - `import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. - This option is part of the experimental API for the `--experimental-modules` - flag, and should not be considered stable. - * `specifier` {string} specifier passed to `import()` - * `module` {vm.SourceTextModule} - * Returns: {Module Namespace Object|vm.SourceTextModule} Returning a - `vm.SourceTextModule` is recommended in order to take advantage of error - tracking, and to avoid issues with namespaces that contain `then` - function exports. - If `options` is a string, then it specifies the filename. Creating a new `vm.Script` object compiles `code` but does not run it. The @@ -527,6 +515,8 @@ evaluated, in which case it will do one of the following two things: This method cannot be called while the module is being evaluated (`module.status` is `'evaluating'`) to prevent infinite recursion. +======= +>>>>>>> esm: Remove --experimental-vm-modules. Corresponds to the [Evaluate() concrete method][] field of [Source Text Module Record][]s in the ECMAScript specification. @@ -811,17 +801,6 @@ changes: depending on whether code cache data is produced successfully. This option is **deprecated** in favor of `script.createCachedData()`. **Default:** `false`. - * `importModuleDynamically` {Function} Called during evaluation of this module - when `import()` is called. If this option is not specified, calls to - `import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. - This option is part of the experimental API for the `--experimental-modules` - flag, and should not be considered stable. - * `specifier` {string} specifier passed to `import()` - * `module` {vm.SourceTextModule} - * Returns: {Module Namespace Object|vm.SourceTextModule} Returning a - `vm.SourceTextModule` is recommended in order to take advantage of error - tracking, and to avoid issues with namespaces that contain `then` - function exports. * Returns: {any} the result of the very last statement executed in the script. The `vm.runInContext()` method compiles `code`, runs it within the context of @@ -909,17 +888,6 @@ changes: depending on whether code cache data is produced successfully. This option is **deprecated** in favor of `script.createCachedData()`. **Default:** `false`. - * `importModuleDynamically` {Function} Called during evaluation of this module - when `import()` is called. If this option is not specified, calls to - `import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. - This option is part of the experimental API for the `--experimental-modules` - flag, and should not be considered stable. - * `specifier` {string} specifier passed to `import()` - * `module` {vm.SourceTextModule} - * Returns: {Module Namespace Object|vm.SourceTextModule} Returning a - `vm.SourceTextModule` is recommended in order to take advantage of error - tracking, and to avoid issues with namespaces that contain `then` - function exports. * Returns: {any} the result of the very last statement executed in the script. The `vm.runInNewContext()` first contextifies the given `sandbox` object (or @@ -987,17 +955,6 @@ changes: depending on whether code cache data is produced successfully. This option is **deprecated** in favor of `script.createCachedData()`. **Default:** `false`. - * `importModuleDynamically` {Function} Called during evaluation of this module - when `import()` is called. If this option is not specified, calls to - `import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][]. - This option is part of the experimental API for the `--experimental-modules` - flag, and should not be considered stable. - * `specifier` {string} specifier passed to `import()` - * `module` {vm.SourceTextModule} - * Returns: {Module Namespace Object|vm.SourceTextModule} Returning a - `vm.SourceTextModule` is recommended in order to take advantage of error - tracking, and to avoid issues with namespaces that contain `then` - function exports. * Returns: {any} the result of the very last statement executed in the script. `vm.runInThisContext()` compiles `code`, runs it within the context of the @@ -1114,7 +1071,6 @@ the `process.nextTick()` and `queueMicrotask()` functions. This issue occurs because all contexts share the same microtask and nextTick queues. -[`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`]: errors.html#ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING [`Error`]: errors.html#errors_class_error [`URL`]: url.html#url_class_url [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval @@ -1124,12 +1080,6 @@ queues. [`vm.createContext()`]: #vm_vm_createcontext_sandbox_options [`vm.runInContext()`]: #vm_vm_runincontext_code_contextifiedsandbox_options [`vm.runInThisContext()`]: #vm_vm_runinthiscontext_code_options -[ECMAScript Module Loader]: esm.html#esm_ecmascript_modules -[Evaluate() concrete method]: https://tc39.github.io/ecma262/#sec-moduleevaluation -[GetModuleNamespace]: https://tc39.github.io/ecma262/#sec-getmodulenamespace -[HostResolveImportedModule]: https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule -[Instantiate() concrete method]: https://tc39.github.io/ecma262/#sec-moduledeclarationinstantiation -[Source Text Module Record]: https://tc39.github.io/ecma262/#sec-source-text-module-records [V8 Embedder's Guide]: https://v8.dev/docs/embed#contexts [contextified]: #vm_what_does_it_mean_to_contextify_an_object [global object]: https://es5.github.io/#x15.1 diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 14aa8d5d32..840b0c73f0 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -218,8 +218,7 @@ function startup() { } const experimentalModules = getOptionValue('--experimental-modules'); - const experimentalVMModules = getOptionValue('--experimental-vm-modules'); - if (experimentalModules || experimentalVMModules) { + if (experimentalModules) { if (experimentalModules) { process.emitWarning( 'The ESM module loader is experimental.', diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 7002776300..dcbc439950 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -842,11 +842,13 @@ E('ERR_MISSING_ARGS', E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK', 'The ES Module loader may not return a format of \'dynamic\' when no ' + 'dynamicInstantiate function was provided', Error); -E('ERR_MISSING_MODULE', 'Cannot find module %s', Error); -E('ERR_MODULE_RESOLUTION_LEGACY', - '%s not found by import in %s.' + - ' Legacy behavior in require() would have found it at %s', - Error); +E('ERR_MODULE_NOT_FOUND', (module, base, legacyResolution) => { + let msg = `Cannot find module '${module}' imported from ${base}.`; + if (legacyResolution) + msg += ' Legacy behavior in require() would have found it at ' + + legacyResolution; + return msg; +}, Error); E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error); E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function', TypeError); E('ERR_NAPI_INVALID_DATAVIEW_ARGS', @@ -940,11 +942,13 @@ E('ERR_UNHANDLED_ERROR', if (err === undefined) return msg; return `${msg} (${err})`; }, Error); +// This should probably be a `TypeError`. E('ERR_UNKNOWN_CREDENTIAL', '%s identifier does not exist: %s', Error); E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError); // This should probably be a `TypeError`. -E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: %s', Error); +E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: \'%s\' imported ' + + 'from %s', Error); E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError); E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError); diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index f4551b7d47..5e91da5c3d 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -761,7 +761,11 @@ if (experimentalModules) { // bootstrap main module. Module.runMain = function() { // Load the main module--the command line argument. - if (experimentalModules) { + const base = path.basename(process.argv[1]); + const ext = path.extname(base); + const isESM = ext === '.mjs'; + + if (experimentalModules && isESM) { if (asyncESM === undefined) lazyLoadESM(); asyncESM.loaderPromise.then((loader) => { return loader.import(pathToFileURL(process.argv[1]).pathname); diff --git a/lib/internal/modules/esm/default_resolve.js b/lib/internal/modules/esm/default_resolve.js index 2cf9014a67..188313f304 100644 --- a/lib/internal/modules/esm/default_resolve.js +++ b/lib/internal/modules/esm/default_resolve.js @@ -10,21 +10,15 @@ const { getOptionValue } = require('internal/options'); const preserveSymlinks = getOptionValue('--preserve-symlinks'); const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); const { - ERR_MISSING_MODULE, - ERR_MODULE_RESOLUTION_LEGACY, + ERR_MODULE_NOT_FOUND, ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes; const { resolve: moduleWrapResolve } = internalBinding('module_wrap'); -const StringStartsWith = Function.call.bind(String.prototype.startsWith); const { pathToFileURL, fileURLToPath } = require('internal/url'); const realpathCache = new Map(); function search(target, base) { - if (base === undefined) { - // We cannot search without a base. - throw new ERR_MISSING_MODULE(target); - } try { return moduleWrapResolve(target, base); } catch (e) { @@ -36,7 +30,7 @@ function search(target, base) { tmpMod.paths = CJSmodule._nodeModulePaths( new URL('./', questionedBase).pathname); const found = CJSmodule._resolveFilename(target, tmpMod); - error = new ERR_MODULE_RESOLUTION_LEGACY(target, base, found); + error = new ERR_MODULE_NOT_FOUND(target, fileURLToPath(base), found); } catch { // ignore } @@ -46,10 +40,7 @@ function search(target, base) { const extensionFormatMap = { '__proto__': null, - '.mjs': 'esm', - '.json': 'json', - '.node': 'addon', - '.js': 'cjs' + '.mjs': 'esm' }; function resolve(specifier, parentURL) { @@ -60,16 +51,8 @@ function resolve(specifier, parentURL) { }; } - let url; - try { - url = search(specifier, - parentURL || pathToFileURL(`${process.cwd()}/`).href); - } catch (e) { - if (typeof e.message === 'string' && - StringStartsWith(e.message, 'Cannot find module')) - e.code = 'MODULE_NOT_FOUND'; - throw e; - } + let url = search(specifier, + parentURL || pathToFileURL(`${process.cwd()}/`).href); const isMain = parentURL === undefined; @@ -90,12 +73,11 @@ function resolve(specifier, parentURL) { if (isMain) format = 'cjs'; else - throw new ERR_UNKNOWN_FILE_EXTENSION(url.pathname); + throw new ERR_UNKNOWN_FILE_EXTENSION(url.pathname, + fileURLToPath(parentURL)); } return { url: `${url}`, format }; } module.exports = resolve; -// exported for tests -module.exports.search = search; diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 776b8d584d..9e0b878838 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -3,24 +3,20 @@ const { NativeModule } = require('internal/bootstrap/loaders'); const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); const { - stripShebang, - stripBOM + stripShebang } = require('internal/modules/cjs/helpers'); const CJSModule = require('internal/modules/cjs/loader'); const internalURLModule = require('internal/url'); const createDynamicModule = require( 'internal/modules/esm/create_dynamic_module'); const fs = require('fs'); -const { _makeLong } = require('path'); const { SafeMap } = require('internal/safe_globals'); const { URL } = require('url'); const { debuglog, promisify } = require('util'); const esmLoader = require('internal/process/esm_loader'); const readFileAsync = promisify(fs.readFile); -const readFileSync = fs.readFileSync; const StringReplace = Function.call.bind(String.prototype.replace); -const JsonParse = JSON.parse; const debug = debuglog('esm'); @@ -91,32 +87,3 @@ translators.set('builtin', async (url) => { reflect.exports.default.set(module.exports); }); }); - -// Strategy for loading a node native module -translators.set('addon', async (url) => { - debug(`Translating NativeModule ${url}`); - return createDynamicModule(['default'], url, (reflect) => { - debug(`Loading NativeModule ${url}`); - const module = { exports: {} }; - const pathname = internalURLModule.fileURLToPath(new URL(url)); - process.dlopen(module, _makeLong(pathname)); - reflect.exports.default.set(module.exports); - }); -}); - -// Strategy for loading a JSON file -translators.set('json', async (url) => { - debug(`Translating JSONModule ${url}`); - return createDynamicModule(['default'], url, (reflect) => { - debug(`Loading JSONModule ${url}`); - const pathname = internalURLModule.fileURLToPath(new URL(url)); - const content = readFileSync(pathname, 'utf8'); - try { - const exports = JsonParse(stripBOM(content)); - reflect.exports.default.set(exports); - } catch (err) { - err.message = pathname + ': ' + err.message; - throw err; - } - }); -}); diff --git a/lib/internal/process/esm_loader.js b/lib/internal/process/esm_loader.js index f81053a1c3..9d8df07c05 100644 --- a/lib/internal/process/esm_loader.js +++ b/lib/internal/process/esm_loader.js @@ -6,7 +6,6 @@ const { callbackMap, } = internalBinding('module_wrap'); -const { pathToFileURL } = require('internal/url'); const Loader = require('internal/modules/esm/loader'); const { wrapToModuleMap, @@ -46,16 +45,8 @@ exports.loaderPromise = new Promise((resolve, reject) => { exports.ESMLoader = undefined; exports.setup = function() { - let ESMLoader = new Loader(); + const ESMLoader = new Loader(); const loaderPromise = (async () => { - const userLoader = require('internal/options').getOptionValue('--loader'); - if (userLoader) { - const hooks = await ESMLoader.import( - userLoader, pathToFileURL(`${process.cwd()}/`).href); - ESMLoader = new Loader(); - ESMLoader.hook(hooks); - exports.ESMLoader = ESMLoader; - } return ESMLoader; })(); loaderResolve(loaderPromise); diff --git a/lib/vm.js b/lib/vm.js index 464724071a..8b1df9df1d 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -402,8 +402,3 @@ module.exports = { isContext, compileFunction, }; - -if (require('internal/options').getOptionValue('--experimental-vm-modules')) { - const { SourceTextModule } = require('internal/vm/source_text_module'); - module.exports.SourceTextModule = SourceTextModule; -} diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 243352fe64..5a0fc9c3d9 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -28,7 +28,6 @@ using v8::HandleScope; using v8::Integer; using v8::IntegrityLevel; using v8::Isolate; -using v8::JSON; using v8::Just; using v8::Local; using v8::Maybe; @@ -45,7 +44,7 @@ using v8::String; using v8::Undefined; using v8::Value; -static const char* const EXTENSIONS[] = {".mjs", ".js", ".json", ".node"}; +static const char* const EXTENSIONS[] = {".mjs"}; ModuleWrap::ModuleWrap(Environment* env, Local object, @@ -468,219 +467,66 @@ std::string ReadFile(uv_file file) { return contents; } -enum CheckFileOptions { - LEAVE_OPEN_AFTER_CHECK, - CLOSE_AFTER_CHECK +enum DescriptorType { + NONE, + FILE, + DIRECTORY }; -Maybe CheckFile(const std::string& path, - CheckFileOptions opt = CLOSE_AFTER_CHECK) { +DescriptorType CheckDescriptor(const std::string& path) { uv_fs_t fs_req; - if (path.empty()) { - return Nothing(); - } - - uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr); - uv_fs_req_cleanup(&fs_req); - - if (fd < 0) { - return Nothing(); - } - - uv_fs_fstat(nullptr, &fs_req, fd, nullptr); - uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR; - uv_fs_req_cleanup(&fs_req); - - if (is_directory) { - CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr)); + int rc = uv_fs_stat(nullptr, &fs_req, path.c_str(), nullptr); + if (rc == 0) { + uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR; uv_fs_req_cleanup(&fs_req); - return Nothing(); - } - - if (opt == CLOSE_AFTER_CHECK) { - CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr)); - uv_fs_req_cleanup(&fs_req); - } - - return Just(fd); -} - -using Exists = PackageConfig::Exists; -using IsValid = PackageConfig::IsValid; -using HasMain = PackageConfig::HasMain; - -const PackageConfig& GetPackageConfig(Environment* env, - const std::string& path) { - auto existing = env->package_json_cache.find(path); - if (existing != env->package_json_cache.end()) { - return existing->second; - } - Maybe check = CheckFile(path, LEAVE_OPEN_AFTER_CHECK); - if (check.IsNothing()) { - auto entry = env->package_json_cache.emplace(path, - PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" }); - return entry.first->second; + return is_directory ? DIRECTORY : FILE; } - - Isolate* isolate = env->isolate(); - v8::HandleScope handle_scope(isolate); - - std::string pkg_src = ReadFile(check.FromJust()); - uv_fs_t fs_req; - CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, check.FromJust(), nullptr)); uv_fs_req_cleanup(&fs_req); - - Local src; - if (!String::NewFromUtf8(isolate, - pkg_src.c_str(), - v8::NewStringType::kNormal, - pkg_src.length()).ToLocal(&src)) { - auto entry = env->package_json_cache.emplace(path, - PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" }); - return entry.first->second; - } - - Local pkg_json_v; - Local pkg_json; - - if (!JSON::Parse(env->context(), src).ToLocal(&pkg_json_v) || - !pkg_json_v->ToObject(env->context()).ToLocal(&pkg_json)) { - auto entry = env->package_json_cache.emplace(path, - PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "" }); - return entry.first->second; - } - - Local pkg_main; - HasMain has_main = HasMain::No; - std::string main_std; - if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) { - has_main = HasMain::Yes; - Utf8Value main_utf8(isolate, pkg_main); - main_std.assign(std::string(*main_utf8, main_utf8.length())); - } - - auto entry = env->package_json_cache.emplace(path, - PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std }); - return entry.first->second; -} - -enum ResolveExtensionsOptions { - TRY_EXACT_NAME, - ONLY_VIA_EXTENSIONS -}; - -template -Maybe ResolveExtensions(const URL& search) { - if (options == TRY_EXACT_NAME) { - std::string filePath = search.ToFilePath(); - Maybe check = CheckFile(filePath); - if (!check.IsNothing()) { - return Just(search); - } - } - - for (const char* extension : EXTENSIONS) { - URL guess(search.path() + extension, &search); - Maybe check = CheckFile(guess.ToFilePath()); - if (!check.IsNothing()) { - return Just(guess); - } - } - - return Nothing(); -} - -inline Maybe ResolveIndex(const URL& search) { - return ResolveExtensions(URL("index", search)); + return NONE; } -Maybe ResolveMain(Environment* env, const URL& search) { - URL pkg("package.json", &search); - - const PackageConfig& pjson = - GetPackageConfig(env, pkg.ToFilePath()); - // Note invalid package.json should throw in resolver - // currently we silently ignore which is incorrect - if (pjson.exists == Exists::No || - pjson.is_valid == IsValid::No || - pjson.has_main == HasMain::No) { - return Nothing(); - } - if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) { - return Resolve(env, "./" + pjson.main, search, IgnoreMain); - } - return Resolve(env, pjson.main, search, IgnoreMain); -} - -Maybe ResolveModule(Environment* env, - const std::string& specifier, - const URL& base) { +Maybe PackageResolve(Environment* env, + const std::string& specifier, + const URL& base) { URL parent(".", base); - URL dir(""); + std::string last_path; do { - dir = parent; - Maybe check = - Resolve(env, "./node_modules/" + specifier, dir, CheckMain); - if (!check.IsNothing()) { - const size_t limit = specifier.find('/'); - const size_t spec_len = - limit == std::string::npos ? specifier.length() : - limit + 1; - std::string chroot = - dir.path() + "node_modules/" + specifier.substr(0, spec_len); - if (check.FromJust().path().substr(0, chroot.length()) != chroot) { - return Nothing(); - } - return check; - } else { - // TODO(bmeck) PREVENT FALLTHROUGH - } - parent = URL("..", &dir); - } while (parent.path() != dir.path()); + URL pkg_url("./node_modules/" + specifier, &parent); + DescriptorType check = CheckDescriptor(pkg_url.ToFilePath()); + if (check == FILE) return Just(pkg_url); + last_path = parent.path(); + parent = URL("..", &parent); + // cross-platform root check + } while (parent.path() != last_path); return Nothing(); } -Maybe ResolveDirectory(Environment* env, - const URL& search, - PackageMainCheck check_pjson_main) { - if (check_pjson_main) { - Maybe main = ResolveMain(env, search); - if (!main.IsNothing()) - return main; - } - return ResolveIndex(search); -} - } // anonymous namespace Maybe Resolve(Environment* env, const std::string& specifier, - const URL& base, - PackageMainCheck check_pjson_main) { - URL pure_url(specifier); - if (!(pure_url.flags() & URL_FLAGS_FAILED)) { - // just check existence, without altering - Maybe check = CheckFile(pure_url.ToFilePath()); - if (check.IsNothing()) { - return Nothing(); + const URL& base) { + // Order swapped from spec for minor perf gain. + // Ok since relative URLs cannot parse as URLs. + URL resolved; + if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { + resolved = URL(specifier, base); + } else { + URL pure_url(specifier); + if (!(pure_url.flags() & URL_FLAGS_FAILED)) { + resolved = pure_url; + } else { + return PackageResolve(env, specifier, base); } - return Just(pure_url); } - if (specifier.length() == 0) { + DescriptorType check = CheckDescriptor(resolved.ToFilePath()); + if (check != FILE) { + std::string msg = "Cannot find module '" + resolved.ToFilePath() + + "' imported from " + base.ToFilePath(); + node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str()); return Nothing(); } - if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { - URL resolved(specifier, base); - Maybe file = ResolveExtensions(resolved); - if (!file.IsNothing()) - return file; - if (specifier.back() != '/') { - resolved = URL(specifier + "/", base); - } - return ResolveDirectory(env, resolved, check_pjson_main); - } else { - return ResolveModule(env, specifier, base); - } + return Just(resolved); } void ModuleWrap::Resolve(const FunctionCallbackInfo& args) { @@ -702,10 +548,18 @@ void ModuleWrap::Resolve(const FunctionCallbackInfo& args) { env, "second argument is not a URL string"); } + TryCatchScope try_catch(env); Maybe result = node::loader::Resolve(env, specifier_std, url); - if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) { - std::string msg = "Cannot find module " + specifier_std; - return node::THROW_ERR_MISSING_MODULE(env, msg.c_str()); + if (try_catch.HasCaught()) { + try_catch.ReThrow(); + return; + } else if (result.IsNothing() || + (result.FromJust().flags() & URL_FLAGS_FAILED)) { + std::string msg = "Cannot find module '" + specifier_std + + "' imported from " + url.ToFilePath(); + node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str()); + try_catch.ReThrow(); + return; } MaybeLocal obj = result.FromJust().ToObject(env); diff --git a/src/module_wrap.h b/src/module_wrap.h index 6d231631d6..8a5592d3f2 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -12,11 +12,6 @@ namespace node { namespace loader { -enum PackageMainCheck : bool { - CheckMain = true, - IgnoreMain = false -}; - enum ScriptType : int { kScript, kModule, @@ -30,8 +25,7 @@ enum HostDefinedOptions : int { v8::Maybe Resolve(Environment* env, const std::string& specifier, - const url::URL& base, - PackageMainCheck read_pkg_json = CheckMain); + const url::URL& base); class ModuleWrap : public BaseObject { public: diff --git a/src/node_config.cc b/src/node_config.cc index c244d1d9ff..313c44871f 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -76,15 +76,8 @@ static void Initialize(Local target, if (env->options()->experimental_modules) { READONLY_TRUE_PROPERTY(target, "experimentalModules"); - const std::string& userland_loader = env->options()->userland_loader; - if (!userland_loader.empty()) { - READONLY_STRING_PROPERTY(target, "userLoader", userland_loader); - } } - if (env->options()->experimental_vm_modules) - READONLY_TRUE_PROPERTY(target, "experimentalVMModules"); - if (env->options()->experimental_repl_await) READONLY_TRUE_PROPERTY(target, "experimentalREPLAwait"); diff --git a/src/node_errors.h b/src/node_errors.h index cea7c108c1..3010ddf594 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -63,8 +63,8 @@ void FatalException(const v8::FunctionCallbackInfo& args); V(ERR_MEMORY_ALLOCATION_FAILED, Error) \ V(ERR_MISSING_ARGS, TypeError) \ V(ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST, TypeError) \ - V(ERR_MISSING_MODULE, Error) \ V(ERR_MISSING_PLATFORM_FOR_WORKER, Error) \ + V(ERR_MODULE_NOT_FOUND, Error) \ V(ERR_OUT_OF_RANGE, RangeError) \ V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \ V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error) \ diff --git a/src/node_options.cc b/src/node_options.cc index b225acb1e0..125a1b4dd7 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -37,10 +37,6 @@ void PerIsolateOptions::CheckOptions(std::vector* errors) { } void EnvironmentOptions::CheckOptions(std::vector* errors) { - if (!userland_loader.empty() && !experimental_modules) { - errors->push_back("--loader requires --experimental-modules be enabled"); - } - if (syntax_check_only && has_eval_string) { errors->push_back("either --check or --eval can be used, not both"); } @@ -105,10 +101,6 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "experimental await keyword support in REPL", &EnvironmentOptions::experimental_repl_await, kAllowedInEnvironment); - AddOption("--experimental-vm-modules", - "experimental ES Module support in vm module", - &EnvironmentOptions::experimental_vm_modules, - kAllowedInEnvironment); AddOption("--experimental-worker", "", NoOp{}, kAllowedInEnvironment); AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals); AddOption("--http-parser", @@ -116,11 +108,6 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "(default: llhttp).", &EnvironmentOptions::http_parser, kAllowedInEnvironment); - AddOption("--loader", - "(with --experimental-modules) use the specified file as a " - "custom loader", - &EnvironmentOptions::userland_loader, - kAllowedInEnvironment); AddOption("--no-deprecation", "silence deprecation warnings", &EnvironmentOptions::no_deprecation, diff --git a/src/node_options.h b/src/node_options.h index beecc4ca84..739d8fe09b 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -110,7 +110,6 @@ class EnvironmentOptions : public Options { bool trace_deprecation = false; bool trace_sync_io = false; bool trace_warnings = false; - std::string userland_loader; bool syntax_check_only = false; bool has_eval_string = false; diff --git a/test/addons/hello-world-esm/binding.cc b/test/addons/hello-world-esm/binding.cc deleted file mode 100644 index 02eecec099..0000000000 --- a/test/addons/hello-world-esm/binding.cc +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -void Method(const v8::FunctionCallbackInfo& args) { - v8::Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(v8::String::NewFromUtf8( - isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); -} - -void init(v8::Local exports) { - NODE_SET_METHOD(exports, "hello", Method); -} - -NODE_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/addons/hello-world-esm/binding.gyp b/test/addons/hello-world-esm/binding.gyp deleted file mode 100644 index 7ede63d94a..0000000000 --- a/test/addons/hello-world-esm/binding.gyp +++ /dev/null @@ -1,9 +0,0 @@ -{ - 'targets': [ - { - 'target_name': 'binding', - 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], - 'sources': [ 'binding.cc' ] - } - ] -} diff --git a/test/addons/hello-world-esm/test.js b/test/addons/hello-world-esm/test.js deleted file mode 100644 index d0faf65540..0000000000 --- a/test/addons/hello-world-esm/test.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; -const common = require('../../common'); - -const assert = require('assert'); -const { spawnSync } = require('child_process'); -const { copyFileSync } = require('fs'); -const { join } = require('path'); - -const buildDir = join(__dirname, 'build'); - -copyFileSync(join(buildDir, common.buildType, 'binding.node'), - join(buildDir, 'binding.node')); - -const result = spawnSync(process.execPath, - ['--experimental-modules', `${__dirname}/test.mjs`]); - -assert.ifError(result.error); -// TODO: Uncomment this once ESM is no longer experimental. -// assert.strictEqual(result.stderr.toString().trim(), ''); -assert.strictEqual(result.stdout.toString().trim(), 'binding.hello() = world'); diff --git a/test/addons/hello-world-esm/test.mjs b/test/addons/hello-world-esm/test.mjs deleted file mode 100644 index d98de5bf87..0000000000 --- a/test/addons/hello-world-esm/test.mjs +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-disable node-core/required-modules */ - -import assert from 'assert'; -import binding from './build/binding.node'; -assert.strictEqual(binding.hello(), 'world'); -console.log('binding.hello() =', binding.hello()); diff --git a/test/common/index.mjs b/test/common/index.mjs index de9119f37e..41592098eb 100644 --- a/test/common/index.mjs +++ b/test/common/index.mjs @@ -1,6 +1,15 @@ // Flags: --experimental-modules /* eslint-disable node-core/required-modules */ -import common from './index.js'; + +import { createRequireFromPath } from 'module'; +import { fileURLToPath as toPath } from 'url'; + +function createRequire(metaUrl) { + return createRequireFromPath(toPath(metaUrl)); +} + +const require = createRequire(import.meta.url); +const common = require('./index.js'); const { isMainThread, @@ -91,5 +100,6 @@ export { getBufferSources, disableCrashOnUnhandledRejection, getTTYfd, - runWithInvalidFD + runWithInvalidFD, + createRequire }; diff --git a/test/es-module/test-esm-basic-imports.mjs b/test/es-module/test-esm-basic-imports.mjs index 78a4106f94..d9bb22be0a 100644 --- a/test/es-module/test-esm-basic-imports.mjs +++ b/test/es-module/test-esm-basic-imports.mjs @@ -1,5 +1,6 @@ // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; import assert from 'assert'; import ok from '../fixtures/es-modules/test-esm-ok.mjs'; import okShebang from './test-esm-shebang.mjs'; diff --git a/test/es-module/test-esm-cyclic-dynamic-import.mjs b/test/es-module/test-esm-cyclic-dynamic-import.mjs index c8dfff919c..a207efc73e 100644 --- a/test/es-module/test-esm-cyclic-dynamic-import.mjs +++ b/test/es-module/test-esm-cyclic-dynamic-import.mjs @@ -1,3 +1,4 @@ // Flags: --experimental-modules -import '../common'; -import('./test-esm-cyclic-dynamic-import'); +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; +import('./test-esm-cyclic-dynamic-import.mjs'); diff --git a/test/es-module/test-esm-double-encoding.mjs b/test/es-module/test-esm-double-encoding.mjs index c81d0530d3..9366d4bd6b 100644 --- a/test/es-module/test-esm-double-encoding.mjs +++ b/test/es-module/test-esm-double-encoding.mjs @@ -1,6 +1,7 @@ // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; // Assert we can import files with `%` in their pathname. -import '../fixtures/es-modules/test-esm-double-encoding-native%2520.js'; +import '../fixtures/es-modules/test-esm-double-encoding-native%2520.mjs'; diff --git a/test/es-module/test-esm-dynamic-import.js b/test/es-module/test-esm-dynamic-import.js index 8873399776..325011b50f 100644 --- a/test/es-module/test-esm-dynamic-import.js +++ b/test/es-module/test-esm-dynamic-import.js @@ -1,4 +1,5 @@ // Flags: --experimental-modules + 'use strict'; const common = require('../common'); const assert = require('assert'); @@ -17,7 +18,7 @@ function expectErrorProperty(result, propertyKey, value) { } function expectMissingModuleError(result) { - expectErrorProperty(result, 'code', 'MODULE_NOT_FOUND'); + expectErrorProperty(result, 'code', 'ERR_MODULE_NOT_FOUND'); } function expectOkNamespace(result) { diff --git a/test/es-module/test-esm-encoded-path.mjs b/test/es-module/test-esm-encoded-path.mjs index 365a425afa..2cabfdacff 100644 --- a/test/es-module/test-esm-encoded-path.mjs +++ b/test/es-module/test-esm-encoded-path.mjs @@ -1,5 +1,6 @@ // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; import assert from 'assert'; // ./test-esm-ok.mjs import ok from '../fixtures/es-modules/test-%65%73%6d-ok.mjs'; diff --git a/test/es-module/test-esm-error-cache.js b/test/es-module/test-esm-error-cache.js index 98244615ef..79f76357ec 100644 --- a/test/es-module/test-esm-error-cache.js +++ b/test/es-module/test-esm-error-cache.js @@ -1,11 +1,11 @@ -'use strict'; - // Flags: --experimental-modules +'use strict'; + require('../common'); const assert = require('assert'); -const file = '../fixtures/syntax/bad_syntax.js'; +const file = '../fixtures/syntax/bad_syntax.mjs'; let error; (async () => { diff --git a/test/es-module/test-esm-example-loader.js b/test/es-module/test-esm-example-loader.js deleted file mode 100644 index 0b0001acea..0000000000 --- a/test/es-module/test-esm-example-loader.js +++ /dev/null @@ -1,6 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/example-loader.mjs -/* eslint-disable node-core/required-modules */ -import assert from 'assert'; -import ok from '../fixtures/es-modules/test-esm-ok.mjs'; - -assert(ok); diff --git a/test/es-module/test-esm-forbidden-globals.mjs b/test/es-module/test-esm-forbidden-globals.mjs index 4e777412a3..cf110ff290 100644 --- a/test/es-module/test-esm-forbidden-globals.mjs +++ b/test/es-module/test-esm-forbidden-globals.mjs @@ -1,5 +1,6 @@ // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; // eslint-disable-next-line no-undef if (typeof arguments !== 'undefined') { diff --git a/test/es-module/test-esm-import-meta.mjs b/test/es-module/test-esm-import-meta.mjs index c17e0e20d4..4c34b337fb 100644 --- a/test/es-module/test-esm-import-meta.mjs +++ b/test/es-module/test-esm-import-meta.mjs @@ -1,6 +1,7 @@ // Flags: --experimental-modules +/* eslint-disable node-core/required-modules */ -import '../common'; +import '../common/index.mjs'; import assert from 'assert'; assert.strictEqual(Object.getPrototypeOf(import.meta), null); diff --git a/test/es-module/test-esm-json.mjs b/test/es-module/test-esm-json.mjs deleted file mode 100644 index a7146d19a9..0000000000 --- a/test/es-module/test-esm-json.mjs +++ /dev/null @@ -1,8 +0,0 @@ -// Flags: --experimental-modules -import '../common'; -import assert from 'assert'; -import ok from '../fixtures/es-modules/test-esm-ok.mjs'; -import json from '../fixtures/es-modules/json.json'; - -assert(ok); -assert.strictEqual(json.val, 42); diff --git a/test/es-module/test-esm-live-binding.mjs b/test/es-module/test-esm-live-binding.mjs index d151e004df..880a6c389b 100644 --- a/test/es-module/test-esm-live-binding.mjs +++ b/test/es-module/test-esm-live-binding.mjs @@ -1,6 +1,7 @@ // Flags: --experimental-modules +/* eslint-disable node-core/required-modules */ -import '../common'; +import '../common/index.mjs'; import assert from 'assert'; import fs, { readFile, readFileSync } from 'fs'; diff --git a/test/es-module/test-esm-loader-dependency.mjs b/test/es-module/test-esm-loader-dependency.mjs deleted file mode 100644 index 1ed8685a6f..0000000000 --- a/test/es-module/test-esm-loader-dependency.mjs +++ /dev/null @@ -1,5 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-with-dep.mjs -/* eslint-disable node-core/required-modules */ -import '../fixtures/es-modules/test-esm-ok.mjs'; - -// We just test that this module doesn't fail loading diff --git a/test/es-module/test-esm-loader-invalid-format.mjs b/test/es-module/test-esm-loader-invalid-format.mjs deleted file mode 100644 index f8714d4aa1..0000000000 --- a/test/es-module/test-esm-loader-invalid-format.mjs +++ /dev/null @@ -1,11 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-invalid-format.mjs -import { expectsError, mustCall } from '../common'; -import assert from 'assert'; - -import('../fixtures/es-modules/test-esm-ok.mjs') -.then(assert.fail, expectsError({ - code: 'ERR_INVALID_RETURN_PROPERTY_VALUE', - message: 'Expected string to be returned for the "format" from the ' + - '"loader resolve" function but got type undefined.' -})) -.then(mustCall()); diff --git a/test/es-module/test-esm-loader-invalid-url.mjs b/test/es-module/test-esm-loader-invalid-url.mjs deleted file mode 100644 index 43971a2e6e..0000000000 --- a/test/es-module/test-esm-loader-invalid-url.mjs +++ /dev/null @@ -1,12 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-invalid-url.mjs -import { expectsError, mustCall } from '../common'; -import assert from 'assert'; - -import('../fixtures/es-modules/test-esm-ok.mjs') -.then(assert.fail, expectsError({ - code: 'ERR_INVALID_RETURN_PROPERTY', - message: 'Expected a valid url to be returned for the "url" from the ' + - '"loader resolve" function but got ' + - '../fixtures/es-modules/test-esm-ok.mjs.' -})) -.then(mustCall()); diff --git a/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs b/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs deleted file mode 100644 index f2b37f7e8a..0000000000 --- a/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs +++ /dev/null @@ -1,9 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs - -import { expectsError } from '../common'; - -import('test').catch(expectsError({ - code: 'ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK', - message: 'The ES Module loader may not return a format of \'dynamic\' ' + - 'when no dynamicInstantiate function was provided' -})); diff --git a/test/es-module/test-esm-loader-search.js b/test/es-module/test-esm-loader-search.js deleted file mode 100644 index 0ca8990cb7..0000000000 --- a/test/es-module/test-esm-loader-search.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; -// Flags: --expose-internals - -// This test ensures that search throws errors appropriately - -const common = require('../common'); - -const { search } = require('internal/modules/esm/default_resolve'); - -common.expectsError( - () => search('target', undefined), - { - code: 'ERR_MISSING_MODULE', - type: Error, - message: 'Cannot find module target' - } -); diff --git a/test/es-module/test-esm-main-lookup.mjs b/test/es-module/test-esm-main-lookup.mjs index ca313a1d26..19c025beab 100644 --- a/test/es-module/test-esm-main-lookup.mjs +++ b/test/es-module/test-esm-main-lookup.mjs @@ -1,6 +1,26 @@ // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; import assert from 'assert'; -import main from '../fixtures/es-modules/pjson-main'; -assert.strictEqual(main, 'main'); +async function main() { + let mod; + try { + mod = await import('../fixtures/es-modules/pjson-main'); + } catch (e) { + assert.strictEqual(e.code, 'ERR_MODULE_NOT_FOUND'); + } + + assert.strictEqual(mod, undefined); + + try { + mod = await import('../fixtures/es-modules/pjson-main/main.mjs'); + } catch (e) { + console.log(e); + assert.fail(); + } + + assert.strictEqual(mod.main, 'main'); +} + +main(); diff --git a/test/es-module/test-esm-named-exports.mjs b/test/es-module/test-esm-named-exports.mjs deleted file mode 100644 index 3aae9230de..0000000000 --- a/test/es-module/test-esm-named-exports.mjs +++ /dev/null @@ -1,8 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs -import '../common'; -import { readFile } from 'fs'; -import assert from 'assert'; -import ok from '../fixtures/es-modules/test-esm-ok.mjs'; - -assert(ok); -assert(readFile); diff --git a/test/es-module/test-esm-namespace.mjs b/test/es-module/test-esm-namespace.mjs index da1286d0f4..38b7ef12d5 100644 --- a/test/es-module/test-esm-namespace.mjs +++ b/test/es-module/test-esm-namespace.mjs @@ -1,5 +1,7 @@ // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ + +import '../common/index.mjs'; import * as fs from 'fs'; import assert from 'assert'; import Module from 'module'; diff --git a/test/es-module/test-esm-preserve-symlinks-not-found-plain.mjs b/test/es-module/test-esm-preserve-symlinks-not-found-plain.mjs deleted file mode 100644 index 2ca0f56581..0000000000 --- a/test/es-module/test-esm-preserve-symlinks-not-found-plain.mjs +++ /dev/null @@ -1,3 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/not-found-assert-loader.mjs -/* eslint-disable node-core/required-modules */ -import './not-found.js'; diff --git a/test/es-module/test-esm-preserve-symlinks-not-found.mjs b/test/es-module/test-esm-preserve-symlinks-not-found.mjs deleted file mode 100644 index 5119957bae..0000000000 --- a/test/es-module/test-esm-preserve-symlinks-not-found.mjs +++ /dev/null @@ -1,3 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/not-found-assert-loader.mjs -/* eslint-disable node-core/required-modules */ -import './not-found'; diff --git a/test/es-module/test-esm-require-cache.mjs b/test/es-module/test-esm-require-cache.mjs index ff32cde36f..09030e0578 100644 --- a/test/es-module/test-esm-require-cache.mjs +++ b/test/es-module/test-esm-require-cache.mjs @@ -1,7 +1,12 @@ // Flags: --experimental-modules -import '../common'; -import '../fixtures/es-module-require-cache/preload.js'; -import '../fixtures/es-module-require-cache/counter.js'; +/* eslint-disable node-core/required-modules */ +import { createRequire } from '../common/index.mjs'; import assert from 'assert'; +// +const require = createRequire(import.meta.url); + +require('../fixtures/es-module-require-cache/preload.js'); +require('../fixtures/es-module-require-cache/counter.js'); + assert.strictEqual(global.counter, 1); delete global.counter; diff --git a/test/es-module/test-esm-resolve-hook.mjs b/test/es-module/test-esm-resolve-hook.mjs deleted file mode 100644 index e326d20b6d..0000000000 --- a/test/es-module/test-esm-resolve-hook.mjs +++ /dev/null @@ -1,8 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/js-loader.mjs -/* eslint-disable node-core/required-modules */ -import { namedExport } from '../fixtures/es-module-loaders/js-as-esm.js'; -import assert from 'assert'; -import ok from '../fixtures/es-modules/test-esm-ok.mjs'; - -assert(ok); -assert(namedExport); diff --git a/test/es-module/test-esm-shared-loader-dep.mjs b/test/es-module/test-esm-shared-loader-dep.mjs deleted file mode 100644 index 5c274d835c..0000000000 --- a/test/es-module/test-esm-shared-loader-dep.mjs +++ /dev/null @@ -1,7 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-shared-dep.mjs -import '../common'; -import assert from 'assert'; -import '../fixtures/es-modules/test-esm-ok.mjs'; -import dep from '../fixtures/es-module-loaders/loader-dep.js'; - -assert.strictEqual(dep.format, 'esm'); diff --git a/test/es-module/test-esm-shebang.mjs b/test/es-module/test-esm-shebang.mjs index d5faace479..486e04dade 100644 --- a/test/es-module/test-esm-shebang.mjs +++ b/test/es-module/test-esm-shebang.mjs @@ -1,6 +1,7 @@ #! }]) // isn't js // Flags: --experimental-modules -import '../common'; +/* eslint-disable node-core/required-modules */ +import '../common/index.mjs'; const isJs = true; export default isJs; diff --git a/test/es-module/test-esm-snapshot.mjs b/test/es-module/test-esm-snapshot.mjs deleted file mode 100644 index 3d4b44bbdd..0000000000 --- a/test/es-module/test-esm-snapshot.mjs +++ /dev/null @@ -1,7 +0,0 @@ -// Flags: --experimental-modules -import '../common'; -import '../fixtures/es-modules/esm-snapshot-mutator'; -import one from '../fixtures/es-modules/esm-snapshot'; -import assert from 'assert'; - -assert.strictEqual(one, 1); diff --git a/test/es-module/test-esm-symlink-main.js b/test/es-module/test-esm-symlink-main.js index f7631ef2e5..871180f5cc 100644 --- a/test/es-module/test-esm-symlink-main.js +++ b/test/es-module/test-esm-symlink-main.js @@ -9,7 +9,7 @@ const fs = require('fs'); tmpdir.refresh(); const realPath = path.resolve(__dirname, '../fixtures/es-modules/symlink.mjs'); -const symlinkPath = path.resolve(tmpdir.path, 'symlink.js'); +const symlinkPath = path.resolve(tmpdir.path, 'symlink.mjs'); try { fs.symlinkSync(realPath, symlinkPath); diff --git a/test/es-module/test-esm-symlink.js b/test/es-module/test-esm-symlink.js index 232925a52e..9b9eb98cd9 100644 --- a/test/es-module/test-esm-symlink.js +++ b/test/es-module/test-esm-symlink.js @@ -12,8 +12,8 @@ const tmpDir = tmpdir.path; const entry = path.join(tmpDir, 'entry.mjs'); const real = path.join(tmpDir, 'index.mjs'); -const link_absolute_path = path.join(tmpDir, 'absolute'); -const link_relative_path = path.join(tmpDir, 'relative'); +const link_absolute_path = path.join(tmpDir, 'absolute.mjs'); +const link_relative_path = path.join(tmpDir, 'relative.mjs'); const link_ignore_extension = path.join(tmpDir, 'ignore_extension.json'); const link_directory = path.join(tmpDir, 'directory'); @@ -22,15 +22,13 @@ fs.writeFileSync(real, 'export default [];'); fs.writeFileSync(entry, ` import assert from 'assert'; import real from './index.mjs'; -import absolute from './absolute'; -import relative from './relative'; +import absolute from './absolute.mjs'; +import relative from './relative.mjs'; import ignoreExtension from './ignore_extension.json'; -import directory from './directory'; assert.strictEqual(absolute, real); assert.strictEqual(relative, real); assert.strictEqual(ignoreExtension, real); -assert.strictEqual(directory, real); `); try { diff --git a/test/es-module/test-esm-throw-undefined.mjs b/test/es-module/test-esm-throw-undefined.mjs deleted file mode 100644 index 541127eee5..0000000000 --- a/test/es-module/test-esm-throw-undefined.mjs +++ /dev/null @@ -1,14 +0,0 @@ -// Flags: --experimental-modules -import '../common'; -import assert from 'assert'; - -async function doTest() { - await assert.rejects( - async () => { - await import('../fixtures/es-module-loaders/throw-undefined'); - }, - (e) => e === undefined - ); -} - -doTest(); diff --git a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs deleted file mode 100644 index 28ccd6ecf2..0000000000 --- a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import module from 'module'; - -const builtins = new Set( - Object.keys(process.binding('natives')).filter(str => - /^(?!(?:internal|node|v8)\/)/.test(str)) -); - -export function dynamicInstantiate(url) { - const builtinInstance = module._load(url.substr(5)); - const builtinExports = ['default', ...Object.keys(builtinInstance)]; - return { - exports: builtinExports, - execute: exports => { - for (let name of builtinExports) - exports[name].set(builtinInstance[name]); - exports.default.set(builtinInstance); - } - }; -} - -export function resolve(specifier, base, defaultResolver) { - if (builtins.has(specifier)) { - return { - url: `node:${specifier}`, - format: 'dynamic' - }; - } - return defaultResolver(specifier, base); -} diff --git a/test/fixtures/es-module-loaders/example-loader.mjs b/test/fixtures/es-module-loaders/example-loader.mjs deleted file mode 100644 index acb4486edc..0000000000 --- a/test/fixtures/es-module-loaders/example-loader.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import url from 'url'; -import path from 'path'; -import process from 'process'; - -const builtins = new Set( - Object.keys(process.binding('natives')).filter((str) => - /^(?!(?:internal|node|v8)\/)/.test(str)) -); -const JS_EXTENSIONS = new Set(['.js', '.mjs']); - -const baseURL = new url.URL('file://'); -baseURL.pathname = process.cwd() + '/'; - -export function resolve(specifier, parentModuleURL = baseURL /*, defaultResolve */) { - if (builtins.has(specifier)) { - return { - url: specifier, - format: 'builtin' - }; - } - if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) { - // For node_modules support: - // return defaultResolve(specifier, parentModuleURL); - throw new Error( - `imports must begin with '/', './', or '../'; '${specifier}' does not`); - } - const resolved = new url.URL(specifier, parentModuleURL); - const ext = path.extname(resolved.pathname); - if (!JS_EXTENSIONS.has(ext)) { - throw new Error( - `Cannot load file with non-JavaScript file extension ${ext}.`); - } - return { - url: resolved.href, - format: 'esm' - }; -} diff --git a/test/fixtures/es-module-loaders/js-as-esm.js b/test/fixtures/es-module-loaders/js-as-esm.js deleted file mode 100644 index b4d2741b2f..0000000000 --- a/test/fixtures/es-module-loaders/js-as-esm.js +++ /dev/null @@ -1 +0,0 @@ -export const namedExport = 'named-export'; diff --git a/test/fixtures/es-module-loaders/js-loader.mjs b/test/fixtures/es-module-loaders/js-loader.mjs deleted file mode 100644 index 9fa6b9eed4..0000000000 --- a/test/fixtures/es-module-loaders/js-loader.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import { URL } from 'url'; - -const builtins = new Set( - Object.keys(process.binding('natives')).filter(str => - /^(?!(?:internal|node|v8)\/)/.test(str)) -) - -const baseURL = new URL('file://'); -baseURL.pathname = process.cwd() + '/'; - -export function resolve (specifier, base = baseURL) { - if (builtins.has(specifier)) { - return { - url: specifier, - format: 'builtin' - }; - } - // load all dependencies as esm, regardless of file extension - const url = new URL(specifier, base).href; - return { - url, - format: 'esm' - }; -} diff --git a/test/fixtures/es-module-loaders/loader-dep.js b/test/fixtures/es-module-loaders/loader-dep.js deleted file mode 100644 index cf821afec1..0000000000 --- a/test/fixtures/es-module-loaders/loader-dep.js +++ /dev/null @@ -1 +0,0 @@ -exports.format = 'esm'; diff --git a/test/fixtures/es-module-loaders/loader-invalid-format.mjs b/test/fixtures/es-module-loaders/loader-invalid-format.mjs deleted file mode 100644 index 17a0dcd04d..0000000000 --- a/test/fixtures/es-module-loaders/loader-invalid-format.mjs +++ /dev/null @@ -1,8 +0,0 @@ -export async function resolve(specifier, parentModuleURL, defaultResolve) { - if (parentModuleURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') { - return { - url: 'file:///asdf' - }; - } - return defaultResolve(specifier, parentModuleURL); -} diff --git a/test/fixtures/es-module-loaders/loader-invalid-url.mjs b/test/fixtures/es-module-loaders/loader-invalid-url.mjs deleted file mode 100644 index 12efbb5021..0000000000 --- a/test/fixtures/es-module-loaders/loader-invalid-url.mjs +++ /dev/null @@ -1,9 +0,0 @@ -export async function resolve(specifier, parentModuleURL, defaultResolve) { - if (parentModuleURL && specifier === '../fixtures/es-modules/test-esm-ok.mjs') { - return { - url: specifier, - format: 'esm' - }; - } - return defaultResolve(specifier, parentModuleURL); -} diff --git a/test/fixtures/es-module-loaders/loader-shared-dep.mjs b/test/fixtures/es-module-loaders/loader-shared-dep.mjs deleted file mode 100644 index 1a19e4c892..0000000000 --- a/test/fixtures/es-module-loaders/loader-shared-dep.mjs +++ /dev/null @@ -1,7 +0,0 @@ -import dep from './loader-dep.js'; -import assert from 'assert'; - -export function resolve(specifier, base, defaultResolve) { - assert.strictEqual(dep.format, 'esm'); - return defaultResolve(specifier, base); -} diff --git a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs deleted file mode 100644 index e7c6c8ff34..0000000000 --- a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs +++ /dev/null @@ -1,6 +0,0 @@ -export async function resolve(specifier, parent, defaultResolve) { - if (specifier === 'unknown-builtin-module') { - return { url: 'unknown-builtin-module', format: 'builtin' }; - } - return defaultResolve(specifier, parent); -} \ No newline at end of file diff --git a/test/fixtures/es-module-loaders/loader-with-dep.mjs b/test/fixtures/es-module-loaders/loader-with-dep.mjs deleted file mode 100644 index 944e6e438c..0000000000 --- a/test/fixtures/es-module-loaders/loader-with-dep.mjs +++ /dev/null @@ -1,7 +0,0 @@ -import dep from './loader-dep.js'; -export function resolve (specifier, base, defaultResolve) { - return { - url: defaultResolve(specifier, base).url, - format: dep.format - }; -} diff --git a/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs b/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs deleted file mode 100644 index 6993747fcc..0000000000 --- a/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs +++ /dev/null @@ -1,6 +0,0 @@ -export function resolve(specifier, parentModule, defaultResolver) { - if (specifier !== 'test') { - return defaultResolver(specifier, parentModule); - } - return { url: 'file://', format: 'dynamic' }; -} diff --git a/test/fixtures/es-module-loaders/module-named-exports.mjs b/test/fixtures/es-module-loaders/module-named-exports.mjs deleted file mode 100644 index 04f7f43ebd..0000000000 --- a/test/fixtures/es-module-loaders/module-named-exports.mjs +++ /dev/null @@ -1,2 +0,0 @@ -export const foo = 'foo'; -export const bar = 'bar'; diff --git a/test/fixtures/es-module-loaders/not-found-assert-loader.mjs b/test/fixtures/es-module-loaders/not-found-assert-loader.mjs deleted file mode 100644 index d15f294fe6..0000000000 --- a/test/fixtures/es-module-loaders/not-found-assert-loader.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'assert'; - -// a loader that asserts that the defaultResolve will throw "not found" -// (skipping the top-level main of course) -let mainLoad = true; -export async function resolve (specifier, base, defaultResolve) { - if (mainLoad) { - mainLoad = false; - return defaultResolve(specifier, base); - } - try { - await defaultResolve(specifier, base); - } - catch (e) { - assert.strictEqual(e.code, 'MODULE_NOT_FOUND'); - return { - format: 'builtin', - url: 'fs' - }; - } - assert.fail(`Module resolution for ${specifier} should be throw MODULE_NOT_FOUND`); -} diff --git a/test/fixtures/es-module-loaders/syntax-error-import.mjs b/test/fixtures/es-module-loaders/syntax-error-import.mjs deleted file mode 100644 index 9cad68c7ce..0000000000 --- a/test/fixtures/es-module-loaders/syntax-error-import.mjs +++ /dev/null @@ -1 +0,0 @@ -import { foo, notfound } from './module-named-exports'; diff --git a/test/fixtures/es-module-loaders/syntax-error.mjs b/test/fixtures/es-module-loaders/syntax-error.mjs deleted file mode 100644 index bda4a7e6eb..0000000000 --- a/test/fixtures/es-module-loaders/syntax-error.mjs +++ /dev/null @@ -1,2 +0,0 @@ -'use strict'; -await async () => 0; diff --git a/test/fixtures/es-module-loaders/throw-undefined.mjs b/test/fixtures/es-module-loaders/throw-undefined.mjs deleted file mode 100644 index f062276767..0000000000 --- a/test/fixtures/es-module-loaders/throw-undefined.mjs +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -throw undefined; diff --git a/test/fixtures/es-modules/esm-snapshot-mutator.js b/test/fixtures/es-modules/esm-snapshot-mutator.js deleted file mode 100644 index ee52c270f6..0000000000 --- a/test/fixtures/es-modules/esm-snapshot-mutator.js +++ /dev/null @@ -1,4 +0,0 @@ -'use strict'; -const shouldSnapshotFilePath = require.resolve('./esm-snapshot.js'); -require('./esm-snapshot.js'); -require.cache[shouldSnapshotFilePath].exports++; diff --git a/test/fixtures/es-modules/esm-snapshot.js b/test/fixtures/es-modules/esm-snapshot.js deleted file mode 100644 index 329a0ca3f4..0000000000 --- a/test/fixtures/es-modules/esm-snapshot.js +++ /dev/null @@ -1,2 +0,0 @@ -'use strict'; -module.exports = 1; diff --git a/test/fixtures/es-modules/json.json b/test/fixtures/es-modules/json.json deleted file mode 100644 index 8288d42e2b..0000000000 --- a/test/fixtures/es-modules/json.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "val": 42 -} diff --git a/test/fixtures/es-modules/loop.mjs b/test/fixtures/es-modules/loop.mjs index 1b5cab10ed..3d2ddd2eb7 100644 --- a/test/fixtures/es-modules/loop.mjs +++ b/test/fixtures/es-modules/loop.mjs @@ -1,4 +1,4 @@ -import { message } from './message'; +import { message } from './message.mjs'; var t = 1; var k = 1; diff --git a/test/fixtures/es-modules/pjson-main/main.js b/test/fixtures/es-modules/pjson-main/main.js deleted file mode 100644 index dfdd47b877..0000000000 --- a/test/fixtures/es-modules/pjson-main/main.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'main'; diff --git a/test/fixtures/es-modules/pjson-main/main.mjs b/test/fixtures/es-modules/pjson-main/main.mjs new file mode 100644 index 0000000000..9eb0aade18 --- /dev/null +++ b/test/fixtures/es-modules/pjson-main/main.mjs @@ -0,0 +1 @@ +export const main = 'main' diff --git a/test/fixtures/es-modules/pjson-main/package.json b/test/fixtures/es-modules/pjson-main/package.json index c13b8cf6ac..ea9b784692 100644 --- a/test/fixtures/es-modules/pjson-main/package.json +++ b/test/fixtures/es-modules/pjson-main/package.json @@ -1,3 +1,3 @@ { - "main": "main.js" + "main": "main.mjs" } diff --git a/test/fixtures/es-modules/test-esm-double-encoding-native%20.js b/test/fixtures/es-modules/test-esm-double-encoding-native%20.mjs similarity index 86% rename from test/fixtures/es-modules/test-esm-double-encoding-native%20.js rename to test/fixtures/es-modules/test-esm-double-encoding-native%20.mjs index ea1caa81be..a3bfe972e5 100644 --- a/test/fixtures/es-modules/test-esm-double-encoding-native%20.js +++ b/test/fixtures/es-modules/test-esm-double-encoding-native%20.mjs @@ -3,4 +3,4 @@ // Trivial test to assert we can load files with `%` in their pathname. // Imported by `test-esm-double-encoding.mjs`. -module.exports = 42; +export default 42; diff --git a/test/fixtures/syntax/bad_syntax.mjs b/test/fixtures/syntax/bad_syntax.mjs new file mode 100644 index 0000000000..c2cd118b23 --- /dev/null +++ b/test/fixtures/syntax/bad_syntax.mjs @@ -0,0 +1 @@ +var foo bar; diff --git a/test/message/esm_display_syntax_error_import.mjs b/test/message/esm_display_syntax_error_import.mjs deleted file mode 100644 index 87cedf1d4e..0000000000 --- a/test/message/esm_display_syntax_error_import.mjs +++ /dev/null @@ -1,7 +0,0 @@ -// Flags: --experimental-modules -/* eslint-disable no-unused-vars */ -import '../common'; -import { - foo, - notfound -} from '../fixtures/es-module-loaders/module-named-exports'; diff --git a/test/message/esm_display_syntax_error_import.out b/test/message/esm_display_syntax_error_import.out deleted file mode 100644 index 31ee2b6f4b..0000000000 --- a/test/message/esm_display_syntax_error_import.out +++ /dev/null @@ -1,6 +0,0 @@ -(node:*) ExperimentalWarning: The ESM module loader is experimental. -file:///*/test/message/esm_display_syntax_error_import.mjs:6 - notfound - ^^^^^^^^ -SyntaxError: The requested module '../fixtures/es-module-loaders/module-named-exports' does not provide an export named 'notfound' - at ModuleJob._instantiate (internal/modules/esm/module_job.js:*:*) diff --git a/test/message/esm_display_syntax_error_import_module.mjs b/test/message/esm_display_syntax_error_import_module.mjs deleted file mode 100644 index 32c0edb350..0000000000 --- a/test/message/esm_display_syntax_error_import_module.mjs +++ /dev/null @@ -1,3 +0,0 @@ -// Flags: --experimental-modules -import '../common'; -import '../fixtures/es-module-loaders/syntax-error-import'; diff --git a/test/message/esm_display_syntax_error_import_module.out b/test/message/esm_display_syntax_error_import_module.out deleted file mode 100644 index b067a77942..0000000000 --- a/test/message/esm_display_syntax_error_import_module.out +++ /dev/null @@ -1,6 +0,0 @@ -(node:*) ExperimentalWarning: The ESM module loader is experimental. -file:///*/test/fixtures/es-module-loaders/syntax-error-import.mjs:1 -import { foo, notfound } from './module-named-exports'; - ^^^^^^^^ -SyntaxError: The requested module './module-named-exports' does not provide an export named 'notfound' - at ModuleJob._instantiate (internal/modules/esm/module_job.js:*:*) diff --git a/test/message/esm_display_syntax_error_module.mjs b/test/message/esm_display_syntax_error_module.mjs deleted file mode 100644 index e74b70bec8..0000000000 --- a/test/message/esm_display_syntax_error_module.mjs +++ /dev/null @@ -1,3 +0,0 @@ -// Flags: --experimental-modules -import '../common'; -import '../fixtures/es-module-loaders/syntax-error'; diff --git a/test/message/esm_display_syntax_error_module.out b/test/message/esm_display_syntax_error_module.out deleted file mode 100644 index e636abad9e..0000000000 --- a/test/message/esm_display_syntax_error_module.out +++ /dev/null @@ -1,6 +0,0 @@ -(node:*) ExperimentalWarning: The ESM module loader is experimental. -file:///*/test/fixtures/es-module-loaders/syntax-error.mjs:2 -await async () => 0; -^^^^^ -SyntaxError: Unexpected reserved word - at translators.set (internal/modules/esm/translators.js:*:*) diff --git a/test/parallel/test-loaders-unknown-builtin-module.mjs b/test/parallel/test-loaders-unknown-builtin-module.mjs deleted file mode 100644 index db3cfa3582..0000000000 --- a/test/parallel/test-loaders-unknown-builtin-module.mjs +++ /dev/null @@ -1,12 +0,0 @@ -// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs -import { expectsError, mustCall } from '../common'; -import assert from 'assert'; - -const unknownBuiltinModule = 'unknown-builtin-module'; - -import(unknownBuiltinModule) -.then(assert.fail, expectsError({ - code: 'ERR_UNKNOWN_BUILTIN_MODULE', - message: `No such built-in module: ${unknownBuiltinModule}` -})) -.then(mustCall()); diff --git a/test/parallel/test-module-main-extension-lookup.js b/test/parallel/test-module-main-extension-lookup.js index 3d20316647..9e7eab295e 100644 --- a/test/parallel/test-module-main-extension-lookup.js +++ b/test/parallel/test-module-main-extension-lookup.js @@ -6,6 +6,6 @@ const { execFileSync } = require('child_process'); const node = process.argv[0]; execFileSync(node, ['--experimental-modules', - fixtures.path('es-modules', 'test-esm-ok')]); + fixtures.path('es-modules', 'test-esm-ok.mjs')]); execFileSync(node, ['--experimental-modules', fixtures.path('es-modules', 'noext')]); diff --git a/test/parallel/test-util-inspect-namespace.js b/test/parallel/test-util-inspect-namespace.js deleted file mode 100644 index f2b6e57178..0000000000 --- a/test/parallel/test-util-inspect-namespace.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules - -require('../common'); -const assert = require('assert'); - -const { SourceTextModule } = require('vm'); -const { inspect } = require('util'); - -(async () => { - const m = new SourceTextModule('export const a = 1; export var b = 2'); - await m.link(() => 0); - m.instantiate(); - assert.strictEqual( - inspect(m.namespace), - '[Module] { a: , b: undefined }'); - await m.evaluate(); - assert.strictEqual(inspect(m.namespace), '[Module] { a: 1, b: 2 }'); -})(); diff --git a/test/parallel/test-util-types.js b/test/parallel/test-util-types.js deleted file mode 100644 index 69ebaaba12..0000000000 --- a/test/parallel/test-util-types.js +++ /dev/null @@ -1,287 +0,0 @@ -// Flags: --experimental-vm-modules --expose-internals -'use strict'; -require('../common'); -const fixtures = require('../common/fixtures'); -const assert = require('assert'); -const { types, inspect } = require('util'); -const vm = require('vm'); -const { internalBinding } = require('internal/test/binding'); -const { JSStream } = internalBinding('js_stream'); - -const external = (new JSStream())._externalStream; -const wasmBuffer = fixtures.readSync('simple.wasm'); - -for (const [ value, _method ] of [ - [ external, 'isExternal' ], - [ new Date() ], - [ (function() { return arguments; })(), 'isArgumentsObject' ], - [ new Boolean(), 'isBooleanObject' ], - [ new Number(), 'isNumberObject' ], - [ new String(), 'isStringObject' ], - [ Object(Symbol()), 'isSymbolObject' ], - [ Object(BigInt(0)), 'isBigIntObject' ], - [ new Error(), 'isNativeError' ], - [ new RegExp() ], - [ async function() {}, 'isAsyncFunction' ], - [ function*() {}, 'isGeneratorFunction' ], - [ (function*() {})(), 'isGeneratorObject' ], - [ Promise.resolve() ], - [ new Map() ], - [ new Set() ], - [ (new Map())[Symbol.iterator](), 'isMapIterator' ], - [ (new Set())[Symbol.iterator](), 'isSetIterator' ], - [ new WeakMap() ], - [ new WeakSet() ], - [ new ArrayBuffer() ], - [ new Uint8Array() ], - [ new Uint8ClampedArray() ], - [ new Uint16Array() ], - [ new Uint32Array() ], - [ new Int8Array() ], - [ new Int16Array() ], - [ new Int32Array() ], - [ new Float32Array() ], - [ new Float64Array() ], - [ new BigInt64Array() ], - [ new BigUint64Array() ], - [ Object.defineProperty(new Uint8Array(), - Symbol.toStringTag, - { value: 'foo' }) ], - [ new DataView(new ArrayBuffer()) ], - [ new SharedArrayBuffer() ], - [ new Proxy({}, {}), 'isProxy' ], - [ new WebAssembly.Module(wasmBuffer), 'isWebAssemblyCompiledModule' ], -]) { - const method = _method || `is${value.constructor.name}`; - assert(method in types, `Missing ${method} for ${inspect(value)}`); - assert(types[method](value), `Want ${inspect(value)} to match ${method}`); - - for (const key of Object.keys(types)) { - if ((types.isArrayBufferView(value) || - types.isAnyArrayBuffer(value)) && key.includes('Array') || - key === 'isBoxedPrimitive') { - continue; - } - - assert.strictEqual(types[key](value), - key === method, - `${inspect(value)}: ${key}, ` + - `${method}, ${types[key](value)}`); - } -} - -// Check boxed primitives. -[ - new Boolean(), - new Number(), - new String(), - Object(Symbol()), - Object(BigInt(0)) -].forEach((entry) => assert(types.isBoxedPrimitive(entry))); - -{ - assert(!types.isUint8Array({ [Symbol.toStringTag]: 'Uint8Array' })); - assert(types.isUint8Array(vm.runInNewContext('new Uint8Array'))); - - assert(!types.isUint8ClampedArray({ - [Symbol.toStringTag]: 'Uint8ClampedArray' - })); - assert(types.isUint8ClampedArray( - vm.runInNewContext('new Uint8ClampedArray') - )); - - assert(!types.isUint16Array({ [Symbol.toStringTag]: 'Uint16Array' })); - assert(types.isUint16Array(vm.runInNewContext('new Uint16Array'))); - - assert(!types.isUint32Array({ [Symbol.toStringTag]: 'Uint32Array' })); - assert(types.isUint32Array(vm.runInNewContext('new Uint32Array'))); - - assert(!types.isInt8Array({ [Symbol.toStringTag]: 'Int8Array' })); - assert(types.isInt8Array(vm.runInNewContext('new Int8Array'))); - - assert(!types.isInt16Array({ [Symbol.toStringTag]: 'Int16Array' })); - assert(types.isInt16Array(vm.runInNewContext('new Int16Array'))); - - assert(!types.isInt32Array({ [Symbol.toStringTag]: 'Int32Array' })); - assert(types.isInt32Array(vm.runInNewContext('new Int32Array'))); - - assert(!types.isFloat32Array({ [Symbol.toStringTag]: 'Float32Array' })); - assert(types.isFloat32Array(vm.runInNewContext('new Float32Array'))); - - assert(!types.isFloat64Array({ [Symbol.toStringTag]: 'Float64Array' })); - assert(types.isFloat64Array(vm.runInNewContext('new Float64Array'))); - - assert(!types.isBigInt64Array({ [Symbol.toStringTag]: 'BigInt64Array' })); - assert(types.isBigInt64Array(vm.runInNewContext('new BigInt64Array'))); - - assert(!types.isBigUint64Array({ [Symbol.toStringTag]: 'BigUint64Array' })); - assert(types.isBigUint64Array(vm.runInNewContext('new BigUint64Array'))); -} - -{ - const primitive = true; - const arrayBuffer = new ArrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - const dataView = new DataView(arrayBuffer); - const uint8Array = new Uint8Array(arrayBuffer); - const uint8ClampedArray = new Uint8ClampedArray(arrayBuffer); - const uint16Array = new Uint16Array(arrayBuffer); - const uint32Array = new Uint32Array(arrayBuffer); - const int8Array = new Int8Array(arrayBuffer); - const int16Array = new Int16Array(arrayBuffer); - const int32Array = new Int32Array(arrayBuffer); - const float32Array = new Float32Array(arrayBuffer); - const float64Array = new Float64Array(arrayBuffer); - const bigInt64Array = new BigInt64Array(arrayBuffer); - const bigUint64Array = new BigUint64Array(arrayBuffer); - - const fakeBuffer = Object.create(Buffer.prototype); - const fakeDataView = Object.create(DataView.prototype); - const fakeUint8Array = Object.create(Uint8Array.prototype); - const fakeUint8ClampedArray = Object.create(Uint8ClampedArray.prototype); - const fakeUint16Array = Object.create(Uint16Array.prototype); - const fakeUint32Array = Object.create(Uint32Array.prototype); - const fakeInt8Array = Object.create(Int8Array.prototype); - const fakeInt16Array = Object.create(Int16Array.prototype); - const fakeInt32Array = Object.create(Int32Array.prototype); - const fakeFloat32Array = Object.create(Float32Array.prototype); - const fakeFloat64Array = Object.create(Float64Array.prototype); - const fakeBigInt64Array = Object.create(BigInt64Array.prototype); - const fakeBigUint64Array = Object.create(BigUint64Array.prototype); - - const stealthyDataView = - Object.setPrototypeOf(new DataView(arrayBuffer), Uint8Array.prototype); - const stealthyUint8Array = - Object.setPrototypeOf(new Uint8Array(arrayBuffer), ArrayBuffer.prototype); - const stealthyUint8ClampedArray = - Object.setPrototypeOf( - new Uint8ClampedArray(arrayBuffer), ArrayBuffer.prototype - ); - const stealthyUint16Array = - Object.setPrototypeOf(new Uint16Array(arrayBuffer), Uint16Array.prototype); - const stealthyUint32Array = - Object.setPrototypeOf(new Uint32Array(arrayBuffer), Uint32Array.prototype); - const stealthyInt8Array = - Object.setPrototypeOf(new Int8Array(arrayBuffer), Int8Array.prototype); - const stealthyInt16Array = - Object.setPrototypeOf(new Int16Array(arrayBuffer), Int16Array.prototype); - const stealthyInt32Array = - Object.setPrototypeOf(new Int32Array(arrayBuffer), Int32Array.prototype); - const stealthyFloat32Array = - Object.setPrototypeOf( - new Float32Array(arrayBuffer), Float32Array.prototype - ); - const stealthyFloat64Array = - Object.setPrototypeOf( - new Float64Array(arrayBuffer), Float64Array.prototype - ); - const stealthyBigInt64Array = - Object.setPrototypeOf( - new BigInt64Array(arrayBuffer), BigInt64Array.prototype - ); - const stealthyBigUint64Array = - Object.setPrototypeOf( - new BigUint64Array(arrayBuffer), BigUint64Array.prototype - ); - - const all = [ - primitive, arrayBuffer, buffer, fakeBuffer, - dataView, fakeDataView, stealthyDataView, - uint8Array, fakeUint8Array, stealthyUint8Array, - uint8ClampedArray, fakeUint8ClampedArray, stealthyUint8ClampedArray, - uint16Array, fakeUint16Array, stealthyUint16Array, - uint32Array, fakeUint32Array, stealthyUint32Array, - int8Array, fakeInt8Array, stealthyInt8Array, - int16Array, fakeInt16Array, stealthyInt16Array, - int32Array, fakeInt32Array, stealthyInt32Array, - float32Array, fakeFloat32Array, stealthyFloat32Array, - float64Array, fakeFloat64Array, stealthyFloat64Array, - bigInt64Array, fakeBigInt64Array, stealthyBigInt64Array, - bigUint64Array, fakeBigUint64Array, stealthyBigUint64Array - ]; - - const expected = { - isArrayBufferView: [ - buffer, - dataView, stealthyDataView, - uint8Array, stealthyUint8Array, - uint8ClampedArray, stealthyUint8ClampedArray, - uint16Array, stealthyUint16Array, - uint32Array, stealthyUint32Array, - int8Array, stealthyInt8Array, - int16Array, stealthyInt16Array, - int32Array, stealthyInt32Array, - float32Array, stealthyFloat32Array, - float64Array, stealthyFloat64Array, - bigInt64Array, stealthyBigInt64Array, - bigUint64Array, stealthyBigUint64Array - ], - isTypedArray: [ - buffer, - uint8Array, stealthyUint8Array, - uint8ClampedArray, stealthyUint8ClampedArray, - uint16Array, stealthyUint16Array, - uint32Array, stealthyUint32Array, - int8Array, stealthyInt8Array, - int16Array, stealthyInt16Array, - int32Array, stealthyInt32Array, - float32Array, stealthyFloat32Array, - float64Array, stealthyFloat64Array, - bigInt64Array, stealthyBigInt64Array, - bigUint64Array, stealthyBigUint64Array - ], - isUint8Array: [ - buffer, uint8Array, stealthyUint8Array - ], - isUint8ClampedArray: [ - uint8ClampedArray, stealthyUint8ClampedArray - ], - isUint16Array: [ - uint16Array, stealthyUint16Array - ], - isUint32Array: [ - uint32Array, stealthyUint32Array - ], - isInt8Array: [ - int8Array, stealthyInt8Array - ], - isInt16Array: [ - int16Array, stealthyInt16Array - ], - isInt32Array: [ - int32Array, stealthyInt32Array - ], - isFloat32Array: [ - float32Array, stealthyFloat32Array - ], - isFloat64Array: [ - float64Array, stealthyFloat64Array - ], - isBigInt64Array: [ - bigInt64Array, stealthyBigInt64Array - ], - isBigUint64Array: [ - bigUint64Array, stealthyBigUint64Array - ] - }; - - for (const testedFunc of Object.keys(expected)) { - const func = types[testedFunc]; - const yup = []; - for (const value of all) { - if (func(value)) { - yup.push(value); - } - } - console.log('Testing', testedFunc); - assert.deepStrictEqual(yup, expected[testedFunc]); - } -} - -(async () => { - const m = new vm.SourceTextModule(''); - await m.link(() => 0); - m.instantiate(); - await m.evaluate(); - assert.ok(types.isModuleNamespaceObject(m.namespace)); -})(); diff --git a/test/parallel/test-vm-module-basic.js b/test/parallel/test-vm-module-basic.js deleted file mode 100644 index 8cf687c2bb..0000000000 --- a/test/parallel/test-vm-module-basic.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules - -const common = require('../common'); -const assert = require('assert'); -const { SourceTextModule, createContext } = require('vm'); - -(async function test1() { - const context = createContext({ - foo: 'bar', - baz: undefined, - typeofProcess: undefined, - }); - const m = new SourceTextModule( - 'baz = foo; typeofProcess = typeof process; typeof Object;', - { context } - ); - assert.strictEqual(m.status, 'uninstantiated'); - await m.link(common.mustNotCall()); - m.instantiate(); - assert.strictEqual(m.status, 'instantiated'); - const result = await m.evaluate(); - assert.strictEqual(m.status, 'evaluated'); - assert.strictEqual(Object.getPrototypeOf(result), null); - assert.deepStrictEqual(context, { - foo: 'bar', - baz: 'bar', - typeofProcess: 'undefined' - }); - assert.strictEqual(result.result, 'function'); -}()); - -(async () => { - const m = new SourceTextModule( - 'global.vmResult = "foo"; Object.prototype.toString.call(process);' - ); - await m.link(common.mustNotCall()); - m.instantiate(); - const { result } = await m.evaluate(); - assert.strictEqual(global.vmResult, 'foo'); - assert.strictEqual(result, '[object process]'); - delete global.vmResult; -})(); - -(async () => { - const m = new SourceTextModule('while (true) {}'); - await m.link(common.mustNotCall()); - m.instantiate(); - await m.evaluate({ timeout: 500 }) - .then(() => assert(false), () => {}); -})(); - -// Check the generated url for each module -(async () => { - const context1 = createContext({ }); - const context2 = createContext({ }); - - const m1 = new SourceTextModule('1', { context: context1 }); - assert.strictEqual(m1.url, 'vm:module(0)'); - const m2 = new SourceTextModule('2', { context: context1 }); - assert.strictEqual(m2.url, 'vm:module(1)'); - const m3 = new SourceTextModule('3', { context: context2 }); - assert.strictEqual(m3.url, 'vm:module(0)'); -})(); diff --git a/test/parallel/test-vm-module-dynamic-import.js b/test/parallel/test-vm-module-dynamic-import.js deleted file mode 100644 index 600f455e93..0000000000 --- a/test/parallel/test-vm-module-dynamic-import.js +++ /dev/null @@ -1,101 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules --experimental-modules - -const common = require('../common'); - -const assert = require('assert'); -const { Script, SourceTextModule, createContext } = require('vm'); - -async function testNoCallback() { - const m = new SourceTextModule('import("foo")', { context: createContext() }); - await m.link(common.mustNotCall()); - m.instantiate(); - const { result } = await m.evaluate(); - let threw = false; - try { - await result; - } catch (err) { - threw = true; - assert.strictEqual(err.code, 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING'); - } - assert(threw); -} - -async function test() { - const foo = new SourceTextModule('export const a = 1;'); - await foo.link(common.mustNotCall()); - foo.instantiate(); - await foo.evaluate(); - - { - const s = new Script('import("foo")', { - importModuleDynamically: common.mustCall((specifier, wrap) => { - assert.strictEqual(specifier, 'foo'); - assert.strictEqual(wrap, s); - return foo; - }), - }); - - const result = s.runInThisContext(); - assert.strictEqual(foo.namespace, await result); - } - - { - const m = new SourceTextModule('import("foo")', { - importModuleDynamically: common.mustCall((specifier, wrap) => { - assert.strictEqual(specifier, 'foo'); - assert.strictEqual(wrap, m); - return foo; - }), - }); - await m.link(common.mustNotCall()); - m.instantiate(); - const { result } = await m.evaluate(); - assert.strictEqual(foo.namespace, await result); - } -} - -async function testInvalid() { - const m = new SourceTextModule('import("foo")', { - importModuleDynamically: common.mustCall((specifier, wrap) => { - return 5; - }), - }); - await m.link(common.mustNotCall()); - m.instantiate(); - const { result } = await m.evaluate(); - await result.catch(common.mustCall((e) => { - assert.strictEqual(e.code, 'ERR_VM_MODULE_NOT_MODULE'); - })); - - const s = new Script('import("foo")', { - importModuleDynamically: common.mustCall((specifier, wrap) => { - return undefined; - }), - }); - let threw = false; - try { - await s.runInThisContext(); - } catch (e) { - threw = true; - assert.strictEqual(e.code, 'ERR_VM_MODULE_NOT_MODULE'); - } - assert(threw); -} - -async function testInvalidimportModuleDynamically() { - assert.throws( - () => new Script( - 'import("foo")', - { importModuleDynamically: false }), - { code: 'ERR_INVALID_ARG_TYPE' } - ); -} - -(async function() { - await testNoCallback(); - await test(); - await testInvalid(); - await testInvalidimportModuleDynamically(); -}()).then(common.mustCall()); diff --git a/test/parallel/test-vm-module-errors.js b/test/parallel/test-vm-module-errors.js deleted file mode 100644 index a343a542a1..0000000000 --- a/test/parallel/test-vm-module-errors.js +++ /dev/null @@ -1,284 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules - -const common = require('../common'); - -const assert = require('assert'); - -const { SourceTextModule, createContext } = require('vm'); - -async function expectsRejection(fn, settings) { - const validateError = common.expectsError(settings); - // Retain async context. - const storedError = new Error('Thrown from:'); - try { - await fn(); - } catch (err) { - try { - validateError(err); - } catch (validationError) { - console.error(validationError); - console.error('Original error:'); - console.error(err); - throw storedError; - } - return; - } - assert.fail('Missing expected exception'); -} - -async function createEmptyLinkedModule() { - const m = new SourceTextModule(''); - await m.link(common.mustNotCall()); - return m; -} - -async function checkArgType() { - common.expectsError(() => { - new SourceTextModule(); - }, { - code: 'ERR_INVALID_ARG_TYPE', - type: TypeError - }); - - for (const invalidOptions of [ - 0, 1, null, true, 'str', () => {}, { url: 0 }, Symbol.iterator, - { context: null }, { context: 'hucairz' }, { context: {} } - ]) { - common.expectsError(() => { - new SourceTextModule('', invalidOptions); - }, { - code: 'ERR_INVALID_ARG_TYPE', - type: TypeError - }); - } - - for (const invalidLinker of [ - 0, 1, undefined, null, true, 'str', {}, Symbol.iterator - ]) { - await expectsRejection(async () => { - const m = new SourceTextModule(''); - await m.link(invalidLinker); - }, { - code: 'ERR_INVALID_ARG_TYPE', - type: TypeError - }); - } -} - -// Check methods/properties can only be used under a specific state. -async function checkModuleState() { - await expectsRejection(async () => { - const m = new SourceTextModule(''); - await m.link(common.mustNotCall()); - assert.strictEqual(m.linkingStatus, 'linked'); - await m.link(common.mustNotCall()); - }, { - code: 'ERR_VM_MODULE_ALREADY_LINKED' - }); - - await expectsRejection(async () => { - const m = new SourceTextModule(''); - m.link(common.mustNotCall()); - assert.strictEqual(m.linkingStatus, 'linking'); - await m.link(common.mustNotCall()); - }, { - code: 'ERR_VM_MODULE_ALREADY_LINKED' - }); - - common.expectsError(() => { - const m = new SourceTextModule(''); - m.instantiate(); - }, { - code: 'ERR_VM_MODULE_NOT_LINKED' - }); - - await expectsRejection(async () => { - const m = new SourceTextModule('import "foo";'); - try { - await m.link(common.mustCall(() => ({}))); - } catch { - assert.strictEqual(m.linkingStatus, 'errored'); - m.instantiate(); - } - assert.fail('Unreachable'); - }, { - code: 'ERR_VM_MODULE_NOT_LINKED' - }); - - { - const m = new SourceTextModule('import "foo";'); - await m.link(common.mustCall(async (specifier, module) => { - assert.strictEqual(module, m); - assert.strictEqual(specifier, 'foo'); - assert.strictEqual(m.linkingStatus, 'linking'); - common.expectsError(() => { - m.instantiate(); - }, { - code: 'ERR_VM_MODULE_NOT_LINKED' - }); - return new SourceTextModule(''); - })); - m.instantiate(); - await m.evaluate(); - } - - await expectsRejection(async () => { - const m = new SourceTextModule(''); - await m.evaluate(); - }, { - code: 'ERR_VM_MODULE_STATUS', - message: 'Module status must be one of instantiated, evaluated, and errored' - }); - - await expectsRejection(async () => { - const m = new SourceTextModule(''); - await m.evaluate(false); - }, { - code: 'ERR_INVALID_ARG_TYPE', - message: 'The "options" argument must be of type Object. ' + - 'Received type boolean' - }); - - await expectsRejection(async () => { - const m = await createEmptyLinkedModule(); - await m.evaluate(); - }, { - code: 'ERR_VM_MODULE_STATUS', - message: 'Module status must be one of instantiated, evaluated, and errored' - }); - - common.expectsError(() => { - const m = new SourceTextModule(''); - m.error; - }, { - code: 'ERR_VM_MODULE_STATUS', - message: 'Module status must be errored' - }); - - await expectsRejection(async () => { - const m = await createEmptyLinkedModule(); - m.instantiate(); - await m.evaluate(); - m.error; - }, { - code: 'ERR_VM_MODULE_STATUS', - message: 'Module status must be errored' - }); - - common.expectsError(() => { - const m = new SourceTextModule(''); - m.namespace; - }, { - code: 'ERR_VM_MODULE_STATUS', - message: 'Module status must not be uninstantiated or instantiating' - }); - - await expectsRejection(async () => { - const m = await createEmptyLinkedModule(); - m.namespace; - }, { - code: 'ERR_VM_MODULE_STATUS', - message: 'Module status must not be uninstantiated or instantiating' - }); -} - -// Check link() fails when the returned module is not valid. -async function checkLinking() { - await expectsRejection(async () => { - const m = new SourceTextModule('import "foo";'); - try { - await m.link(common.mustCall(() => ({}))); - } catch (err) { - assert.strictEqual(m.linkingStatus, 'errored'); - throw err; - } - assert.fail('Unreachable'); - }, { - code: 'ERR_VM_MODULE_NOT_MODULE' - }); - - await expectsRejection(async () => { - const c = createContext({ a: 1 }); - const foo = new SourceTextModule('', { context: c }); - await foo.link(common.mustNotCall()); - const bar = new SourceTextModule('import "foo";'); - try { - await bar.link(common.mustCall(() => foo)); - } catch (err) { - assert.strictEqual(bar.linkingStatus, 'errored'); - throw err; - } - assert.fail('Unreachable'); - }, { - code: 'ERR_VM_MODULE_DIFFERENT_CONTEXT' - }); - - await expectsRejection(async () => { - const erroredModule = new SourceTextModule('import "foo";'); - try { - await erroredModule.link(common.mustCall(() => ({}))); - } catch { - // ignored - } finally { - assert.strictEqual(erroredModule.linkingStatus, 'errored'); - } - - const rootModule = new SourceTextModule('import "errored";'); - await rootModule.link(common.mustCall(() => erroredModule)); - }, { - code: 'ERR_VM_MODULE_LINKING_ERRORED' - }); -} - -common.expectsError(() => { - new SourceTextModule('', { - importModuleDynamically: 'hucairz' - }); -}, { - code: 'ERR_INVALID_ARG_TYPE', - type: TypeError, - message: 'The "options.importModuleDynamically"' + - ' property must be of type function. Received type string' -}); - -// Check the JavaScript engine deals with exceptions correctly -async function checkExecution() { - await (async () => { - 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. - assert.throws(() => { - m.instantiate(); - }, SyntaxError); - })(); - - await (async () => { - const m = new SourceTextModule('throw new Error();'); - await m.link(common.mustNotCall()); - m.instantiate(); - const evaluatePromise = m.evaluate(); - await evaluatePromise.catch(() => {}); - assert.strictEqual(m.status, 'errored'); - try { - await evaluatePromise; - } catch (err) { - assert.strictEqual(m.error, err); - return; - } - assert.fail('Missing expected exception'); - })(); -} - -const finished = common.mustCall(); - -(async function main() { - await checkArgType(); - await checkModuleState(); - await checkLinking(); - await checkExecution(); - finished(); -})(); diff --git a/test/parallel/test-vm-module-import-meta.js b/test/parallel/test-vm-module-import-meta.js deleted file mode 100644 index 4886464f34..0000000000 --- a/test/parallel/test-vm-module-import-meta.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules - -const common = require('../common'); -const assert = require('assert'); -const { SourceTextModule } = require('vm'); - -async function testBasic() { - const m = new SourceTextModule('import.meta;', { - initializeImportMeta: common.mustCall((meta, module) => { - assert.strictEqual(module, m); - meta.prop = 42; - }) - }); - await m.link(common.mustNotCall()); - m.instantiate(); - const { result } = await m.evaluate(); - assert.strictEqual(typeof result, 'object'); - assert.strictEqual(Object.getPrototypeOf(result), null); - assert.strictEqual(result.prop, 42); - assert.deepStrictEqual(Reflect.ownKeys(result), ['prop']); -} - -async function testInvalid() { - for (const invalidValue of [ - null, {}, 0, Symbol.iterator, [], 'string', false - ]) { - common.expectsError(() => { - new SourceTextModule('', { - initializeImportMeta: invalidValue - }); - }, { - code: 'ERR_INVALID_ARG_TYPE', - type: TypeError - }); - } -} - -(async () => { - await testBasic(); - await testInvalid(); -})(); diff --git a/test/parallel/test-vm-module-link.js b/test/parallel/test-vm-module-link.js deleted file mode 100644 index 20518c4054..0000000000 --- a/test/parallel/test-vm-module-link.js +++ /dev/null @@ -1,136 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules - -const common = require('../common'); - -const assert = require('assert'); -const { URL } = require('url'); - -const { SourceTextModule } = require('vm'); - -async function simple() { - const foo = new SourceTextModule('export default 5;'); - await foo.link(common.mustNotCall()); - - const bar = new SourceTextModule('import five from "foo"; five'); - - assert.deepStrictEqual(bar.dependencySpecifiers, ['foo']); - - await bar.link(common.mustCall((specifier, module) => { - assert.strictEqual(module, bar); - assert.strictEqual(specifier, 'foo'); - return foo; - })); - - bar.instantiate(); - - assert.strictEqual((await bar.evaluate()).result, 5); -} - -async function depth() { - const foo = new SourceTextModule('export default 5'); - await foo.link(common.mustNotCall()); - - async function getProxy(parentName, parentModule) { - const mod = new SourceTextModule(` - import ${parentName} from '${parentName}'; - export default ${parentName}; - `); - await mod.link(common.mustCall((specifier, module) => { - assert.strictEqual(module, mod); - assert.strictEqual(specifier, parentName); - return parentModule; - })); - return mod; - } - - const bar = await getProxy('foo', foo); - const baz = await getProxy('bar', bar); - const barz = await getProxy('baz', baz); - - barz.instantiate(); - await barz.evaluate(); - - assert.strictEqual(barz.namespace.default, 5); -} - -async function circular() { - const foo = new SourceTextModule(` - import getFoo from 'bar'; - export let foo = 42; - export default getFoo(); - `); - const bar = new SourceTextModule(` - import { foo } from 'foo'; - export default function getFoo() { - return foo; - } - `); - await foo.link(common.mustCall(async (fooSpecifier, fooModule) => { - assert.strictEqual(fooModule, foo); - assert.strictEqual(fooSpecifier, 'bar'); - await bar.link(common.mustCall((barSpecifier, barModule) => { - assert.strictEqual(barModule, bar); - assert.strictEqual(barSpecifier, 'foo'); - assert.strictEqual(foo.linkingStatus, 'linking'); - return foo; - })); - assert.strictEqual(bar.linkingStatus, 'linked'); - return bar; - })); - - foo.instantiate(); - await foo.evaluate(); - assert.strictEqual(foo.namespace.default, 42); -} - -async function circular2() { - const sourceMap = { - 'root': ` - import * as a from './a.mjs'; - import * as b from './b.mjs'; - if (!('fromA' in a)) - throw new Error(); - if (!('fromB' in a)) - throw new Error(); - if (!('fromA' in b)) - throw new Error(); - if (!('fromB' in b)) - throw new Error(); - `, - './a.mjs': ` - export * from './b.mjs'; - export var fromA; - `, - './b.mjs': ` - export * from './a.mjs'; - export var fromB; - ` - }; - const moduleMap = new Map(); - 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 SourceTextModule(sourceMap[specifier], { - url: new URL(specifier, 'file:///').href, - }); - moduleMap.set(specifier, mod); - return mod; - } - await rootModule.link(link); - rootModule.instantiate(); - await rootModule.evaluate(); -} - -const finished = common.mustCall(); - -(async function main() { - await simple(); - await depth(); - await circular(); - await circular2(); - finished(); -})(); diff --git a/test/parallel/test-vm-module-reevaluate.js b/test/parallel/test-vm-module-reevaluate.js deleted file mode 100644 index c3914f362f..0000000000 --- a/test/parallel/test-vm-module-reevaluate.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -// Flags: --experimental-vm-modules - -const common = require('../common'); - -const assert = require('assert'); - -const { SourceTextModule } = require('vm'); - -const finished = common.mustCall(); - -(async function main() { - { - const m = new SourceTextModule('1'); - await m.link(common.mustNotCall()); - m.instantiate(); - assert.strictEqual((await m.evaluate()).result, 1); - assert.strictEqual((await m.evaluate()).result, undefined); - assert.strictEqual((await m.evaluate()).result, undefined); - } - - { - const m = new SourceTextModule('throw new Error()'); - await m.link(common.mustNotCall()); - m.instantiate(); - - let threw = false; - try { - await m.evaluate(); - } catch (err) { - assert(err instanceof Error); - threw = true; - } - assert(threw); - - threw = false; - try { - await m.evaluate(); - } catch (err) { - assert(err instanceof Error); - threw = true; - } - assert(threw); - } - - finished(); -})();