Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
31 changes: 24 additions & 7 deletions lib/internal/modules/esm/module_job.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

const {
Array,
ArrayPrototypeFind,
ArrayPrototypeJoin,
ArrayPrototypeSome,
FunctionPrototype,
ObjectSetPrototypeOf,
PromisePrototypeThen,
Expand Down Expand Up @@ -61,11 +61,11 @@ const CJSGlobalLike = [
'__filename',
'__dirname',
];
const isCommonJSGlobalLikeNotDefinedError = (errorMessage) =>
ArrayPrototypeSome(
const getUndefinedCJSGlobalLike = (errorMessage) =>
ArrayPrototypeFind(
CJSGlobalLike,
(globalLike) => errorMessage === `${globalLike} is not defined`,
);
) ?? null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not useful, it it?

Suggested change
) ?? null;
);

Copy link
Contributor Author

@mag123c mag123c Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.. It's redundant since ArrayPrototypeFind returns undefined when not found.
Thanks for review. I applied it



/**
Expand All @@ -75,11 +75,28 @@ const isCommonJSGlobalLikeNotDefinedError = (errorMessage) =>
* @returns {void}
*/
const explainCommonJSGlobalLikeNotDefinedError = (e, url, hasTopLevelAwait) => {
if (e?.name === 'ReferenceError' &&
isCommonJSGlobalLikeNotDefinedError(e.message)) {
const undefinedGlobal = getUndefinedCJSGlobalLike(e?.message);
if (e?.name === 'ReferenceError' && undefinedGlobal !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const undefinedGlobal = getUndefinedCJSGlobalLike(e?.message);
if (e?.name === 'ReferenceError' && undefinedGlobal !== null) {
const notDefinedGlobalLike = e?.name === 'ReferenceError' && findCommonJSGlobalLikeNotDefinedError(e.message);
if (notDefinedGlobalLike) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt of this suggestion? That would remove one optional chaining, and skip the function call for unrelated errorrs

Copy link
Contributor Author

@mag123c mag123c Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just my codding style. 😢 updated to use short-circuit evaluation. Thanks!


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.`;
let advice;
switch (undefinedGlobal) {
case 'require':
advice = 'replace require() with import';
break;
case 'module':
case 'exports':
advice = 'use export instead of module.exports/exports';
break;
case '__filename':
advice = 'use import.meta.filename instead';
break;
case '__dirname':
advice = 'use import.meta.dirname instead';
break;
}

e.message = `Cannot determine intended module format because both '${undefinedGlobal}' 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, ${advice}.`;
e.code = 'ERR_AMBIGUOUS_MODULE_SYNTAX';
return;
}
Expand Down
58 changes: 56 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 },

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\./
);
strictEqual(stdout, '');
strictEqual(code, 1);
Expand Down Expand Up @@ -440,7 +440,61 @@ describe('cjs & esm ambiguous syntax case', () => {

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\./
);

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

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

match(
stderr,
/ReferenceError: Cannot determine intended module format because both 'exports' 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, use export instead of module\.exports\/exports\./
);

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

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

match(
stderr,
/ReferenceError: Cannot determine intended module format because both '__filename' 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, use import\.meta\.filename instead\./
);

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

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

match(
stderr,
/ReferenceError: Cannot determine intended module format because both '__dirname' 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, use import\.meta\.dirname instead\./
);

strictEqual(code, 1);
Expand Down
Loading