Usage#
node \\[options\\] index.js' +
+ 'href="#usage-and-example" id="usage-and-example">#' +
+ '' +
+ '' +
'See also#
Check' +
+ 'href="#see-also" id="see-also">#
Check' +
'out alsothis guide
'
},
{
diff --git a/test/es-module/test-esm-data-urls.js b/test/es-module/test-esm-data-urls.js
index ba8bd4c95746c0..78cd01b4d55a12 100644
--- a/test/es-module/test-esm-data-urls.js
+++ b/test/es-module/test-esm-data-urls.js
@@ -99,7 +99,7 @@ function createBase64URL(mime, body) {
await import(plainESMURL);
common.mustNotCall()();
} catch (e) {
- assert.strictEqual(e.code, 'ERR_INVALID_MODULE_SPECIFIER');
+ assert.strictEqual(e.code, 'ERR_INVALID_URL');
}
}
{
diff --git a/test/es-module/test-esm-example-loader.js b/test/es-module/test-esm-example-loader.mjs
similarity index 100%
rename from test/es-module/test-esm-example-loader.js
rename to test/es-module/test-esm-example-loader.mjs
diff --git a/test/es-module/test-esm-get-source-loader.mjs b/test/es-module/test-esm-get-source-loader.mjs
deleted file mode 100644
index 66bac969a47d8f..00000000000000
--- a/test/es-module/test-esm-get-source-loader.mjs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Flags: --experimental-loader ./test/fixtures/es-module-loaders/get-source.mjs
-/* eslint-disable node-core/require-common-first, node-core/required-modules */
-import assert from 'assert';
-import { message } from '../fixtures/es-modules/message.mjs';
-
-assert.strictEqual(message, 'WOOHOO!');
diff --git a/test/es-module/test-esm-loader-get-format.mjs b/test/es-module/test-esm-loader-get-format.mjs
deleted file mode 100644
index 2a252439f91ce4..00000000000000
--- a/test/es-module/test-esm-loader-get-format.mjs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Flags: --experimental-loader ./test/fixtures/es-module-loaders/loader-get-format.mjs
-import { mustCall, mustNotCall } from '../common/index.mjs';
-import assert from 'assert';
-
-import('../fixtures/es-modules/package-type-module/extension.unknown')
-.then(
- mustCall((ns) => {
- assert.strictEqual(ns.default, 'unknown');
- }),
- // Do not use .catch; want exclusive or
- mustNotCall(() => {})
-);
diff --git a/test/es-module/test-esm-loader-modulemap.js b/test/es-module/test-esm-loader-modulemap.js
index 2d74cd385be52b..48443de4c270c6 100644
--- a/test/es-module/test-esm-loader-modulemap.js
+++ b/test/es-module/test-esm-loader-modulemap.js
@@ -7,7 +7,7 @@
require('../common');
const assert = require('assert');
-const { Loader } = require('internal/modules/esm/loader');
+const { ESMLoader } = require('internal/modules/esm/loader');
const ModuleMap = require('internal/modules/esm/module_map');
const ModuleJob = require('internal/modules/esm/module_job');
const createDynamicModule = require(
@@ -15,7 +15,7 @@ const createDynamicModule = require(
const stubModuleUrl = new URL('file://tmp/test');
const stubModule = createDynamicModule(['default'], stubModuleUrl);
-const loader = new Loader();
+const loader = new ESMLoader();
const moduleMap = new ModuleMap();
const moduleJob = new ModuleJob(loader, stubModule.module,
() => new Promise(() => {}));
diff --git a/test/es-module/test-esm-loader-stringify-text.mjs b/test/es-module/test-esm-loader-stringify-text.mjs
index ed9bd5069ebf1d..e66da9491b4cd2 100644
--- a/test/es-module/test-esm-loader-stringify-text.mjs
+++ b/test/es-module/test-esm-loader-stringify-text.mjs
@@ -12,6 +12,34 @@ import('test:ArrayBuffer').then(
mustCall(),
mustNotCall('Should accept ArrayBuffers'),
);
+import('test:BigInt64Array').then(
+ mustCall(),
+ mustNotCall('Should accept BigInt64Array'),
+);
+import('test:BigUint64Array').then(
+ mustCall(),
+ mustNotCall('Should accept BigUint64Array'),
+);
+import('test:Float32Array').then(
+ mustCall(),
+ mustNotCall('Should accept Float32Array'),
+);
+import('test:Float64Array').then(
+ mustCall(),
+ mustNotCall('Should accept Float64Array'),
+);
+import('test:Int8Array').then(
+ mustCall(),
+ mustNotCall('Should accept Int8Array'),
+);
+import('test:Int16Array').then(
+ mustCall(),
+ mustNotCall('Should accept Int16Array'),
+);
+import('test:Int32Array').then(
+ mustCall(),
+ mustNotCall('Should accept Int32Array'),
+);
import('test:null').then(
mustNotCall('Should not accept null'),
mustCall((e) => {
@@ -38,6 +66,18 @@ import('test:String').then(
assert.strictEqual(e.code, 'ERR_INVALID_RETURN_PROPERTY_VALUE');
})
);
+import('test:Uint8ClampedArray').then(
+ mustCall(),
+ mustNotCall('Should accept Uint8ClampedArray'),
+);
+import('test:Uint16Array').then(
+ mustCall(),
+ mustNotCall('Should accept Uint16Array'),
+);
+import('test:Uint32Array').then(
+ mustCall(),
+ mustNotCall('Should accept Uint32Array'),
+);
import('test:Uint8Array').then(
mustCall(),
mustNotCall('Should accept Uint8Arrays'),
diff --git a/test/es-module/test-esm-loader.mjs b/test/es-module/test-esm-loader.mjs
new file mode 100644
index 00000000000000..e19a38cc4231b0
--- /dev/null
+++ b/test/es-module/test-esm-loader.mjs
@@ -0,0 +1,83 @@
+// Flags: --experimental-loader ./test/fixtures/es-module-loaders/hooks-custom.mjs
+import '../common/index.mjs';
+import assert from 'assert';
+
+
+await assert.rejects(
+ import('nonexistent/file.mjs'),
+ { code: 'ERR_MODULE_NOT_FOUND' },
+);
+
+await assert.rejects(
+ import('../fixtures/es-modules/file.unknown'),
+ { code: 'ERR_UNKNOWN_FILE_EXTENSION' },
+);
+
+await assert.rejects(
+ import('esmHook/badReturnVal.mjs'),
+ { code: 'ERR_INVALID_RETURN_VALUE' },
+);
+
+// Nullish values are allowed; booleans are not
+await assert.rejects(
+ import('esmHook/format.false'),
+ { code: 'ERR_INVALID_RETURN_PROPERTY_VALUE' },
+);
+await assert.rejects(
+ import('esmHook/format.true'),
+ { code: 'ERR_INVALID_RETURN_PROPERTY_VALUE' },
+);
+
+await assert.rejects(
+ import('esmHook/badReturnFormatVal.mjs'),
+ { code: 'ERR_INVALID_RETURN_PROPERTY_VALUE' },
+);
+
+await assert.rejects(
+ import('esmHook/unsupportedReturnFormatVal.mjs'),
+ { code: 'ERR_UNKNOWN_MODULE_FORMAT' },
+);
+
+await assert.rejects(
+ import('esmHook/badReturnSourceVal.mjs'),
+ { code: 'ERR_INVALID_RETURN_PROPERTY_VALUE' },
+);
+
+await import('../fixtures/es-module-loaders/js-as-esm.js')
+.then((parsedModule) => {
+ assert.strictEqual(typeof parsedModule, 'object');
+ assert.strictEqual(parsedModule.namedExport, 'named-export');
+});
+
+// The custom loader tells node .ext files are MJS
+await import('../fixtures/es-modules/file.ext')
+.then((parsedModule) => {
+ assert.strictEqual(typeof parsedModule, 'object');
+ const { default: defaultExport } = parsedModule;
+ assert.strictEqual(typeof defaultExport, 'function');
+ assert.strictEqual(defaultExport.name, 'iAmReal');
+ assert.strictEqual(defaultExport(), true);
+});
+
+// The custom loader's resolve hook predetermines the format
+await import('esmHook/preknownFormat.pre')
+.then((parsedModule) => {
+ assert.strictEqual(typeof parsedModule, 'object');
+ assert.strictEqual(parsedModule.default, 'hello world');
+});
+
+// The custom loader provides source even though file does not actually exist
+await import('esmHook/virtual.mjs')
+.then((parsedModule) => {
+ assert.strictEqual(typeof parsedModule, 'object');
+ assert.strictEqual(typeof parsedModule.default, 'undefined');
+ assert.strictEqual(parsedModule.message, 'WOOHOO!');
+});
+
+// Ensure custom loaders have separate context from userland
+// hooks-custom.mjs also increments count (which starts at 0)
+// if both share context, count here would be 2
+await import('../fixtures/es-modules/stateful.mjs')
+.then(({ default: count }) => {
+ assert.strictEqual(count(), 1);
+});
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 39b11e02739d4b..00000000000000
--- a/test/es-module/test-esm-resolve-hook.mjs
+++ /dev/null
@@ -1,8 +0,0 @@
-// Flags: --experimental-loader ./test/fixtures/es-module-loaders/js-loader.mjs
-/* eslint-disable node-core/require-common-first, 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-transform-source-loader.mjs b/test/es-module/test-esm-transform-source-loader.mjs
deleted file mode 100644
index e6d4affea495de..00000000000000
--- a/test/es-module/test-esm-transform-source-loader.mjs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Flags: --experimental-loader ./test/fixtures/es-module-loaders/transform-source.mjs
-/* eslint-disable node-core/require-common-first, node-core/required-modules */
-import assert from 'assert';
-import { message } from '../fixtures/es-modules/message.mjs';
-
-assert.strictEqual(message, 'A MESSAGE');
diff --git a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs
index f06e9e90ff97c3..f206d7635b3f63 100644
--- a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs
+++ b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs
@@ -2,7 +2,7 @@ import module from 'module';
const GET_BUILTIN = `$__get_builtin_hole_${Date.now()}`;
-export function getGlobalPreloadCode() {
+export function globalPreload() {
return `Object.defineProperty(globalThis, ${JSON.stringify(GET_BUILTIN)}, {
value: (builtinName) => {
return getBuiltin(builtinName);
@@ -13,8 +13,9 @@ export function getGlobalPreloadCode() {
`;
}
-export function resolve(specifier, context, defaultResolve) {
- const def = defaultResolve(specifier, context);
+export function resolve(specifier, context, next) {
+ const def = next(specifier, context);
+
if (def.url.startsWith('node:')) {
return {
url: `custom-${def.url}`,
@@ -23,7 +24,7 @@ export function resolve(specifier, context, defaultResolve) {
return def;
}
-export function getSource(url, context, defaultGetSource) {
+export function load(url, context, next) {
if (url.startsWith('custom-node:')) {
const urlObj = new URL(url);
return {
@@ -31,14 +32,7 @@ export function getSource(url, context, defaultGetSource) {
format: 'module',
};
}
- return defaultGetSource(url, context);
-}
-
-export function getFormat(url, context, defaultGetFormat) {
- if (url.startsWith('custom-node:')) {
- return { format: 'module' };
- }
- return defaultGetFormat(url, context, defaultGetFormat);
+ return next(url, context);
}
function generateBuiltinModule(builtinName) {
diff --git a/test/fixtures/es-module-loaders/get-source.mjs b/test/fixtures/es-module-loaders/get-source.mjs
deleted file mode 100644
index e5a9c65201aa28..00000000000000
--- a/test/fixtures/es-module-loaders/get-source.mjs
+++ /dev/null
@@ -1,10 +0,0 @@
-export async function getSource(url, { format }, defaultGetSource) {
- if (url.endsWith('fixtures/es-modules/message.mjs')) {
- // Oh, I’ve got that one in my cache!
- return {
- source: `export const message = 'Woohoo!'.toUpperCase();`
- }
- } else {
- return defaultGetSource(url, {format}, defaultGetSource);
- }
-}
diff --git a/test/fixtures/es-module-loaders/hooks-custom.mjs b/test/fixtures/es-module-loaders/hooks-custom.mjs
new file mode 100644
index 00000000000000..59f49ff9e60c13
--- /dev/null
+++ b/test/fixtures/es-module-loaders/hooks-custom.mjs
@@ -0,0 +1,69 @@
+import count from '../es-modules/stateful.mjs';
+
+
+// Arbitrary instance of manipulating a module's internal state
+// used to assert node-land and user-land have different contexts
+count();
+
+/**
+ * @param {string} url A fully resolved file url.
+ * @param {object} context Additional info.
+ * @param {function} next for now, next is defaultLoad a wrapper for
+ * defaultGetFormat + defaultGetSource
+ * @returns {{ format: string, source: (string|SharedArrayBuffer|Uint8Array) }}
+ */
+export function load(url, context, next) {
+ // Load all .js files as ESM, regardless of package scope
+ if (url.endsWith('.js')) return next(url, {
+ ...context,
+ format: 'module',
+ });
+
+ if (url.endsWith('.ext')) return next(url, {
+ ...context,
+ format: 'module',
+ });
+
+ if (url === 'esmHook/badReturnVal.mjs') return 'export function returnShouldBeObject() {}';
+
+ if (url === 'esmHook/badReturnFormatVal.mjs') return {
+ format: Array(0),
+ source: '',
+ }
+ if (url === 'esmHook/unsupportedReturnFormatVal.mjs') return {
+ format: 'foo', // Not one of the allowable inputs: no translator named 'foo'
+ source: '',
+ }
+
+ if (url === 'esmHook/badReturnSourceVal.mjs') return {
+ format: 'module',
+ source: Array(0),
+ }
+
+ if (url === 'esmHook/preknownFormat.pre') return {
+ format: context.format,
+ source: `const msg = 'hello world'; export default msg;`
+ };
+
+ if (url === 'esmHook/virtual.mjs') return {
+ format: 'module',
+ source: `export const message = 'Woohoo!'.toUpperCase();`,
+ };
+
+ return next(url, context, next);
+}
+
+export function resolve(specifier, context, next) {
+ let format = '';
+
+ if (specifier === 'esmHook/format.false') format = false;
+ if (specifier === 'esmHook/format.true') format = true;
+ if (specifier === 'esmHook/preknownFormat.pre') format = 'module';
+
+ if (specifier.startsWith('esmHook')) return {
+ format,
+ url: specifier,
+ };
+
+ return next(specifier, context, next);
+}
diff --git a/test/fixtures/es-module-loaders/hooks-obsolete.mjs b/test/fixtures/es-module-loaders/hooks-obsolete.mjs
new file mode 100644
index 00000000000000..9d12251923d7e9
--- /dev/null
+++ b/test/fixtures/es-module-loaders/hooks-obsolete.mjs
@@ -0,0 +1,22 @@
+export function dynamicInstantiate() {}
+export function getFormat() {}
+export function getSource() {}
+export function transformSource() {}
+
+
+export function load(url, context, next) {
+ if (url === 'whatever') return {
+ format: 'module',
+ source: '',
+ };
+
+ return next(url, context, next);
+}
+
+export function resolve(specifier, context, next) {
+ if (specifier === 'whatever') return {
+ url: specifier,
+ };
+
+ return next(specifier, context, next);
+}
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 2f79475e77e269..00000000000000
--- a/test/fixtures/es-module-loaders/js-loader.mjs
+++ /dev/null
@@ -1,9 +0,0 @@
-export function getFormat(url, context, defaultGetFormat) {
- // Load all .js files as ESM, regardless of package scope
- if (url.endsWith('.js')) {
- return {
- format: 'module'
- }
- }
- return defaultGetFormat(url, context, defaultGetFormat);
-}
diff --git a/test/fixtures/es-module-loaders/loader-invalid-format.mjs b/test/fixtures/es-module-loaders/loader-invalid-format.mjs
index 55ae1cec8ee926..fc1b84658b76de 100644
--- a/test/fixtures/es-module-loaders/loader-invalid-format.mjs
+++ b/test/fixtures/es-module-loaders/loader-invalid-format.mjs
@@ -7,11 +7,12 @@ export async function resolve(specifier, { parentURL }, defaultResolve) {
return defaultResolve(specifier, {parentURL}, defaultResolve);
}
-export function getFormat(url, context, defaultGetFormat) {
+export async function load(url, context, next) {
if (url === 'file:///asdf') {
return {
- format: 'esm'
+ format: 'esm',
+ source: '',
}
}
- return defaultGetFormat(url, context, defaultGetFormat);
+ return next(url, context, next);
}
diff --git a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs
index 4ef089fd6eb3fd..1063f8dfd65f2f 100644
--- a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs
+++ b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs
@@ -1,17 +1,7 @@
-export async function resolve(specifier, { parentURL }, defaultResolve) {
- if (specifier === 'unknown-builtin-module') {
- return {
- url: 'node:unknown-builtin-module'
- };
- }
- return defaultResolve(specifier, {parentURL}, defaultResolve);
-}
+export function resolve(specifier, context, next) {
+ if (specifier === 'unknown-builtin-module') return {
+ url: 'node:unknown-builtin-module'
+ };
-export async function getFormat(url, context, defaultGetFormat) {
- if (url === 'node:unknown-builtin-module') {
- return {
- format: 'builtin'
- };
- }
- return defaultGetFormat(url, context, defaultGetFormat);
+ return next(specifier, context, next);
}
diff --git a/test/fixtures/es-module-loaders/string-sources.mjs b/test/fixtures/es-module-loaders/string-sources.mjs
index 3133231208ce1e..180a356bc81478 100644
--- a/test/fixtures/es-module-loaders/string-sources.mjs
+++ b/test/fixtures/es-module-loaders/string-sources.mjs
@@ -2,29 +2,37 @@ const SOURCES = {
__proto__: null,
'test:Array': ['1', '2'], // both `1,2` and `12` are valid ESM
'test:ArrayBuffer': new ArrayBuffer(0),
+ 'test:BigInt64Array': new BigInt64Array(0),
+ 'test:BigUint64Array': new BigUint64Array(0),
+ 'test:Float32Array': new Float32Array(0),
+ 'test:Float64Array': new Float64Array(0),
+ 'test:Int8Array': new Int8Array(0),
+ 'test:Int16Array': new Int16Array(0),
+ 'test:Int32Array': new Int32Array(0),
'test:null': null,
'test:Object': {},
'test:SharedArrayBuffer': new SharedArrayBuffer(0),
'test:string': '',
'test:String': new String(''),
'test:Uint8Array': new Uint8Array(0),
+ 'test:Uint8ClampedArray': new Uint8ClampedArray(0),
+ 'test:Uint16Array': new Uint16Array(0),
+ 'test:Uint32Array': new Uint32Array(0),
'test:undefined': undefined,
}
-export function resolve(specifier, context, defaultFn) {
+export function resolve(specifier, context, next) {
if (specifier.startsWith('test:')) {
return { url: specifier };
}
- return defaultFn(specifier, context);
+ return next(specifier, context);
}
-export function getFormat(href, context, defaultFn) {
+
+export function load(href, context, next) {
if (href.startsWith('test:')) {
- return { format: 'module' };
+ return {
+ format: 'module',
+ source: SOURCES[href],
+ };
}
- return defaultFn(href, context);
-}
-export function getSource(href, context, defaultFn) {
- if (href.startsWith('test:')) {
- return { source: SOURCES[href] };
- }
- return defaultFn(href, context);
+ return next(href, context);
}
diff --git a/test/fixtures/es-module-loaders/transform-source.mjs b/test/fixtures/es-module-loaders/transform-source.mjs
deleted file mode 100644
index 25d983b64e62ca..00000000000000
--- a/test/fixtures/es-module-loaders/transform-source.mjs
+++ /dev/null
@@ -1,14 +0,0 @@
-export async function transformSource(
- source, { url, format }, defaultTransformSource) {
- if (format === 'module') {
- if (typeof source !== 'string') {
- source = new TextDecoder().decode(source);
- }
- return {
- source: source.replace(`'A message';`, `'A message'.toUpperCase();`)
- };
- } else { // source could be a buffer, e.g. for WASM
- return defaultTransformSource(
- source, {url, format}, defaultTransformSource);
- }
-}
diff --git a/test/fixtures/es-modules/file.ext b/test/fixtures/es-modules/file.ext
new file mode 100644
index 00000000000000..db07b384e169d8
--- /dev/null
+++ b/test/fixtures/es-modules/file.ext
@@ -0,0 +1,3 @@
+// fixtures/es-module-loader.mjs tells node to treat this file like ESM
+
+export default function iAmReal() { return true };
diff --git a/test/fixtures/es-modules/file.unknown b/test/fixtures/es-modules/file.unknown
new file mode 100644
index 00000000000000..e69de29bb2d1d6
diff --git a/test/fixtures/es-modules/stateful.mjs b/test/fixtures/es-modules/stateful.mjs
new file mode 100644
index 00000000000000..745669c462e60d
--- /dev/null
+++ b/test/fixtures/es-modules/stateful.mjs
@@ -0,0 +1,5 @@
+let counter = 0;
+
+export default function count() {
+ return ++counter;
+}
diff --git a/test/message/esm_display_syntax_error.mjs b/test/message/esm_display_syntax_error.mjs
deleted file mode 100644
index 0b9a30c2d054f7..00000000000000
--- a/test/message/esm_display_syntax_error.mjs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Flags: --no-harmony-top-level-await
-
-'use strict';
-await async () => 0;
diff --git a/test/message/esm_display_syntax_error.out b/test/message/esm_display_syntax_error.out
deleted file mode 100644
index f1b7ff4e2290ee..00000000000000
--- a/test/message/esm_display_syntax_error.out
+++ /dev/null
@@ -1,7 +0,0 @@
-file:///*/test/message/esm_display_syntax_error.mjs:4
-await async () => 0;
-^^^^^
-
-SyntaxError: Unexpected reserved word
- at Loader.moduleStrategy (node:internal/modules/esm/translators:*:*)
- at async link (node:internal/modules/esm/module_job:*:*)
diff --git a/test/message/esm_display_syntax_error_import.out b/test/message/esm_display_syntax_error_import.out
index ad906af431bf95..62607b93c7c593 100644
--- a/test/message/esm_display_syntax_error_import.out
+++ b/test/message/esm_display_syntax_error_import.out
@@ -4,6 +4,7 @@ file:///*/test/message/esm_display_syntax_error_import.mjs:5
SyntaxError: The requested module '../fixtures/es-module-loaders/module-named-exports.mjs' does not provide an export named 'notfound'
at ModuleJob._instantiate (node:internal/modules/esm/module_job:*:*)
at async ModuleJob.run (node:internal/modules/esm/module_job:*:*)
- at async Loader.import (node:internal/modules/esm/loader:*:*)
- at async Object.loadESM (node:internal/process/esm_loader:*:*)
+ at async Promise.all (index 0)
+ at async ESMLoader.import (node:internal/modules/esm/loader:*:*)
+ at async loadESM (node:internal/process/esm_loader:*:*)
at async handleMainPromise (node:internal/modules/run_main:*:*)
diff --git a/test/message/esm_display_syntax_error_import_module.out b/test/message/esm_display_syntax_error_import_module.out
index 60a208d534af40..0ecb87a952e891 100644
--- a/test/message/esm_display_syntax_error_import_module.out
+++ b/test/message/esm_display_syntax_error_import_module.out
@@ -4,6 +4,7 @@ import { foo, notfound } from './module-named-exports.mjs';
SyntaxError: The requested module './module-named-exports.mjs' does not provide an export named 'notfound'
at ModuleJob._instantiate (node:internal/modules/esm/module_job:*:*)
at async ModuleJob.run (node:internal/modules/esm/module_job:*:*)
- at async Loader.import (node:internal/modules/esm/loader:*:*)
- at async Object.loadESM (node:internal/process/esm_loader:*:*)
+ at async Promise.all (index 0)
+ at async ESMLoader.import (node:internal/modules/esm/loader:*:*)
+ at async loadESM (node:internal/process/esm_loader:*:*)
at async handleMainPromise (node:internal/modules/run_main:*:*)
diff --git a/test/message/esm_display_syntax_error_module.out b/test/message/esm_display_syntax_error_module.out
index fc0912a96c0d26..26dbf480239b9c 100644
--- a/test/message/esm_display_syntax_error_module.out
+++ b/test/message/esm_display_syntax_error_module.out
@@ -3,4 +3,5 @@ await async () => 0;
^^^^^^^^^^^^^
SyntaxError: Malformed arrow function parameter list
- at Loader.moduleStrategy (node:internal/modules/esm/translators:*:*)
+ at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:*:*)
+ at ESMLoader.moduleProvider (node:internal/modules/esm/loader:*:*)
diff --git a/test/message/esm_loader_not_found.out b/test/message/esm_loader_not_found.out
index 61b1623cdf176f..21d7ab3e44f205 100644
--- a/test/message/esm_loader_not_found.out
+++ b/test/message/esm_loader_not_found.out
@@ -7,12 +7,12 @@ Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'i-dont-exist' imported from *
at new NodeError (node:internal/errors:*:*)
at packageResolve (node:internal/modules/esm/resolve:*:*)
at moduleResolve (node:internal/modules/esm/resolve:*:*)
- at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:*:*)
- at Loader.resolve (node:internal/modules/esm/loader:*:*)
- at Loader.getModuleJob (node:internal/modules/esm/loader:*:*)
- at Loader.import (node:internal/modules/esm/loader:*:*)
- at node:internal/process/esm_loader:*:*
+ at defaultResolve (node:internal/modules/esm/resolve:*:*)
+ at ESMLoader.resolve (node:internal/modules/esm/loader:*:*)
+ at ESMLoader.getModuleJob (node:internal/modules/esm/loader:*:*)
+ at ESMLoader.import (node:internal/modules/esm/loader:*:*)
at initializeLoader (node:internal/process/esm_loader:*:*)
- at Object.loadESM (node:internal/process/esm_loader:*:*) {
+ at loadESM (node:internal/process/esm_loader:*:*)
+ at runMainESM (node:internal/modules/run_main:*:*) {
code: 'ERR_MODULE_NOT_FOUND'
}
diff --git a/test/message/esm_loader_not_found_cjs_hint_bare.out b/test/message/esm_loader_not_found_cjs_hint_bare.out
index aaeed40ed60013..4a255ebf0b6972 100644
--- a/test/message/esm_loader_not_found_cjs_hint_bare.out
+++ b/test/message/esm_loader_not_found_cjs_hint_bare.out
@@ -7,9 +7,9 @@ Did you mean to import some_module/obj.js?
at new NodeError (node:internal/errors:*:*)
at finalizeResolution (node:internal/modules/esm/resolve:*:*)
at moduleResolve (node:internal/modules/esm/resolve:*:*)
- at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:*:*)
- at Loader.resolve (node:internal/modules/esm/loader:*:*)
- at Loader.getModuleJob (node:internal/modules/esm/loader:*:*)
+ at defaultResolve (node:internal/modules/esm/resolve:*:*)
+ at ESMLoader.resolve (node:internal/modules/esm/loader:*:*)
+ at ESMLoader.getModuleJob (node:internal/modules/esm/loader:*:*)
at ModuleWrap. (node:internal/modules/esm/module_job:*:*)
at link (node:internal/modules/esm/module_job:*:*) {
code: 'ERR_MODULE_NOT_FOUND'
diff --git a/test/message/esm_loader_not_found_cjs_hint_relative.out b/test/message/esm_loader_not_found_cjs_hint_relative.out
index 89b8d56133ce3a..817b4aa0724e8e 100644
--- a/test/message/esm_loader_not_found_cjs_hint_relative.out
+++ b/test/message/esm_loader_not_found_cjs_hint_relative.out
@@ -9,12 +9,12 @@ Did you mean to import ./test/common/fixtures.js?
at new NodeError (node:internal/errors:*:*)
at finalizeResolution (node:internal/modules/esm/resolve:*:*)
at moduleResolve (node:internal/modules/esm/resolve:*:*)
- at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:*:*)
- at Loader.resolve (node:internal/modules/esm/loader:*:*)
- at Loader.getModuleJob (node:internal/modules/esm/loader:*:*)
- at Loader.import (node:internal/modules/esm/loader:*:*)
- at node:internal/process/esm_loader:*:*
+ at defaultResolve (node:internal/modules/esm/resolve:*:*)
+ at ESMLoader.resolve (node:internal/modules/esm/loader:*:*)
+ at ESMLoader.getModuleJob (node:internal/modules/esm/loader:*:*)
+ at ESMLoader.import (node:internal/modules/esm/loader:*:*)
at initializeLoader (node:internal/process/esm_loader:*:*)
- at Object.loadESM (node:internal/process/esm_loader:*:*) {
+ at loadESM (node:internal/process/esm_loader:*:*)
+ at runMainESM (node:internal/modules/run_main:*:*) {
code: 'ERR_MODULE_NOT_FOUND'
}
diff --git a/test/message/esm_loader_syntax_error.out b/test/message/esm_loader_syntax_error.out
index de6014add667bc..fb8a2030828a9d 100644
--- a/test/message/esm_loader_syntax_error.out
+++ b/test/message/esm_loader_syntax_error.out
@@ -5,5 +5,6 @@ await async () => 0;
^^^^^^^^^^^^^
SyntaxError: Malformed arrow function parameter list
- at Loader.moduleStrategy (node:internal/modules/esm/translators:*:*)
+ at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:*:*)
+ at ESMLoader.moduleProvider (node:internal/modules/esm/loader:*:*)
at async link (node:internal/modules/esm/module_job:*:*)
diff --git a/test/message/test-esm-loader-obsolete-hooks.mjs b/test/message/test-esm-loader-obsolete-hooks.mjs
new file mode 100644
index 00000000000000..9a6a9c48057b40
--- /dev/null
+++ b/test/message/test-esm-loader-obsolete-hooks.mjs
@@ -0,0 +1,4 @@
+// Flags: --no-warnings --throw-deprecation --experimental-loader ./test/fixtures/es-module-loaders/hooks-obsolete.mjs
+/* eslint-disable node-core/require-common-first, node-core/required-modules */
+
+await import('whatever');
diff --git a/test/message/test-esm-loader-obsolete-hooks.out b/test/message/test-esm-loader-obsolete-hooks.out
new file mode 100644
index 00000000000000..5099c9c8d8610b
--- /dev/null
+++ b/test/message/test-esm-loader-obsolete-hooks.out
@@ -0,0 +1,10 @@
+node:internal/process/warning:*
+ throw warning;
+ ^
+
+DeprecationWarning: Obsolete loader hook(s) supplied and will be ignored: dynamicInstantiate, getFormat, getSource, transformSource
+ at Function.pluckHooks (node:internal/modules/esm/loader:*:*)
+ at ESMLoader.addCustomLoaders (node:internal/modules/esm/loader:*:*)
+ at initializeLoader (node:internal/process/esm_loader:*:*)
+ at async loadESM (node:internal/process/esm_loader:*:*)
+ at async handleMainPromise (node:internal/modules/run_main:*:*)
diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js
index bb77c7201b21d2..b68a262103c7e8 100644
--- a/test/parallel/test-bootstrap-modules.js
+++ b/test/parallel/test-bootstrap-modules.js
@@ -72,10 +72,10 @@ const expectedModules = new Set([
'NativeModule internal/modules/esm/get_format',
'NativeModule internal/modules/esm/get_source',
'NativeModule internal/modules/esm/loader',
+ 'NativeModule internal/modules/esm/load',
'NativeModule internal/modules/esm/module_job',
'NativeModule internal/modules/esm/module_map',
'NativeModule internal/modules/esm/resolve',
- 'NativeModule internal/modules/esm/transform_source',
'NativeModule internal/modules/esm/translators',
'NativeModule internal/process/esm_loader',
'NativeModule internal/options',
diff --git a/test/parallel/test-no-harmony-top-level-await.mjs b/test/parallel/test-no-harmony-top-level-await.mjs
deleted file mode 100644
index 5805af0e5ee265..00000000000000
--- a/test/parallel/test-no-harmony-top-level-await.mjs
+++ /dev/null
@@ -1,8 +0,0 @@
-// Flags: --no-harmony-top-level-await
-
-import {
- mustCall,
-} from '../common/index.mjs';
-
-process.on('unhandledRejection', mustCall());
-Promise.reject(new Error('should not be fatal error'));
diff --git a/test/parallel/test-webcrypto-ed25519-ed448.js b/test/parallel/test-webcrypto-ed25519-ed448.js
index 8abca247738621..b18f3f9d3b4d44 100644
--- a/test/parallel/test-webcrypto-ed25519-ed448.js
+++ b/test/parallel/test-webcrypto-ed25519-ed448.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
@@ -11,6 +12,9 @@ const {
webcrypto: { subtle }
} = require('crypto');
+const { internalBinding } = require('internal/test/binding');
+const { DOMException } = internalBinding('messaging');
+
async function generateKey(namedCurve) {
return subtle.generateKey(
{
@@ -429,3 +433,53 @@ assert.rejects(
}
}
}
+
+{
+ // See: https://github.com/nodejs/node/pull/40300
+ for (const namedCurve of ['NODE-ED25519', 'NODE-ED448']) {
+ assert.rejects(
+ (async () => {
+ const { privateKey } = await generateKey(namedCurve);
+ return subtle.sign(
+ {
+ name: namedCurve,
+ hash: 'SHA-256'
+ },
+ privateKey,
+ Buffer.from('abc')
+ );
+ })(),
+ (err) => {
+ assert.strictEqual(err.message, `Hash is not permitted for ${namedCurve}`);
+ assert(err instanceof DOMException);
+ return true;
+ }).then(common.mustCall());
+
+ assert.rejects(
+ (async () => {
+ const { publicKey, privateKey } = await generateKey(namedCurve);
+ const signature = await subtle.sign(
+ {
+ name: namedCurve,
+ },
+ privateKey,
+ Buffer.from('abc')
+ ).catch(common.mustNotCall());
+
+ return subtle.verify(
+ {
+ name: namedCurve,
+ hash: 'SHA-256',
+ },
+ publicKey,
+ signature,
+ Buffer.from('abc')
+ );
+ })(),
+ (err) => {
+ assert.strictEqual(err.message, `Hash is not permitted for ${namedCurve}`);
+ assert(err instanceof DOMException);
+ return true;
+ }).then(common.mustCall());
+ }
+}
diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json
index ab89356f82c805..812f7a9ffce237 100644
--- a/test/wpt/status/url.json
+++ b/test/wpt/status/url.json
@@ -1,7 +1,6 @@
{
"toascii.window.js": {
- "requires": ["small-icu"],
- "skip": "TODO: port from .window.js"
+ "requires": ["small-icu"]
},
"percent-encoding.window.js": {
"requires": ["small-icu"],
@@ -13,9 +12,6 @@
"urlencoded-parser.any.js": {
"fail": "missing Request and Response"
},
- "idlharness.any.js": {
- "fail": "getter/setter names are wrong, etc."
- },
"urlsearchparams-constructor.any.js": {
"fail": "FormData is not defined"
},
@@ -30,5 +26,8 @@
},
"url-setters-a-area.window.js": {
"skip": "already tested in url-setters.any.js"
+ },
+ "idlharness.any.js": {
+ "fail": "Fixed in a semver-major change: https://github.com/nodejs/node/pull/39752"
}
}
diff --git a/test/wpt/test-url.js b/test/wpt/test-url.js
index 4652bfd880cd76..f64189ea3f66d6 100644
--- a/test/wpt/test-url.js
+++ b/test/wpt/test-url.js
@@ -15,4 +15,13 @@ runner.setInitScript(`
global.DOMException = DOMException;
`);
+runner.setScriptModifier((obj) => {
+ if (obj.filename.includes('toascii.window.js')) {
+ // `a` and `area` in `toascii.window.js` is for testing `Element` that
+ // created via `document.createElement`. So we need to ignore them and just
+ // test `URL`.
+ obj.code = obj.code.replace(/\["url", "a", "area"\]/, '[ "url" ]');
+ }
+});
+runner.pretendGlobalThisAs('Window');
runner.runJsTests();
diff --git a/tools/code_cache/mkcodecache.cc b/tools/code_cache/mkcodecache.cc
index 3a1d0ee50e5078..9a0127184372bc 100644
--- a/tools/code_cache/mkcodecache.cc
+++ b/tools/code_cache/mkcodecache.cc
@@ -28,7 +28,6 @@ int main(int argc, char* argv[]) {
#endif // _WIN32
v8::V8::SetFlagsFromString("--random_seed=42");
- v8::V8::SetFlagsFromString("--harmony-top-level-await");
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " \n";
diff --git a/tools/doc/allhtml.mjs b/tools/doc/allhtml.mjs
index 905ea5d3dd6c6f..8c2135dc8cbc8f 100644
--- a/tools/doc/allhtml.mjs
+++ b/tools/doc/allhtml.mjs
@@ -31,13 +31,31 @@ for (const link of toc.match(//g)) {
// Split the doc.
const match = /(<\/ul>\s*)?<\/\w+>\s*<\w+ id="apicontent">/.exec(data);
+ // Get module name
+ const moduleName = href.replace(/\.html$/, '');
+
contents += data.slice(0, match.index)
- .replace(/[\s\S]*?id="toc"[^>]*>\s*<\w+>.*?<\/\w+>\s*(\s*)?/, '');
+ .replace(/[\s\S]*?id="toc"[^>]*>\s*<\w+>.*?<\/\w+>\s*(
')
- .replace(/