const path = require('path'); const url = require('url'); const formattedImport = async file => { if (path.isAbsolute(file)) { try { return await import(url.pathToFileURL(file)); } catch (err) { // This is a hack created because ESM in Node.js (at least in Node v15.5.1) does not emit // 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. if ( err instanceof SyntaxError && err.message && err.stack && !err.stack.includes(file) ) { const newErrorWithFilename = new SyntaxError(err.message); newErrorWithFilename.stack = err.stack.replace( /^SyntaxError/, `SyntaxError[ @${file} ]` ); throw newErrorWithFilename; } throw err; } } return import(file); }; exports.requireOrImport = async 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. // If Node.js or the community establish a better procedure for that, we can fix this code. // Another option here would be to always use `import()`, as this also supports CJS, but I would be // wary of using it for _all_ existing test files, till ESM is fully stable. try { return require(file); } catch (err) { if (err.code === 'ERR_REQUIRE_ESM') { return formattedImport(file); } else { throw err; } } }; exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => { for (const file of files) { preLoadFunc(file); const result = await exports.requireOrImport(path.resolve(file)); postLoadFunc(file, result); } };