diff --git a/lib/nodejs/esm-utils.js b/lib/nodejs/esm-utils.js index 9a854be376..18abe81ff8 100644 --- a/lib/nodejs/esm-utils.js +++ b/lib/nodejs/esm-utils.js @@ -10,7 +10,7 @@ const formattedImport = async file => { // the location of the syntax error in the error thrown. // This is problematic because the user can't see what file has the problem, // so we add the file location to the error. - // This `if` should be removed once Node.js fixes the problem. + // TODO: remove once Node.js fixes the problem. if ( err instanceof SyntaxError && err.message && @@ -30,64 +30,52 @@ const formattedImport = async file => { return import(file); }; -const hasStableEsmImplementation = (() => { - const [major, minor] = process.version.split('.'); - // ESM is stable from v12.22.0 onward - // https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules - const majorNumber = parseInt(major.slice(1), 10); - const minorNumber = parseInt(minor, 10); - return majorNumber > 12 || (majorNumber === 12 && minorNumber >= 22); -})(); - -exports.requireOrImport = hasStableEsmImplementation - ? async file => { - if (path.extname(file) === '.mjs') { - return formattedImport(file); - } +exports.requireOrImport = async file => { + if (path.extname(file) === '.mjs') { + return formattedImport(file); + } + try { + return dealWithExports(await formattedImport(file)); + } catch (err) { + if ( + err.code === 'ERR_MODULE_NOT_FOUND' || + err.code === 'ERR_UNKNOWN_FILE_EXTENSION' || + err.code === 'ERR_UNSUPPORTED_DIR_IMPORT' + ) { try { - return dealWithExports(await formattedImport(file)); - } catch (err) { + // Importing a file usually works, but the resolution of `import` is the ESM + // resolution algorithm, and not the CJS resolution algorithm. We may have + // failed because we tried the ESM resolution, so we try to `require` it. + return require(file); + } catch (requireErr) { if ( - err.code === 'ERR_MODULE_NOT_FOUND' || - err.code === 'ERR_UNKNOWN_FILE_EXTENSION' || - err.code === 'ERR_UNSUPPORTED_DIR_IMPORT' + requireErr.code === 'ERR_REQUIRE_ESM' || + (requireErr instanceof SyntaxError && + requireErr + .toString() + .includes('Cannot use import statement outside a module')) ) { - try { - // Importing a file usually works, but the resolution of `import` is the ESM - // resolution algorithm, and not the CJS resolution algorithm. So in this case - // if we fail, we may have failed because we tried the ESM resolution and failed - // So we try to `require` it - return require(file); - } catch (requireErr) { - if ( - requireErr.code === 'ERR_REQUIRE_ESM' || - (requireErr instanceof SyntaxError && - requireErr - .toString() - .includes('Cannot use import statement outside a module')) - ) { - // ERR_REQUIRE_ESM happens when the test file is a JS file, but via type:module is actually ESM, - // AND has an import to a file that doesn't exist. - // This throws an `ERR_MODULE_NOT_FOUND` error above, - // and when we try to `require` it here, it throws an `ERR_REQUIRE_ESM`. - // What we want to do is throw the original error (the `ERR_MODULE_NOT_FOUND`), - // and not the `ERR_REQUIRE_ESM` error, which is a red herring. - // - // SyntaxError happens when in an edge case: when we're using an ESM loader that loads - // a `test.ts` file (i.e. unrecognized extension), and that file includes an unknown - // import (which thows an ERR_MODULE_NOT_FOUND). require-ing it will throw the - // syntax error, because we cannot require a file that has import-s. - throw err; - } else { - throw requireErr; - } - } - } else { + // ERR_REQUIRE_ESM happens when the test file is a JS file, but via type:module is actually ESM, + // AND has an import to a file that doesn't exist. + // This throws an `ERR_MODULE_NOT_FOUND` error above, + // and when we try to `require` it here, it throws an `ERR_REQUIRE_ESM`. + // What we want to do is throw the original error (the `ERR_MODULE_NOT_FOUND`), + // and not the `ERR_REQUIRE_ESM` error, which is a red herring. + // + // SyntaxError happens when in an edge case: when we're using an ESM loader that loads + // a `test.ts` file (i.e. unrecognized extension), and that file includes an unknown + // import (which throws an ERR_MODULE_NOT_FOUND). `require`-ing it will throw the + // syntax error, because we cannot require a file that has `import`-s. throw err; + } else { + throw requireErr; } } + } else { + throw err; } - : implementationOfRequireOrImportForUnstableEsm; + } +}; function dealWithExports(module) { if (module.default) { @@ -104,21 +92,3 @@ exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => { postLoadFunc(file, result); } }; - -/* istanbul ignore next */ -async function implementationOfRequireOrImportForUnstableEsm(file) { - if (path.extname(file) === '.mjs') { - return formattedImport(file); - } - // This is currently the only known way of figuring out whether a file is CJS or ESM in - // Node.js that doesn't necessitate calling `import` first. - try { - return require(file); - } catch (err) { - if (err.code === 'ERR_REQUIRE_ESM') { - return formattedImport(file); - } else { - throw err; - } - } -} diff --git a/test/integration/diffs.spec.js b/test/integration/diffs.spec.js index 2f15fecc0b..26c4882d10 100644 --- a/test/integration/diffs.spec.js +++ b/test/integration/diffs.spec.js @@ -69,12 +69,6 @@ describe('diffs', function () { var diffs, expected; before(function (done) { - // @TODO: It should be removed when Node.js 10 LTS is not supported. - const nodeVersion = parseInt(process.version.match(/^v(\d+)\./)[1], 10); - if (nodeVersion === 10) { - this.skip(); - } - run('diffs/diffs.fixture.js', [], function (err, res) { if (err) { done(err); diff --git a/test/integration/glob.spec.js b/test/integration/glob.spec.js index c85c072d49..19b06f8b1c 100644 --- a/test/integration/glob.spec.js +++ b/test/integration/glob.spec.js @@ -187,13 +187,6 @@ var testGlob = { }) }; -var isFlakeyNode = (function () { - var version = process.versions.node.split('.'); - return ( - version[0] === '0' && version[1] === '10' && process.platform === 'win32' - ); -})(); - function execMochaWith(validate) { return function execMocha(glob, assertOn, done) { exec( @@ -206,12 +199,8 @@ function execMochaWith(validate) { function (error, stdout, stderr) { try { validate(error, stderr); - if (isFlakeyNode && error && stderr === '') { - execMocha(glob, assertOn, done); - } else { - assertOn({stdout: stdout, stderr: stderr}); - done(); - } + assertOn({stdout: stdout, stderr: stderr}); + done(); } catch (assertion) { done(assertion); } diff --git a/test/integration/no-diff.spec.js b/test/integration/no-diff.spec.js index 99775abf48..d7eeb9ea1e 100644 --- a/test/integration/no-diff.spec.js +++ b/test/integration/no-diff.spec.js @@ -6,12 +6,6 @@ var run = helpers.runMocha; describe('no-diff', function () { describe('when enabled', function () { it('should not display a diff', function (done) { - // @TODO: It should be removed when Node.js 10 LTS is not supported. - const nodeVersion = parseInt(process.version.match(/^v(\d+)\./)[1], 10); - if (nodeVersion === 10) { - this.skip(); - } - run('no-diff.fixture.js', ['--no-diff'], function (err, res) { if (err) { done(err);