Skip to content

Commit

Permalink
module: add some typings to internal/modules/esm/resolve
Browse files Browse the repository at this point in the history
PR-URL: #39504
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
  • Loading branch information
aduh95 authored and danielleadams committed Aug 16, 2021
1 parent 016b7ba commit 4df59bc
Showing 1 changed file with 121 additions and 10 deletions.
131 changes: 121 additions & 10 deletions lib/internal/modules/esm/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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')
Expand Down Expand Up @@ -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)) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -205,19 +249,25 @@ 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}
*/
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) {
Expand Down Expand Up @@ -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];
Expand All @@ -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');
Expand All @@ -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(
Expand Down Expand Up @@ -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)}`;
Expand Down Expand Up @@ -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;
Expand All @@ -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}
*/
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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}
*/
Expand Down Expand Up @@ -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] !== '.';
}
Expand All @@ -734,7 +845,7 @@ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {

/**
* @param {string} specifier
* @param {URL} base
* @param {string | URL | undefined} base
* @param {Set<string>} conditions
* @returns {URL}
*/
Expand Down

0 comments on commit 4df59bc

Please sign in to comment.