esm: refactor `get_format` · nodejs/node@0d327c8
@@ -17,6 +17,7 @@ const {
1717 mimeToFormat,
1818} = require('internal/modules/esm/formats');
191920+const detectModule = getOptionValue('--experimental-detect-module');
2021const experimentalNetworkImports =
2122getOptionValue('--experimental-network-imports');
2223const { containsModuleSyntax } = internalBinding('contextify');
@@ -33,6 +34,17 @@ const protocolHandlers = {
3334'node:'() { return 'builtin'; },
3435};
353637+/**
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 ? null : '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
112124default: { // 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
154163return 'commonjs';
155164}
156165default: { // 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 null;
168+}
169+const format = getFormatOfExtensionlessFile(url);
170+if (format === 'wasm') {
163171return format;
164172}
165-return 'commonjs';
173+return detectModuleFormat(source, url);
166174}
167175}
168176}