Skip to content

Commit aadf162

Browse files
committed
esm: fix format sometimes being null
1 parent 86415e4 commit aadf162

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

lib/internal/modules/esm/get_format.js

+33-25
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const {
1717
mimeToFormat,
1818
} = require('internal/modules/esm/formats');
1919

20+
const detectModule = getOptionValue('--experimental-detect-module');
2021
const experimentalNetworkImports =
2122
getOptionValue('--experimental-network-imports');
2223
const { containsModuleSyntax } = internalBinding('contextify');
@@ -33,6 +34,17 @@ const protocolHandlers = {
3334
'node:'() { return 'builtin'; },
3435
};
3536

37+
/**
38+
* Determine whether the given ambiguous source contains CommonJS or ES module syntax.
39+
* @param {string | Buffer | undefined} source
40+
* @param {URL} url
41+
*/
42+
function detectModuleFormat(source, url) {
43+
if (!source) { return detectModule ? undefined : 'commonjs'; }
44+
if (!detectModule) { return 'commonjs'; }
45+
return containsModuleSyntax(`${source}`, fileURLToPath(url), url) ? 'module' : 'commonjs';
46+
}
47+
3648
/**
3749
* @param {URL} parsed
3850
* @returns {string | null}
@@ -112,26 +124,23 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
112124
default: { // The user did not pass `--experimental-default-type`.
113125
// `source` is undefined when this is called from `defaultResolve`;
114126
// but this gets called again from `defaultLoad`/`defaultLoadSync`.
115-
if (getOptionValue('--experimental-detect-module')) {
116-
const format = source ?
117-
(containsModuleSyntax(`${source}`, fileURLToPath(url), url) ? 'module' : 'commonjs') :
118-
null;
119-
if (format === 'module') {
120-
// This module has a .js extension, a package.json with no `type` field, and ESM syntax.
121-
// Warn about the missing `type` field so that the user can avoid the performance penalty of detection.
122-
typelessPackageJsonFilesWarnedAbout ??= new SafeSet();
123-
if (!typelessPackageJsonFilesWarnedAbout.has(pjsonPath)) {
124-
const warning = `${url} parsed as an ES module because module syntax was detected;` +
125-
` to avoid the performance penalty of syntax detection, add "type": "module" to ${pjsonPath}`;
126-
process.emitWarning(warning, {
127-
code: 'MODULE_TYPELESS_PACKAGE_JSON',
128-
});
129-
typelessPackageJsonFilesWarnedAbout.add(pjsonPath);
130-
}
127+
// For ambiguous files (no type field, .js extension) we return
128+
// undefined from `resolve` and re-run the check in `load`.
129+
const format = detectModuleFormat(source, url);
130+
if (format === 'module') {
131+
// This module has a .js extension, a package.json with no `type` field, and ESM syntax.
132+
// Warn about the missing `type` field so that the user can avoid the performance penalty of detection.
133+
typelessPackageJsonFilesWarnedAbout ??= new SafeSet();
134+
if (!typelessPackageJsonFilesWarnedAbout.has(pjsonPath)) {
135+
const warning = `${url} parsed as an ES module because module syntax was detected;` +
136+
` to avoid the performance penalty of syntax detection, add "type": "module" to ${pjsonPath}`;
137+
process.emitWarning(warning, {
138+
code: 'MODULE_TYPELESS_PACKAGE_JSON',
139+
});
140+
typelessPackageJsonFilesWarnedAbout.add(pjsonPath);
131141
}
132-
return format;
133142
}
134-
return 'commonjs';
143+
return format;
135144
}
136145
}
137146
}
@@ -154,15 +163,14 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
154163
return 'commonjs';
155164
}
156165
default: { // The user did not pass `--experimental-default-type`.
157-
if (getOptionValue('--experimental-detect-module')) {
158-
if (!source) { return null; }
159-
const format = getFormatOfExtensionlessFile(url);
160-
if (format === 'module') {
161-
return containsModuleSyntax(`${source}`, fileURLToPath(url), url) ? 'module' : 'commonjs';
162-
}
166+
if (!source) {
167+
return;
168+
}
169+
const format = getFormatOfExtensionlessFile(url);
170+
if (format === 'wasm') {
163171
return format;
164172
}
165-
return 'commonjs';
173+
return detectModuleFormat(source, url);
166174
}
167175
}
168176
}

test/es-module/test-esm-detect-ambiguous.mjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ describe('--experimental-detect-module', { concurrency: !process.env.TEST_PARALL
175175
'--no-warnings',
176176
'--loader',
177177
`data:text/javascript,import { writeSync } from "node:fs"; export ${encodeURIComponent(
178-
async function resolve(s, c, next) {
179-
const result = await next(s, c);
178+
async function resolve(specifier, context, next) {
179+
const result = await next(specifier, context);
180180
writeSync(1, result.format + '\n');
181181
return result;
182182
}
@@ -185,7 +185,7 @@ describe('--experimental-detect-module', { concurrency: !process.env.TEST_PARALL
185185
]);
186186

187187
strictEqual(stderr, '');
188-
strictEqual(stdout, 'null\nexecuted\n');
188+
strictEqual(stdout, 'undefined\nexecuted\n');
189189
strictEqual(code, 0);
190190
strictEqual(signal, null);
191191

0 commit comments

Comments
 (0)