Skip to content

Commit

Permalink
module: fix legacy node specifier resolution to resolve "main" field
Browse files Browse the repository at this point in the history
PR-URL: #38979
Fixes: #32103
Fixes: #38739
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
  • Loading branch information
aduh95 authored and danielleadams committed Jun 14, 2021
1 parent f652284 commit 92ed1c6
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 6 deletions.
26 changes: 20 additions & 6 deletions lib/internal/modules/esm/resolve.js
Expand Up @@ -34,7 +34,7 @@ const { getOptionValue } = require('internal/options');
const policy = getOptionValue('--experimental-policy') ?
require('internal/process/policy') :
null;
const { sep, relative } = require('path');
const { sep, relative, resolve } = require('path');
const preserveSymlinks = getOptionValue('--preserve-symlinks');
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
const typeFlag = getOptionValue('--input-type');
Expand Down Expand Up @@ -204,16 +204,18 @@ function getPackageScopeConfig(resolved) {
return packageConfig;
}

/*
/**
* Legacy CommonJS main resolution:
* 1. let M = pkg_url + (json main field)
* 2. TRY(M, M.js, M.json, M.node)
* 3. TRY(M/index.js, M/index.json, M/index.node)
* 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
* 5. NOT_FOUND
* @param {string | URL} url
* @returns {boolean}
*/
function fileExists(url) {
return tryStatSync(fileURLToPath(url)).isFile();
return statSync(url, { throwIfNoEntry: false })?.isFile() ?? false;
}

function legacyMainResolve(packageJSONUrl, packageConfig, base) {
Expand Down Expand Up @@ -272,7 +274,19 @@ function resolveExtensions(search) {
return undefined;
}

function resolveIndex(search) {
function resolveDirectoryEntry(search) {
const dirPath = fileURLToPath(search);
const pkgJsonPath = resolve(dirPath, 'package.json');
if (fileExists(pkgJsonPath)) {
const pkgJson = packageJsonReader.read(pkgJsonPath);
if (pkgJson.containsKeys) {
const { main } = JSONParse(pkgJson.string);
if (main != null) {
const mainUrl = pathToFileURL(resolve(dirPath, main));
return resolveExtensionsWithTryExactName(mainUrl);
}
}
}
return resolveExtensions(new URL('index', search));
}

Expand All @@ -288,10 +302,10 @@ function finalizeResolution(resolved, base) {
let file = resolveExtensionsWithTryExactName(resolved);
if (file !== undefined) return file;
if (!StringPrototypeEndsWith(path, '/')) {
file = resolveIndex(new URL(`${resolved}/`));
file = resolveDirectoryEntry(new URL(`${resolved}/`));
if (file !== undefined) return file;
} else {
return resolveIndex(resolved) || resolved;
return resolveDirectoryEntry(resolved) || resolved;
}
throw new ERR_MODULE_NOT_FOUND(
resolved.pathname, fileURLToPath(base), 'module');
Expand Down
3 changes: 3 additions & 0 deletions test/es-module/test-esm-specifiers-legacy-flag.mjs
Expand Up @@ -6,12 +6,15 @@ import assert from 'assert';
import commonjs from '../fixtures/es-module-specifiers/package-type-commonjs';
// esm index.js
import module from '../fixtures/es-module-specifiers/package-type-module';
// Directory entry with main.js
import main from '../fixtures/es-module-specifiers/dir-with-main';
// Notice the trailing slash
import success, { explicit, implicit, implicitModule }
from '../fixtures/es-module-specifiers/';

assert.strictEqual(commonjs, 'commonjs');
assert.strictEqual(module, 'module');
assert.strictEqual(main, 'main');
assert.strictEqual(success, 'success');
assert.strictEqual(explicit, 'esm');
assert.strictEqual(implicit, 'cjs');
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/es-module-specifiers/dir-with-main/main.js
@@ -0,0 +1 @@
module.exports = 'main';
3 changes: 3 additions & 0 deletions test/fixtures/es-module-specifiers/dir-with-main/package.json
@@ -0,0 +1,3 @@
{
"main": "./main.js"
}

0 comments on commit 92ed1c6

Please sign in to comment.