mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
module: add some typings to internal/modules/esm/resolve
PR-URL: https://github.com/nodejs/node/pull/39504 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
@@ -59,7 +59,26 @@ const userConditions = getOptionValue('--conditions');
|
||||
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import', ...userConditions]);
|
||||
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
|
||||
|
||||
/**
|
||||
* @typedef {string | string[] | Record<string, unknown>} Exports
|
||||
* @typedef {'module' | 'commonjs'} PackageType
|
||||
* @typedef {{
|
||||
* exports?: ExportConfig;
|
||||
* name?: string;
|
||||
* main?: string;
|
||||
* type?: PackageType;
|
||||
* }} PackageConfig
|
||||
*/
|
||||
|
||||
const emittedPackageWarnings = new SafeSet();
|
||||
|
||||
/**
|
||||
* @param {string} match
|
||||
* @param {URL} pjsonUrl
|
||||
* @param {boolean} isExports
|
||||
* @param {string | URL | undefined} base
|
||||
* @returns {void}
|
||||
*/
|
||||
function emitFolderMapDeprecation(match, pjsonUrl, isExports, base) {
|
||||
const pjsonPath = fileURLToPath(pjsonUrl);
|
||||
|
||||
@@ -76,6 +95,13 @@ function emitFolderMapDeprecation(match, pjsonUrl, isExports, base) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL} url
|
||||
* @param {URL} packageJSONUrl
|
||||
* @param {string | URL | undefined} base
|
||||
* @param {string} main
|
||||
* @returns
|
||||
*/
|
||||
function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
|
||||
const { format } = defaultGetFormat(url);
|
||||
if (format !== 'module')
|
||||
@@ -104,6 +130,10 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} [conditions]
|
||||
* @returns {Set<string>}
|
||||
*/
|
||||
function getConditionsSet(conditions) {
|
||||
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
|
||||
if (!ArrayIsArray(conditions)) {
|
||||
@@ -118,9 +148,19 @@ function getConditionsSet(conditions) {
|
||||
const realpathCache = new SafeMap();
|
||||
const packageJSONCache = new SafeMap(); /* string -> PackageConfig */
|
||||
|
||||
/**
|
||||
* @param {string | URL} path
|
||||
* @returns {import('fs').Stats}
|
||||
*/
|
||||
const tryStatSync =
|
||||
(path) => statSync(path, { throwIfNoEntry: false }) ?? new Stats();
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @param {string} specifier
|
||||
* @param {string | URL | undefined} base
|
||||
* @returns {PackageConfig}
|
||||
*/
|
||||
function getPackageConfig(path, specifier, base) {
|
||||
const existing = packageJSONCache.get(path);
|
||||
if (existing !== undefined) {
|
||||
@@ -173,6 +213,10 @@ function getPackageConfig(path, specifier, base) {
|
||||
return packageConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL | string} resolved
|
||||
* @returns {PackageConfig}
|
||||
*/
|
||||
function getPackageScopeConfig(resolved) {
|
||||
let packageJSONUrl = new URL('./package.json', resolved);
|
||||
while (true) {
|
||||
@@ -205,12 +249,6 @@ function getPackageScopeConfig(resolved) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
@@ -218,6 +256,18 @@ function fileExists(url) {
|
||||
return statSync(url, { throwIfNoEntry: false })?.isFile() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {URL} packageJSONUrl
|
||||
* @param {PackageConfig} packageConfig
|
||||
* @param {string | URL | undefined} base
|
||||
* @returns {URL}
|
||||
*/
|
||||
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
|
||||
let guess;
|
||||
if (packageConfig.main !== undefined) {
|
||||
@@ -259,12 +309,21 @@ function legacyMainResolve(packageJSONUrl, packageConfig, base) {
|
||||
fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL} search
|
||||
* @returns {URL | undefined}
|
||||
*/
|
||||
function resolveExtensionsWithTryExactName(search) {
|
||||
if (fileExists(search)) return search;
|
||||
return resolveExtensions(search);
|
||||
}
|
||||
|
||||
const extensions = ['.js', '.json', '.node', '.mjs'];
|
||||
|
||||
/**
|
||||
* @param {URL} search
|
||||
* @returns {URL | undefined}
|
||||
*/
|
||||
function resolveExtensions(search) {
|
||||
for (let i = 0; i < extensions.length; i++) {
|
||||
const extension = extensions[i];
|
||||
@@ -274,6 +333,10 @@ function resolveExtensions(search) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL} search
|
||||
* @returns {URL | undefined}
|
||||
*/
|
||||
function resolveDirectoryEntry(search) {
|
||||
const dirPath = fileURLToPath(search);
|
||||
const pkgJsonPath = resolve(dirPath, 'package.json');
|
||||
@@ -291,6 +354,11 @@ function resolveDirectoryEntry(search) {
|
||||
}
|
||||
|
||||
const encodedSepRegEx = /%2F|%2C/i;
|
||||
/**
|
||||
* @param {URL} resolved
|
||||
* @param {string | URL | undefined} base
|
||||
* @returns {URL | undefined}
|
||||
*/
|
||||
function finalizeResolution(resolved, base) {
|
||||
if (RegExpPrototypeTest(encodedSepRegEx, resolved.pathname))
|
||||
throw new ERR_INVALID_MODULE_SPECIFIER(
|
||||
@@ -325,18 +393,35 @@ function finalizeResolution(resolved, base) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @param {URL} packageJSONUrl
|
||||
* @param {string | URL | undefined} base
|
||||
*/
|
||||
function throwImportNotDefined(specifier, packageJSONUrl, base) {
|
||||
throw new ERR_PACKAGE_IMPORT_NOT_DEFINED(
|
||||
specifier, packageJSONUrl && fileURLToPath(new URL('.', packageJSONUrl)),
|
||||
fileURLToPath(base));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @param {URL} packageJSONUrl
|
||||
* @param {string | URL | undefined} base
|
||||
*/
|
||||
function throwExportsNotFound(subpath, packageJSONUrl, base) {
|
||||
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
|
||||
fileURLToPath(new URL('.', packageJSONUrl)), subpath,
|
||||
base && fileURLToPath(base));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string | URL} subpath
|
||||
* @param {URL} packageJSONUrl
|
||||
* @param {boolean} internal
|
||||
* @param {string | URL | undefined} base
|
||||
*/
|
||||
function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) {
|
||||
const reason = `request is not a valid subpath for the "${internal ?
|
||||
'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}`;
|
||||
@@ -478,6 +563,13 @@ function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
|
||||
base);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Exports} exports
|
||||
* @param {URL} packageJSONUrl
|
||||
* @param {string | URL | undefined} base
|
||||
* @returns
|
||||
*/
|
||||
function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
|
||||
if (typeof exports === 'string' || ArrayIsArray(exports)) return true;
|
||||
if (typeof exports !== 'object' || exports === null) return false;
|
||||
@@ -504,8 +596,8 @@ function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
|
||||
/**
|
||||
* @param {URL} packageJSONUrl
|
||||
* @param {string} packageSubpath
|
||||
* @param {object} packageConfig
|
||||
* @param {string} base
|
||||
* @param {PackageConfig} packageConfig
|
||||
* @param {string | URL | undefined} base
|
||||
* @param {Set<string>} conditions
|
||||
* @returns {URL}
|
||||
*/
|
||||
@@ -560,6 +652,12 @@ function packageExportsResolve(
|
||||
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string | URL | undefined} base
|
||||
* @param {Set<string>} conditions
|
||||
* @returns
|
||||
*/
|
||||
function packageImportsResolve(name, base, conditions) {
|
||||
if (name === '#' || StringPrototypeStartsWith(name, '#/')) {
|
||||
const reason = 'is not a valid internal imports specifier name';
|
||||
@@ -615,11 +713,20 @@ function packageImportsResolve(name, base, conditions) {
|
||||
throwImportNotDefined(name, packageJSONUrl, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL} url
|
||||
* @returns {PackageType}
|
||||
*/
|
||||
function getPackageType(url) {
|
||||
const packageConfig = getPackageScopeConfig(url);
|
||||
return packageConfig.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @param {string | URL | undefined} base
|
||||
* @returns {{ packageName: string, packageSubpath: string, isScoped: boolean }}
|
||||
*/
|
||||
function parsePackageName(specifier, base) {
|
||||
let separatorIndex = StringPrototypeIndexOf(specifier, '/');
|
||||
let validPackageName = true;
|
||||
@@ -659,7 +766,7 @@ function parsePackageName(specifier, base) {
|
||||
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @param {URL} base
|
||||
* @param {string | URL | undefined} base
|
||||
* @param {Set<string>} conditions
|
||||
* @returns {URL}
|
||||
*/
|
||||
@@ -712,6 +819,10 @@ function packageResolve(specifier, base, conditions) {
|
||||
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isBareSpecifier(specifier) {
|
||||
return specifier[0] && specifier[0] !== '/' && specifier[0] !== '.';
|
||||
}
|
||||
@@ -734,7 +845,7 @@ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
|
||||
|
||||
/**
|
||||
* @param {string} specifier
|
||||
* @param {URL} base
|
||||
* @param {string | URL | undefined} base
|
||||
* @param {Set<string>} conditions
|
||||
* @returns {URL}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user