Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions lib/internal/modules/esm/module_job.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ const isCommonJSGlobalLikeNotDefinedError = (errorMessage) =>
*/
const explainCommonJSGlobalLikeNotDefinedError = (e, url, hasTopLevelAwait) => {
if (e?.name === 'ReferenceError' &&
isCommonJSGlobalLikeNotDefinedError(e.message)) {
isCommonJSGlobalLikeNotDefinedError(e.message)) {

if (hasTopLevelAwait) {
e.message = `Cannot determine intended module format because both require() and top-level await are present. If the code is intended to be CommonJS, wrap await in an async function. If the code is intended to be an ES module, replace require() with import.`;
const globalName = StringPrototypeSplit(e.message, ' ')[0];
e.message = `Cannot determine intended module format because both ${globalName} and top-level await are present. If the code is intended to be CommonJS, wrap await in an async function. If the code is intended to be an ES module, replace ${globalName} with import.`;
e.code = 'ERR_AMBIGUOUS_MODULE_SYNTAX';
return;
}
Expand All @@ -96,9 +97,9 @@ const explainCommonJSGlobalLikeNotDefinedError = (e, url, hasTopLevelAwait) => {

const packageConfig =
StringPrototypeStartsWith(url, 'file://') &&
RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, url) !== null &&
require('internal/modules/package_json_reader')
.getPackageScopeConfig(url);
RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, url) !== null &&
require('internal/modules/package_json_reader')
.getPackageScopeConfig(url);
if (packageConfig.type === 'module') {
e.message +=
'\nThis file is being treated as an ES module because it has a ' +
Expand Down Expand Up @@ -191,7 +192,7 @@ class ModuleJob extends ModuleJobBase {
* @param {ModuleRequestType} requestType Type of the module request.
*/
constructor(loader, url, importAttributes = { __proto__: null }, moduleOrModulePromise,
phase = kEvaluationPhase, isMain, inspectBrk, requestType) {
phase = kEvaluationPhase, isMain, inspectBrk, requestType) {
super(loader, url, importAttributes, phase, isMain, inspectBrk);

// Expose the promise to the ModuleWrap directly for linking below.
Expand Down Expand Up @@ -308,8 +309,8 @@ class ModuleJob extends ModuleJobBase {
// stack trace originates in module_job, not the file itself. A hidden
// symbol with filename could be set in node_errors.cc to facilitate this.
if (!getSourceMapsSupport().enabled &&
StringPrototypeIncludes(e.message,
' does not provide an export named')) {
StringPrototypeIncludes(e.message,
' does not provide an export named')) {
const splitStack = StringPrototypeSplit(e.stack, '\n', 2);
const { 1: childSpecifier, 2: name } = RegExpPrototypeExec(
/module '(.*)' does not provide an export named '(.+)'/,
Expand All @@ -336,9 +337,8 @@ class ModuleJob extends ModuleJobBase {
` '${childSpecifier}' is a CommonJS module, which may not support` +
' all module.exports as named exports.\nCommonJS modules can ' +
'always be imported via the default export, for example using:' +
`\n\nimport pkg from '${childSpecifier}';\n${
destructuringAssignment ?
`const ${destructuringAssignment} = pkg;\n` : ''}`;
`\n\nimport pkg from '${childSpecifier}';\n${destructuringAssignment ?
`const ${destructuringAssignment} = pkg;\n` : ''}`;
const newStack = StringPrototypeSplit(e.stack, '\n');
newStack[3] = `SyntaxError: ${e.message}`;
e.stack = ArrayPrototypeJoin(newStack, '\n');
Expand Down Expand Up @@ -441,7 +441,7 @@ class ModuleJobSync extends ModuleJobBase {
* first line paused in the debugger (because --inspect-brk is passed).
*/
constructor(loader, url, importAttributes, moduleWrap, phase = kEvaluationPhase, isMain,
inspectBrk, requestType) {
inspectBrk, requestType) {
super(loader, url, importAttributes, phase, isMain, inspectBrk);

this.module = moduleWrap;
Expand Down Expand Up @@ -492,7 +492,7 @@ class ModuleJobSync extends ModuleJobBase {
}

assert.fail('Unexpected status of a module that is imported again after being required. ' +
`Status = ${status}`);
`Status = ${status}`);
}

runSync(parent) {
Expand Down
23 changes: 21 additions & 2 deletions test/es-module/test-esm-detect-ambiguous.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ describe('Module syntax detection', { concurrency: !process.env.TEST_PARALLEL },

assert.match(
stderr,
/ReferenceError: Cannot determine intended module format because both require\(\) and top-level await are present\. If the code is intended to be CommonJS, wrap await in an async function\. If the code is intended to be an ES module, replace require\(\) with import\./
/ReferenceError: Cannot determine intended module format because both require and top-level await are present\. If the code is intended to be CommonJS, wrap await in an async function\. If the code is intended to be an ES module, replace require with import\./
);
assert.strictEqual(stdout, '');
assert.strictEqual(code, 1);
Expand Down Expand Up @@ -440,7 +440,26 @@ describe('cjs & esm ambiguous syntax case', () => {

assert.match(
stderr,
/ReferenceError: Cannot determine intended module format because both require\(\) and top-level await are present\. If the code is intended to be CommonJS, wrap await in an async function\. If the code is intended to be an ES module, replace require\(\) with import\./
/ReferenceError: Cannot determine intended module format because both require and top-level await are present\. If the code is intended to be CommonJS, wrap await in an async function\. If the code is intended to be an ES module, replace require with import\./
);

assert.strictEqual(code, 1);
assert.strictEqual(signal, null);
});

it('should throw an ambiguous syntax error when using top-level await with module', async () => {
const { stderr, code, signal } = await spawnPromisified(
process.execPath,
[
'--input-type=module',
'--eval',
`await 1;\nmodule.exports = 1;`,
]
);

assert.match(
stderr,
/ReferenceError: Cannot determine intended module format because both module and top-level await are present\. If the code is intended to be CommonJS, wrap await in an async function\. If the code is intended to be an ES module, replace module with import\./
);

assert.strictEqual(code, 1);
Expand Down