Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Bedford <guybedford@gmail.com>2020-08-10 02:54:01 +0300
committerGuy Bedford <guybedford@gmail.com>2020-08-13 21:04:24 +0300
commitf8976a76bbb49d678056d6d2ddd57064cf9e63c2 (patch)
tree864e198c4ac8ab2cffb21cad70d09b77025abdc0 /lib/internal/modules
parent56b25e7a6f741c8181c55f3d40d0cab6ffa1eb4d (diff)
module: share CJS/ESM resolver fns, refactoring
PR-URL: https://github.com/nodejs/node/pull/34744 Reviewed-By: Jan Krems <jan.krems@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib/internal/modules')
-rw-r--r--lib/internal/modules/cjs/loader.js290
-rw-r--r--lib/internal/modules/esm/resolve.js223
2 files changed, 149 insertions, 364 deletions
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index 794f84c1285..dcad0bcf632 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -33,13 +33,11 @@ const {
Error,
JSONParse,
Map,
- Number,
ObjectCreate,
ObjectDefineProperty,
ObjectFreeze,
ObjectGetOwnPropertyDescriptor,
ObjectGetPrototypeOf,
- ObjectIs,
ObjectKeys,
ObjectPrototypeHasOwnProperty,
ObjectSetPrototypeOf,
@@ -49,7 +47,6 @@ const {
SafeWeakMap,
SafeSet,
String,
- StringPrototypeIndexOf,
StringPrototypeMatch,
StringPrototypeSlice,
StringPrototypeStartsWith,
@@ -94,10 +91,7 @@ let hasLoadedAnyUserCJSModule = false;
const {
ERR_INVALID_ARG_VALUE,
ERR_INVALID_OPT_VALUE,
- ERR_INVALID_PACKAGE_CONFIG,
- ERR_INVALID_PACKAGE_TARGET,
ERR_INVALID_MODULE_SPECIFIER,
- ERR_PACKAGE_PATH_NOT_EXPORTED,
ERR_REQUIRE_ESM
} = require('internal/errors').codes;
const { validateString } = require('internal/validators');
@@ -117,7 +111,8 @@ const asyncESM = require('internal/process/esm_loader');
const { kEvaluated } = internalBinding('module_wrap');
const {
encodedSepRegEx,
- packageInternalResolve
+ packageExportsResolve,
+ packageImportsResolve
} = require('internal/modules/esm/resolve');
const isWindows = process.platform === 'win32';
@@ -319,18 +314,8 @@ function readPackageScope(checkPath) {
return false;
}
-function readPackageMain(requestPath) {
- const pkg = readPackage(requestPath);
- return pkg ? pkg.main : undefined;
-}
-
-function readPackageExports(requestPath) {
- const pkg = readPackage(requestPath);
- return pkg ? pkg.exports : undefined;
-}
-
function tryPackage(requestPath, exts, isMain, originalPath) {
- const pkg = readPackageMain(requestPath);
+ const pkg = readPackage(requestPath)?.main;
if (!pkg) {
return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain);
@@ -435,108 +420,28 @@ function trySelfParentPath(parent) {
function trySelf(parentPath, request) {
if (!parentPath) return false;
- const { data: pkg, path: basePath } = readPackageScope(parentPath) || {};
+ const { data: pkg, path: pkgPath } = readPackageScope(parentPath) || {};
if (!pkg || pkg.exports === undefined) return false;
if (typeof pkg.name !== 'string') return false;
let expansion;
if (request === pkg.name) {
- expansion = '';
+ expansion = '.';
} else if (StringPrototypeStartsWith(request, `${pkg.name}/`)) {
- expansion = StringPrototypeSlice(request, pkg.name.length);
+ expansion = '.' + StringPrototypeSlice(request, pkg.name.length);
} else {
return false;
}
- const fromExports = applyExports(basePath, expansion);
- if (fromExports) {
- return tryFile(fromExports, false);
- }
- assert(fromExports !== false);
-}
-
-function isConditionalDotExportSugar(exports, basePath) {
- if (typeof exports === 'string')
- return true;
- if (ArrayIsArray(exports))
- return true;
- if (typeof exports !== 'object')
- return false;
- let isConditional = false;
- let firstCheck = true;
- for (const key of ObjectKeys(exports)) {
- const curIsConditional = key[0] !== '.';
- if (firstCheck) {
- firstCheck = false;
- isConditional = curIsConditional;
- } else if (isConditional !== curIsConditional) {
- throw new ERR_INVALID_PACKAGE_CONFIG(basePath, '"exports" cannot ' +
- 'contain some keys starting with \'.\' and some not. The exports ' +
- 'object must either be an object of package subpath keys or an ' +
- 'object of main entry condition name keys only.');
- }
- }
- return isConditional;
-}
-
-function applyExports(basePath, expansion) {
- const mappingKey = `.${expansion}`;
-
- let pkgExports = readPackageExports(basePath);
- if (pkgExports === undefined || pkgExports === null)
- return false;
-
- if (isConditionalDotExportSugar(pkgExports, basePath))
- pkgExports = { '.': pkgExports };
-
- if (typeof pkgExports === 'object') {
- if (ObjectPrototypeHasOwnProperty(pkgExports, mappingKey)) {
- const mapping = pkgExports[mappingKey];
- const resolved = resolveExportsTarget(
- pathToFileURL(basePath + '/'), mapping, '', mappingKey);
- if (resolved === null || resolved === undefined)
- throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
- basePath, mappingKey);
- return resolved;
- }
-
- let dirMatch = '';
- for (const candidateKey of ObjectKeys(pkgExports)) {
- if (candidateKey[candidateKey.length - 1] !== '/') continue;
- if (candidateKey.length > dirMatch.length &&
- StringPrototypeStartsWith(mappingKey, candidateKey)) {
- dirMatch = candidateKey;
- }
- }
-
- if (dirMatch !== '') {
- const mapping = pkgExports[dirMatch];
- const subpath = StringPrototypeSlice(mappingKey, dirMatch.length);
- const resolved = resolveExportsTarget(pathToFileURL(basePath + '/'),
- mapping, subpath, mappingKey);
- if (resolved === null || resolved === undefined)
- throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
- basePath, mappingKey + subpath);
- // Extension searching for folder exports only
- const rc = stat(resolved);
- if (rc === 0) return resolved;
- if (!(RegExpPrototypeTest(trailingSlashRegex, resolved))) {
- const exts = ObjectKeys(Module._extensions);
- const filename = tryExtensions(resolved, exts, false);
- if (filename) return filename;
- }
- if (rc === 1) {
- const exts = ObjectKeys(Module._extensions);
- const filename = tryPackage(resolved, exts, false,
- basePath + expansion);
- if (filename) return filename;
- }
- // Undefined means not found
- return;
- }
+ try {
+ return finalizeEsmResolution(packageExportsResolve(
+ pathToFileURL(pkgPath + '/package.json'), expansion, pkg,
+ pathToFileURL(parentPath), cjsConditions), request, parentPath, pkgPath);
+ } catch (e) {
+ if (e.code === 'ERR_MODULE_NOT_FOUND')
+ throw createEsmNotFoundErr(request, pkgPath + '/package.json');
+ throw e;
}
-
- throw new ERR_PACKAGE_PATH_NOT_EXPORTED(basePath, mappingKey);
}
// This only applies to requests of a specific form:
@@ -547,107 +452,21 @@ function resolveExports(nmPath, request) {
// The implementation's behavior is meant to mirror resolution in ESM.
const [, name, expansion = ''] =
StringPrototypeMatch(request, EXPORTS_PATTERN) || [];
- if (!name) {
- return false;
- }
-
- const basePath = path.resolve(nmPath, name);
- const fromExports = applyExports(basePath, expansion);
- if (fromExports) {
- return tryFile(fromExports, false);
- }
- return fromExports;
-}
-
-function isArrayIndex(p) {
- assert(typeof p === 'string');
- const n = Number(p);
- if (String(n) !== p)
- return false;
- if (ObjectIs(n, +0))
- return true;
- if (!Number.isInteger(n))
- return false;
- return n >= 0 && n < (2 ** 32) - 1;
-}
-
-function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
- if (typeof target === 'string') {
- let resolvedTarget, resolvedTargetPath;
- const pkgPathPath = baseUrl.pathname;
- if (StringPrototypeStartsWith(target, './')) {
- resolvedTarget = new URL(target, baseUrl);
- resolvedTargetPath = resolvedTarget.pathname;
- if (!StringPrototypeStartsWith(resolvedTargetPath, pkgPathPath) ||
- StringPrototypeIndexOf(resolvedTargetPath, '/node_modules/',
- pkgPathPath.length - 1) !== -1)
- resolvedTarget = undefined;
- }
- if (subpath.length > 0 && target[target.length - 1] !== '/')
- resolvedTarget = undefined;
- if (resolvedTarget === undefined)
- throw new ERR_INVALID_PACKAGE_TARGET(baseUrl.pathname, mappingKey,
- target);
- const resolved = new URL(subpath, resolvedTarget);
- const resolvedPath = resolved.pathname;
- if (StringPrototypeStartsWith(resolvedPath, resolvedTargetPath) &&
- StringPrototypeIndexOf(resolvedPath, '/node_modules/',
- pkgPathPath.length - 1) === -1) {
- if (StringPrototypeMatch(resolvedPath, encodedSepRegEx))
- throw new ERR_INVALID_MODULE_SPECIFIER(
- resolvedPath, 'must not include encoded "/" or "\\" characters',
- fileURLToPath(baseUrl));
- return fileURLToPath(resolved);
- }
- const reason = 'request is not a valid subpath for the "exports" ' +
- `resolution of ${baseUrl.pathname}package.json`;
- throw new ERR_INVALID_MODULE_SPECIFIER(mappingKey + subpath, reason);
- } else if (ArrayIsArray(target)) {
- if (target.length === 0)
- return null;
- let lastException;
- for (const targetValue of target) {
- let resolved;
- try {
- resolved = resolveExportsTarget(baseUrl, targetValue, subpath,
- mappingKey);
- } catch (e) {
- lastException = e;
- if (e.code !== 'ERR_INVALID_PACKAGE_TARGET')
- throw e;
- }
- if (resolved === undefined)
- continue;
- if (resolved === null) {
- lastException = null;
- continue;
- }
- return resolved;
- }
- // Throw last fallback error
- if (lastException === undefined || lastException === null)
- return lastException;
- throw lastException;
- } else if (typeof target === 'object' && target !== null) {
- const keys = ObjectKeys(target);
- if (keys.some(isArrayIndex)) {
- throw new ERR_INVALID_PACKAGE_CONFIG(baseUrl, '"exports" cannot ' +
- 'contain numeric property keys.');
- }
- for (const p of keys) {
- if (cjsConditions.has(p) || p === 'default') {
- const resolved = resolveExportsTarget(baseUrl, target[p], subpath,
- mappingKey);
- if (resolved === undefined)
- continue;
- return resolved;
- }
+ if (!name)
+ return;
+ const pkgPath = path.resolve(nmPath, name);
+ const pkg = readPackage(pkgPath);
+ if (pkg && pkg.exports !== null && pkg.exports !== undefined) {
+ try {
+ return finalizeEsmResolution(packageExportsResolve(
+ pathToFileURL(pkgPath + '/package.json'), '.' + expansion, pkg, null,
+ cjsConditions), request, null, pkgPath);
+ } catch (e) {
+ if (e.code === 'ERR_MODULE_NOT_FOUND')
+ throw createEsmNotFoundErr(request, pkgPath + '/package.json');
+ throw e;
}
- return undefined;
- } else if (target === null) {
- return null;
}
- throw new ERR_INVALID_PACKAGE_TARGET(baseUrl.pathname, mappingKey, target);
}
const trailingSlashRegex = /(?:^|\/)\.?\.$/;
@@ -680,12 +499,8 @@ Module._findPath = function(request, paths, isMain) {
if (!absoluteRequest) {
const exportsResolved = resolveExports(curPath, request);
- // Undefined means not found, false means no exports
- if (exportsResolved === undefined)
- break;
- if (exportsResolved) {
+ if (exportsResolved)
return exportsResolved;
- }
}
const basePath = path.resolve(curPath, request);
@@ -1050,19 +865,14 @@ Module._resolveFilename = function(request, parent, isMain, options) {
if (pkg.data && pkg.data.imports !== null &&
pkg.data.imports !== undefined) {
try {
- const resolved = packageInternalResolve(
- request, pathToFileURL(parent.filename), cjsConditions);
- return fileURLToPath(resolved);
- } catch (err) {
- if (err.code === 'ERR_MODULE_NOT_FOUND') {
- // eslint-disable-next-line no-restricted-syntax
- const err = new Error(`Cannot find module '${request}'`);
- err.code = 'MODULE_NOT_FOUND';
- err.path = path.resolve(pkg.path, 'package.json');
- // TODO(BridgeAR): Add the requireStack as well.
- throw err;
- }
- throw err;
+ return finalizeEsmResolution(
+ packageImportsResolve(request, pathToFileURL(parent.filename),
+ cjsConditions), request, parent.filename,
+ pkg.path);
+ } catch (e) {
+ if (e.code === 'ERR_MODULE_NOT_FOUND')
+ throw createEsmNotFoundErr(request);
+ throw e;
}
}
}
@@ -1098,6 +908,34 @@ Module._resolveFilename = function(request, parent, isMain, options) {
throw err;
};
+function finalizeEsmResolution(match, request, parentPath, pkgPath) {
+ const { resolved, exact } = match;
+ if (StringPrototypeMatch(resolved, encodedSepRegEx))
+ throw new ERR_INVALID_MODULE_SPECIFIER(
+ resolved, 'must not include encoded "/" or "\\" characters', parentPath);
+ const filename = fileURLToPath(resolved);
+ let actual = tryFile(filename);
+ if (!exact && !actual) {
+ const exts = ObjectKeys(Module._extensions);
+ actual = tryExtensions(filename, exts, false) ||
+ tryPackage(filename, exts, false, request);
+ }
+ if (actual)
+ return actual;
+ const err = createEsmNotFoundErr(filename,
+ path.resolve(pkgPath, 'package.json'));
+ throw err;
+}
+
+function createEsmNotFoundErr(request, path) {
+ // eslint-disable-next-line no-restricted-syntax
+ const err = new Error(`Cannot find module '${request}'`);
+ err.code = 'MODULE_NOT_FOUND';
+ if (path)
+ err.path = path;
+ // TODO(BridgeAR): Add the requireStack as well.
+ return err;
+}
// Given a file name, pass it to the proper extension handler.
Module.prototype.load = function(filename) {
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index 7cf35529481..f6879465451 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -15,7 +15,6 @@ const {
SafeSet,
String,
StringPrototypeEndsWith,
- StringPrototypeIncludes,
StringPrototypeIndexOf,
StringPrototypeReplace,
StringPrototypeSlice,
@@ -78,14 +77,6 @@ function tryStatSync(path) {
}
}
-/**
- *
- * '/foo/package.json' -> '/foo'
- */
-function removePackageJsonFromPath(path) {
- return StringPrototypeSlice(path, 0, path.length - 13);
-}
-
function getPackageConfig(path) {
const existing = packageJSONCache.get(path);
if (existing !== undefined) {
@@ -110,8 +101,7 @@ function getPackageConfig(path) {
try {
packageJSON = JSONParse(source);
} catch (error) {
- const errorPath = removePackageJsonFromPath(path);
- throw new ERR_INVALID_PACKAGE_CONFIG(errorPath, error.message, true);
+ throw new ERR_INVALID_PACKAGE_CONFIG(path, null, error.message);
}
let { imports, main, name, type } = packageJSON;
@@ -177,7 +167,7 @@ function fileExists(url) {
return tryStatSync(fileURLToPath(url)).isFile();
}
-function legacyMainResolve(packageJSONUrl, packageConfig) {
+function legacyMainResolve(packageJSONUrl, packageConfig, base) {
let guess;
if (packageConfig.main !== undefined) {
// Note: fs check redundances will be handled by Descriptor cache here.
@@ -222,7 +212,8 @@ function legacyMainResolve(packageJSONUrl, packageConfig) {
return guess;
}
// Not found.
- return undefined;
+ throw new ERR_MODULE_NOT_FOUND(
+ fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
}
function resolveExtensionsWithTryExactName(search) {
@@ -246,35 +237,34 @@ function resolveIndex(search) {
const encodedSepRegEx = /%2F|%2C/i;
function finalizeResolution(resolved, base) {
+ if (RegExpPrototypeTest(encodedSepRegEx, resolved.pathname))
+ throw new ERR_INVALID_MODULE_SPECIFIER(
+ resolved.pathname, 'must not include encoded "/" or "\\" characters',
+ fileURLToPath(base));
+
+ const path = fileURLToPath(resolved);
if (getOptionValue('--experimental-specifier-resolution') === 'node') {
let file = resolveExtensionsWithTryExactName(resolved);
if (file !== undefined) return file;
- if (!StringPrototypeEndsWith(resolved.pathname, '/')) {
- file = resolveIndex(new URL(`${resolved.pathname}/`, base));
+ if (!StringPrototypeEndsWith(path, '/')) {
+ file = resolveIndex(new URL(`${resolved}/`));
+ if (file !== undefined) return file;
} else {
- file = resolveIndex(resolved);
+ return resolveIndex(resolved) || resolved;
}
- if (file !== undefined) return file;
throw new ERR_MODULE_NOT_FOUND(
resolved.pathname, fileURLToPath(base), 'module');
}
- if (RegExpPrototypeTest(encodedSepRegEx, resolved.pathname))
- throw new ERR_INVALID_MODULE_SPECIFIER(
- resolved.pathname, 'must not include encoded "/" or "\\" characters',
- fileURLToPath(base));
-
- const path = fileURLToPath(resolved);
- const stats = tryStatSync(path);
-
+ const stats = tryStatSync(StringPrototypeEndsWith(path, '/') ?
+ StringPrototypeSlice(path, -1) : path);
if (stats.isDirectory()) {
- const err = new ERR_UNSUPPORTED_DIR_IMPORT(
- path || resolved.pathname, fileURLToPath(base));
+ const err = new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base));
err.url = String(resolved);
throw err;
} else if (!stats.isFile()) {
throw new ERR_MODULE_NOT_FOUND(
- path || resolved.pathname, fileURLToPath(base), 'module');
+ path || resolved.pathname, base && fileURLToPath(base), 'module');
}
return resolved;
@@ -288,14 +278,15 @@ function throwImportNotDefined(specifier, packageJSONUrl, base) {
function throwExportsNotFound(subpath, packageJSONUrl, base) {
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
- fileURLToPath(new URL('.', packageJSONUrl)), subpath, fileURLToPath(base));
+ fileURLToPath(new URL('.', packageJSONUrl)), subpath,
+ base && fileURLToPath(base));
}
function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) {
const reason = `request is not a valid subpath for the "${internal ?
- 'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}${
- base ? ` imported from ${base}` : ''}`;
- throw new ERR_INVALID_MODULE_SPECIFIER(subpath, reason, fileURLToPath(base));
+ 'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}`;
+ throw new ERR_INVALID_MODULE_SPECIFIER(subpath, reason,
+ base && fileURLToPath(base));
}
function throwInvalidPackageTarget(
@@ -307,44 +298,46 @@ function throwInvalidPackageTarget(
}
throw new ERR_INVALID_PACKAGE_TARGET(
fileURLToPath(new URL('.', packageJSONUrl)), subpath, target,
- internal, fileURLToPath(base));
+ internal, base && fileURLToPath(base));
}
+const invalidSegmentRegEx = /(^|\\|\/)(\.\.?|node_modules)(\\|\/|$)/;
+
function resolvePackageTargetString(
target, subpath, match, packageJSONUrl, base, internal, conditions) {
if (subpath !== '' && target[target.length - 1] !== '/')
throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
- if (!target.startsWith('./')) {
- if (internal && !target.startsWith('../') && !target.startsWith('/')) {
+ if (!StringPrototypeStartsWith(target, './')) {
+ if (internal && !StringPrototypeStartsWith(target, '../') &&
+ !StringPrototypeStartsWith(target, '/')) {
let isURL = false;
try {
new URL(target);
isURL = true;
} catch {}
if (!isURL)
- return packageResolve(target + subpath, base, conditions);
+ return packageResolve(target + subpath, packageJSONUrl, conditions);
}
throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
}
+ if (RegExpPrototypeTest(invalidSegmentRegEx, StringPrototypeSlice(target, 2)))
+ throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
+
const resolved = new URL(target, packageJSONUrl);
const resolvedPath = resolved.pathname;
const packagePath = new URL('.', packageJSONUrl).pathname;
- if (!StringPrototypeStartsWith(resolvedPath, packagePath) ||
- StringPrototypeIncludes(
- resolvedPath, '/node_modules/', packagePath.length - 1))
+ if (!StringPrototypeStartsWith(resolvedPath, packagePath))
throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
if (subpath === '') return resolved;
- const subpathResolved = new URL(subpath, resolved);
- const subpathResolvedPath = subpathResolved.pathname;
- if (!StringPrototypeStartsWith(subpathResolvedPath, resolvedPath) ||
- StringPrototypeIncludes(subpathResolvedPath,
- '/node_modules/', packagePath.length - 1))
+
+ if (RegExpPrototypeTest(invalidSegmentRegEx, subpath))
throwInvalidSubpath(match + subpath, packageJSONUrl, internal, base);
- return subpathResolved;
+
+ return new URL(subpath, resolved);
}
/**
@@ -357,12 +350,12 @@ function isArrayIndex(key) {
return keyNum >= 0 && keyNum < 0xFFFF_FFFF;
}
-function resolvePackageTarget(
- packageJSONUrl, target, subpath, packageSubpath, base, internal, conditions) {
+function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
+ base, internal, conditions) {
if (typeof target === 'string') {
- return finalizeResolution(resolvePackageTargetString(
+ return resolvePackageTargetString(
target, subpath, packageSubpath, packageJSONUrl, base, internal,
- conditions), base);
+ conditions);
} else if (ArrayIsArray(target)) {
if (target.length === 0)
return null;
@@ -387,7 +380,7 @@ function resolvePackageTarget(
lastException = null;
continue;
}
- return finalizeResolution(resolved, base);
+ return resolved;
}
if (lastException === undefined || lastException === null)
return lastException;
@@ -398,8 +391,8 @@ function resolvePackageTarget(
const key = keys[i];
if (isArrayIndex(key)) {
throw new ERR_INVALID_PACKAGE_CONFIG(
- fileURLToPath(packageJSONUrl),
- '"exports" cannot contain numeric property keys');
+ fileURLToPath(packageJSONUrl), base,
+ '"exports" cannot contain numeric property keys.');
}
}
for (let i = 0; i < keys.length; i++) {
@@ -436,7 +429,7 @@ function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
isConditionalSugar = curIsConditionalSugar;
} else if (isConditionalSugar !== curIsConditionalSugar) {
throw new ERR_INVALID_PACKAGE_CONFIG(
- fileURLToPath(packageJSONUrl),
+ fileURLToPath(packageJSONUrl), base,
'"exports" cannot contain some keys starting with \'.\' and some not.' +
' The exports object must either be an object of package subpath keys' +
' or an object of main entry condition name keys only.');
@@ -445,44 +438,6 @@ function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
return isConditionalSugar;
}
-function packageMainResolve(packageJSONUrl, packageConfig, base, conditions) {
- if (packageConfig.exists) {
- const exports = packageConfig.exports;
- if (exports !== undefined) {
- if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
- const resolved = resolvePackageTarget(packageJSONUrl, exports, '', '',
- base, false, conditions);
- if (resolved === null || resolved === undefined)
- throwExportsNotFound('.', packageJSONUrl, base);
- return resolved;
- } else if (typeof exports === 'object' && exports !== null) {
- const target = exports['.'];
- if (target !== undefined) {
- const resolved = resolvePackageTarget(packageJSONUrl, target, '', '',
- base, false, conditions);
- if (resolved === null || resolved === undefined)
- throwExportsNotFound('.', packageJSONUrl, base);
- return resolved;
- }
- }
-
- throw new ERR_PACKAGE_PATH_NOT_EXPORTED(packageJSONUrl, '.');
- }
- if (getOptionValue('--experimental-specifier-resolution') === 'node') {
- if (packageConfig.main !== undefined) {
- return finalizeResolution(
- new URL(packageConfig.main, packageJSONUrl), base);
- }
- return finalizeResolution(
- new URL('index', packageJSONUrl), base);
- }
- return legacyMainResolve(packageJSONUrl, packageConfig);
- }
-
- throw new ERR_MODULE_NOT_FOUND(
- fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
-}
-
/**
* @param {URL} packageJSONUrl
* @param {string} packageSubpath
@@ -493,28 +448,27 @@ function packageMainResolve(packageJSONUrl, packageConfig, base, conditions) {
*/
function packageExportsResolve(
packageJSONUrl, packageSubpath, packageConfig, base, conditions) {
- const exports = packageConfig.exports;
- if (exports === undefined ||
- isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
- throwExportsNotFound(packageSubpath, packageJSONUrl, base);
- }
+ let exports = packageConfig.exports;
+ if (isConditionalExportsMainSugar(exports, packageJSONUrl, base))
+ exports = { '.': exports };
if (ObjectPrototypeHasOwnProperty(exports, packageSubpath)) {
const target = exports[packageSubpath];
const resolved = resolvePackageTarget(
- packageJSONUrl, target, '', packageSubpath, base, false, conditions);
+ packageJSONUrl, target, '', packageSubpath, base, false, conditions
+ );
if (resolved === null || resolved === undefined)
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
- return finalizeResolution(resolved, base);
+ return { resolved, exact: true };
}
let bestMatch = '';
const keys = ObjectGetOwnPropertyNames(exports);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
- if (key[key.length - 1] !== '/') continue;
- if (StringPrototypeStartsWith(packageSubpath, key) &&
- key.length > bestMatch.length) {
+ if (key[key.length - 1] === '/' &&
+ StringPrototypeStartsWith(packageSubpath, key) &&
+ key.length > bestMatch.length) {
bestMatch = key;
}
}
@@ -522,18 +476,18 @@ function packageExportsResolve(
if (bestMatch) {
const target = exports[bestMatch];
const subpath = StringPrototypeSubstr(packageSubpath, bestMatch.length);
- const resolved = resolvePackageTarget(
- packageJSONUrl, target, subpath, bestMatch, base, false, conditions);
+ const resolved = resolvePackageTarget(packageJSONUrl, target, subpath,
+ bestMatch, base, false, conditions);
if (resolved === null || resolved === undefined)
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
- return finalizeResolution(resolved, base);
+ return { resolved, exact: false };
}
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
}
-function packageInternalResolve(name, base, conditions) {
- if (name === '#' || name.startsWith('#/')) {
+function packageImportsResolve(name, base, conditions) {
+ if (name === '#' || StringPrototypeStartsWith(name, '#/')) {
const reason = 'is not a valid internal imports specifier name';
throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base));
}
@@ -545,17 +499,18 @@ function packageInternalResolve(name, base, conditions) {
if (imports) {
if (ObjectPrototypeHasOwnProperty(imports, name)) {
const resolved = resolvePackageTarget(
- packageJSONUrl, imports[name], '', name, base, true, conditions);
+ packageJSONUrl, imports[name], '', name, base, true, conditions
+ );
if (resolved !== null)
- return finalizeResolution(resolved, base);
+ return { resolved, exact: true };
} else {
let bestMatch = '';
const keys = ObjectGetOwnPropertyNames(imports);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
- if (key[key.length - 1] !== '/') continue;
- if (StringPrototypeStartsWith(name, key) &&
- key.length > bestMatch.length) {
+ if (key[key.length - 1] === '/' &&
+ StringPrototypeStartsWith(name, key) &&
+ key.length > bestMatch.length) {
bestMatch = key;
}
}
@@ -564,10 +519,9 @@ function packageInternalResolve(name, base, conditions) {
const target = imports[bestMatch];
const subpath = StringPrototypeSubstr(name, bestMatch.length);
const resolved = resolvePackageTarget(
- packageJSONUrl, target, subpath, bestMatch, base, true,
- conditions);
+ packageJSONUrl, target, subpath, bestMatch, base, true, conditions);
if (resolved !== null)
- return finalizeResolution(resolved, base);
+ return { resolved, exact: false };
}
}
}
@@ -617,23 +571,18 @@ function packageResolve(specifier, base, conditions) {
specifier, 'is not a valid package name', fileURLToPath(base));
}
- const packageSubpath = separatorIndex === -1 ?
- '' : '.' + StringPrototypeSlice(specifier, separatorIndex);
+ const packageSubpath = '.' + (separatorIndex === -1 ? '' :
+ StringPrototypeSlice(specifier, separatorIndex));
// ResolveSelf
const packageConfig = getPackageScopeConfig(base, base);
if (packageConfig.exists) {
const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
if (packageConfig.name === packageName &&
- packageConfig.exports !== undefined) {
- if (packageSubpath === './') {
- return new URL('./', packageJSONUrl);
- } else if (packageSubpath === '') {
- return packageMainResolve(packageJSONUrl, packageConfig, base,
- conditions);
- }
+ packageConfig.exports !== undefined && packageConfig.exports !== null) {
return packageExportsResolve(
- packageJSONUrl, packageSubpath, packageConfig, base, conditions);
+ packageJSONUrl, packageSubpath, packageConfig, base, conditions
+ ).resolved;
}
}
@@ -642,7 +591,8 @@ function packageResolve(specifier, base, conditions) {
let packageJSONPath = fileURLToPath(packageJSONUrl);
let lastPath;
do {
- const stat = tryStatSync(removePackageJsonFromPath(packageJSONPath));
+ const stat = tryStatSync(StringPrototypeSlice(packageJSONPath, 0,
+ packageJSONPath.length - 13));
if (!stat.isDirectory()) {
lastPath = packageJSONPath;
packageJSONUrl = new URL((isScoped ?
@@ -654,17 +604,13 @@ function packageResolve(specifier, base, conditions) {
// Package match.
const packageConfig = getPackageConfig(packageJSONPath, base);
- if (packageSubpath === './') {
- return new URL('./', packageJSONUrl);
- } else if (packageSubpath === '') {
- return packageMainResolve(packageJSONUrl, packageConfig, base,
- conditions);
- } else if (packageConfig.exports !== undefined) {
+ if (packageConfig.exports !== undefined && packageConfig.exports !== null)
return packageExportsResolve(
- packageJSONUrl, packageSubpath, packageConfig, base, conditions);
- }
- return finalizeResolution(
- new URL(packageSubpath, packageJSONUrl), base);
+ packageJSONUrl, packageSubpath, packageConfig, base, conditions
+ ).resolved;
+ if (packageSubpath === '.')
+ return legacyMainResolve(packageJSONUrl, packageConfig, base);
+ return new URL(packageSubpath, packageJSONUrl);
// Cross-platform root check.
} while (packageJSONPath.length !== lastPath.length);
@@ -706,12 +652,12 @@ function moduleResolve(specifier, base, conditions) {
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
resolved = new URL(specifier, base);
} else if (specifier[0] === '#') {
- resolved = packageInternalResolve(specifier, base, conditions);
+ ({ resolved } = packageImportsResolve(specifier, base, conditions));
} else {
try {
resolved = new URL(specifier);
} catch {
- return packageResolve(specifier, base, conditions);
+ resolved = packageResolve(specifier, base, conditions);
}
}
return finalizeResolution(resolved, base);
@@ -847,5 +793,6 @@ module.exports = {
defaultResolve,
encodedSepRegEx,
getPackageType,
- packageInternalResolve
+ packageExportsResolve,
+ packageImportsResolve
};