From a4dc1ba87ca5ac96b42de77d2f0aa8a114ef1ad6 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 29 Jul 2025 10:55:11 -0400 Subject: [PATCH 1/6] fix: use original require() error if ERR_UNKNOWN_FILE_EXTENSION --- lib/nodejs/esm-utils.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/nodejs/esm-utils.js b/lib/nodejs/esm-utils.js index 3cea8af249..9916a61d5e 100644 --- a/lib/nodejs/esm-utils.js +++ b/lib/nodejs/esm-utils.js @@ -92,9 +92,19 @@ const tryImportAndRequire = async (file, esmDecorator) => { const requireModule = async (file, esmDecorator) => { try { return require(file); - } catch (err) { - // Import if require fails. - return dealWithExports(await formattedImport(file, esmDecorator)); + } catch (requireErr) { + // Fallback to import() if require() fails. + try { + return dealWithExports(await formattedImport(file, esmDecorator)); + } catch (importErr) { + // If a --require module throws in a Node.js version that doesn't yet support .ts files, + // the fallback import() will throw an uninformative error about the file extension. + // What we actually care about is the original require() error. + // See: https://github.com/mochajs/mocha/issues/5393 + throw /\.(?:c|m)?ts$/.test(file) || importErr?.code === "ERR_UNKNOWN_FILE_EXTENSION" + ? requireErr + : importErr; + } } } From e7a549af9a3f16c57b1130fead8069b8314e5d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Tue, 12 Aug 2025 07:22:21 -0600 Subject: [PATCH 2/6] Update lib/nodejs/esm-utils.js Co-authored-by: Mark Wiemer <7833360+mark-wiemer@users.noreply.github.com> --- lib/nodejs/esm-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nodejs/esm-utils.js b/lib/nodejs/esm-utils.js index 9916a61d5e..b8ecc18c55 100644 --- a/lib/nodejs/esm-utils.js +++ b/lib/nodejs/esm-utils.js @@ -101,7 +101,7 @@ const requireModule = async (file, esmDecorator) => { // the fallback import() will throw an uninformative error about the file extension. // What we actually care about is the original require() error. // See: https://github.com/mochajs/mocha/issues/5393 - throw /\.(?:c|m)?ts$/.test(file) || importErr?.code === "ERR_UNKNOWN_FILE_EXTENSION" + throw /\.(cts|mts|ts)$/.test(file) || importErr?.code === "ERR_UNKNOWN_FILE_EXTENSION" ? requireErr : importErr; } From 7643d83c538d56b07b92979b869228448500494c Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 1 Sep 2025 09:40:35 -0400 Subject: [PATCH 3/6] Add in comments --- lib/nodejs/esm-utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/nodejs/esm-utils.js b/lib/nodejs/esm-utils.js index 45d1ab9171..d4999f8dc9 100644 --- a/lib/nodejs/esm-utils.js +++ b/lib/nodejs/esm-utils.js @@ -107,13 +107,14 @@ const requireModule = async (file, esmDecorator) => { // See: https://github.com/mochajs/mocha/issues/5393 if ( /\.(cts|mts|ts)$/.test(file) || - importErr?.code === 'ERR_UNKNOWN_FILE_EXTENSION' + importErr.code === 'ERR_UNKNOWN_FILE_EXTENSION' ) { throw requireErr; } // Similarly, for an exports/imports mismatch such as a missing 'default', // the require() error will be more informative for users. + // See: https://github.com/mochajs/mocha/issues/5411 if (importErr.code === 'ERR_INTERNAL_ASSERTION') { throw requireErr; } From 4a80ed637b2afb51310f51204c2fd323c1f2459c Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Thu, 25 Sep 2025 13:47:39 -0400 Subject: [PATCH 4/6] test: add broken-syntax.ts fixture and test --- test/node-unit/esm-utils.spec.js | 15 +++++++++++++++ test/node-unit/fixtures/broken-syntax.ts | 1 + 2 files changed, 16 insertions(+) create mode 100644 test/node-unit/fixtures/broken-syntax.ts diff --git a/test/node-unit/esm-utils.spec.js b/test/node-unit/esm-utils.spec.js index e751ce3caf..f2de8160fa 100644 --- a/test/node-unit/esm-utils.spec.js +++ b/test/node-unit/esm-utils.spec.js @@ -20,6 +20,21 @@ describe('esm-utils', function () { } ); }); + + it('should show a syntax error message when importing a TypeScript file with a syntax complaint', async function () { + return expect( + () => + esmUtils.requireOrImport( + '../../test/node-unit/fixtures/broken-syntax.ts' + ), + 'to be rejected with error satisfying', + { + name: 'SyntaxError', + message: + /Invalid or unexpected token|Expected ident/ + } + ); + }); }); describe('loadFilesAsync()', function () { diff --git a/test/node-unit/fixtures/broken-syntax.ts b/test/node-unit/fixtures/broken-syntax.ts new file mode 100644 index 0000000000..550b2f0afd --- /dev/null +++ b/test/node-unit/fixtures/broken-syntax.ts @@ -0,0 +1 @@ +@! From a9665182d64f7065b0ff03361a55be475cb3a024 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Thu, 25 Sep 2025 13:49:00 -0400 Subject: [PATCH 5/6] chore: reset a change to main --- lib/nodejs/esm-utils.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/nodejs/esm-utils.js b/lib/nodejs/esm-utils.js index d4999f8dc9..77541d7f51 100644 --- a/lib/nodejs/esm-utils.js +++ b/lib/nodejs/esm-utils.js @@ -126,10 +126,7 @@ const requireModule = async (file, esmDecorator) => { // We only assign this `requireOrImport` function once based on Node version // We check for file extensions in `requireModule` and `tryImportAndRequire` -debug( - 'assigning requireOrImport, require_module === %O', - process.features.require_module -); +debug('assigning requireOrImport, require_module === %O', process.features.require_module); if (process.features.require_module) { exports.requireOrImport = requireModule; } else { From be723897b95eb2b4336aa71a0262d9bad23e474e Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Thu, 25 Sep 2025 13:51:16 -0400 Subject: [PATCH 6/6] test: slightly improve name --- test/node-unit/esm-utils.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/node-unit/esm-utils.spec.js b/test/node-unit/esm-utils.spec.js index f2de8160fa..2ca4cbfc34 100644 --- a/test/node-unit/esm-utils.spec.js +++ b/test/node-unit/esm-utils.spec.js @@ -21,7 +21,7 @@ describe('esm-utils', function () { ); }); - it('should show a syntax error message when importing a TypeScript file with a syntax complaint', async function () { + it('should show a syntax error message when importing a TypeScript file with invalid syntax', async function () { return expect( () => esmUtils.requireOrImport(