|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"use strict"; |
|
|
|
|
|
|
|
|
const { versions } = require("process"); |
|
|
|
|
|
const AliasFieldPlugin = require("./AliasFieldPlugin"); |
|
|
const AliasPlugin = require("./AliasPlugin"); |
|
|
const AppendPlugin = require("./AppendPlugin"); |
|
|
const ConditionalPlugin = require("./ConditionalPlugin"); |
|
|
const DescriptionFilePlugin = require("./DescriptionFilePlugin"); |
|
|
const DirectoryExistsPlugin = require("./DirectoryExistsPlugin"); |
|
|
const ExportsFieldPlugin = require("./ExportsFieldPlugin"); |
|
|
const ExtensionAliasPlugin = require("./ExtensionAliasPlugin"); |
|
|
const FileExistsPlugin = require("./FileExistsPlugin"); |
|
|
const ImportsFieldPlugin = require("./ImportsFieldPlugin"); |
|
|
const JoinRequestPartPlugin = require("./JoinRequestPartPlugin"); |
|
|
const JoinRequestPlugin = require("./JoinRequestPlugin"); |
|
|
const MainFieldPlugin = require("./MainFieldPlugin"); |
|
|
const ModulesInHierarchicalDirectoriesPlugin = require("./ModulesInHierarchicalDirectoriesPlugin"); |
|
|
const ModulesInRootPlugin = require("./ModulesInRootPlugin"); |
|
|
const NextPlugin = require("./NextPlugin"); |
|
|
const ParsePlugin = require("./ParsePlugin"); |
|
|
const PnpPlugin = require("./PnpPlugin"); |
|
|
const Resolver = require("./Resolver"); |
|
|
const RestrictionsPlugin = require("./RestrictionsPlugin"); |
|
|
const ResultPlugin = require("./ResultPlugin"); |
|
|
const RootsPlugin = require("./RootsPlugin"); |
|
|
const SelfReferencePlugin = require("./SelfReferencePlugin"); |
|
|
const SymlinkPlugin = require("./SymlinkPlugin"); |
|
|
const SyncAsyncFileSystemDecorator = require("./SyncAsyncFileSystemDecorator"); |
|
|
const TryNextPlugin = require("./TryNextPlugin"); |
|
|
const UnsafeCachePlugin = require("./UnsafeCachePlugin"); |
|
|
const UseFilePlugin = require("./UseFilePlugin"); |
|
|
const { PathType, getType } = require("./util/path"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function processPnpApiOption(option) { |
|
|
if ( |
|
|
option === undefined && |
|
|
versions.pnp |
|
|
) { |
|
|
const _findPnpApi = |
|
|
|
|
|
( |
|
|
|
|
|
require("module").findPnpApi |
|
|
); |
|
|
|
|
|
if (_findPnpApi) { |
|
|
return { |
|
|
resolveToUnqualified(request, issuer, opts) { |
|
|
const pnpapi = _findPnpApi(issuer); |
|
|
|
|
|
if (!pnpapi) { |
|
|
|
|
|
return null; |
|
|
} |
|
|
|
|
|
return pnpapi.resolveToUnqualified(request, issuer, opts); |
|
|
}, |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
return option || null; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeAlias(alias) { |
|
|
return typeof alias === "object" && !Array.isArray(alias) && alias !== null |
|
|
? Object.keys(alias).map((key) => { |
|
|
|
|
|
const obj = { name: key, onlyModule: false, alias: alias[key] }; |
|
|
|
|
|
if (/\$$/.test(key)) { |
|
|
obj.onlyModule = true; |
|
|
obj.name = key.slice(0, -1); |
|
|
} |
|
|
|
|
|
return obj; |
|
|
}) |
|
|
: (alias) || []; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function mergeFilteredToArray(array, filter) { |
|
|
|
|
|
const result = []; |
|
|
const set = new Set(array); |
|
|
|
|
|
for (const item of set) { |
|
|
if (filter(item)) { |
|
|
const lastElement = |
|
|
result.length > 0 ? result[result.length - 1] : undefined; |
|
|
if (Array.isArray(lastElement)) { |
|
|
lastElement.push(item); |
|
|
} else { |
|
|
result.push([item]); |
|
|
} |
|
|
} else { |
|
|
result.push(item); |
|
|
} |
|
|
} |
|
|
|
|
|
return result; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function createOptions(options) { |
|
|
const mainFieldsSet = new Set(options.mainFields || ["main"]); |
|
|
|
|
|
const mainFields = []; |
|
|
|
|
|
for (const item of mainFieldsSet) { |
|
|
if (typeof item === "string") { |
|
|
mainFields.push({ |
|
|
name: [item], |
|
|
forceRelative: true, |
|
|
}); |
|
|
} else if (Array.isArray(item)) { |
|
|
mainFields.push({ |
|
|
name: item, |
|
|
forceRelative: true, |
|
|
}); |
|
|
} else { |
|
|
mainFields.push({ |
|
|
name: Array.isArray(item.name) ? item.name : [item.name], |
|
|
forceRelative: item.forceRelative, |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
return { |
|
|
alias: normalizeAlias(options.alias), |
|
|
fallback: normalizeAlias(options.fallback), |
|
|
aliasFields: new Set(options.aliasFields), |
|
|
cachePredicate: |
|
|
options.cachePredicate || |
|
|
function trueFn() { |
|
|
return true; |
|
|
}, |
|
|
cacheWithContext: |
|
|
typeof options.cacheWithContext !== "undefined" |
|
|
? options.cacheWithContext |
|
|
: true, |
|
|
exportsFields: new Set(options.exportsFields || ["exports"]), |
|
|
importsFields: new Set(options.importsFields || ["imports"]), |
|
|
conditionNames: new Set(options.conditionNames), |
|
|
descriptionFiles: [ |
|
|
...new Set(options.descriptionFiles || ["package.json"]), |
|
|
], |
|
|
enforceExtension: |
|
|
options.enforceExtension === undefined |
|
|
? Boolean(options.extensions && options.extensions.includes("")) |
|
|
: options.enforceExtension, |
|
|
extensions: new Set(options.extensions || [".js", ".json", ".node"]), |
|
|
extensionAlias: options.extensionAlias |
|
|
? Object.keys(options.extensionAlias).map((k) => ({ |
|
|
extension: k, |
|
|
alias: (options.extensionAlias)[ |
|
|
k |
|
|
], |
|
|
})) |
|
|
: [], |
|
|
fileSystem: options.useSyncFileSystemCalls |
|
|
? new SyncAsyncFileSystemDecorator( |
|
|
( |
|
|
(options.fileSystem) |
|
|
), |
|
|
) |
|
|
: options.fileSystem, |
|
|
unsafeCache: |
|
|
options.unsafeCache && typeof options.unsafeCache !== "object" |
|
|
? ({}) |
|
|
: options.unsafeCache || false, |
|
|
symlinks: typeof options.symlinks !== "undefined" ? options.symlinks : true, |
|
|
resolver: options.resolver, |
|
|
modules: mergeFilteredToArray( |
|
|
Array.isArray(options.modules) |
|
|
? options.modules |
|
|
: options.modules |
|
|
? [options.modules] |
|
|
: ["node_modules"], |
|
|
(item) => { |
|
|
const type = getType(item); |
|
|
return type === PathType.Normal || type === PathType.Relative; |
|
|
}, |
|
|
), |
|
|
mainFields, |
|
|
mainFiles: new Set(options.mainFiles || ["index"]), |
|
|
plugins: options.plugins || [], |
|
|
pnpApi: processPnpApiOption(options.pnpApi), |
|
|
roots: new Set(options.roots || undefined), |
|
|
fullySpecified: options.fullySpecified || false, |
|
|
resolveToContext: options.resolveToContext || false, |
|
|
preferRelative: options.preferRelative || false, |
|
|
preferAbsolute: options.preferAbsolute || false, |
|
|
restrictions: new Set(options.restrictions), |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports.createResolver = function createResolver(options) { |
|
|
const normalizedOptions = createOptions(options); |
|
|
|
|
|
const { |
|
|
alias, |
|
|
fallback, |
|
|
aliasFields, |
|
|
cachePredicate, |
|
|
cacheWithContext, |
|
|
conditionNames, |
|
|
descriptionFiles, |
|
|
enforceExtension, |
|
|
exportsFields, |
|
|
extensionAlias, |
|
|
importsFields, |
|
|
extensions, |
|
|
fileSystem, |
|
|
fullySpecified, |
|
|
mainFields, |
|
|
mainFiles, |
|
|
modules, |
|
|
plugins: userPlugins, |
|
|
pnpApi, |
|
|
resolveToContext, |
|
|
preferRelative, |
|
|
preferAbsolute, |
|
|
symlinks, |
|
|
unsafeCache, |
|
|
resolver: customResolver, |
|
|
restrictions, |
|
|
roots, |
|
|
} = normalizedOptions; |
|
|
|
|
|
const plugins = [...userPlugins]; |
|
|
|
|
|
const resolver = |
|
|
customResolver || new Resolver(fileSystem, normalizedOptions); |
|
|
|
|
|
|
|
|
|
|
|
resolver.ensureHook("resolve"); |
|
|
resolver.ensureHook("internalResolve"); |
|
|
resolver.ensureHook("newInternalResolve"); |
|
|
resolver.ensureHook("parsedResolve"); |
|
|
resolver.ensureHook("describedResolve"); |
|
|
resolver.ensureHook("rawResolve"); |
|
|
resolver.ensureHook("normalResolve"); |
|
|
resolver.ensureHook("internal"); |
|
|
resolver.ensureHook("rawModule"); |
|
|
resolver.ensureHook("alternateRawModule"); |
|
|
resolver.ensureHook("module"); |
|
|
resolver.ensureHook("resolveAsModule"); |
|
|
resolver.ensureHook("undescribedResolveInPackage"); |
|
|
resolver.ensureHook("resolveInPackage"); |
|
|
resolver.ensureHook("resolveInExistingDirectory"); |
|
|
resolver.ensureHook("relative"); |
|
|
resolver.ensureHook("describedRelative"); |
|
|
resolver.ensureHook("directory"); |
|
|
resolver.ensureHook("undescribedExistingDirectory"); |
|
|
resolver.ensureHook("existingDirectory"); |
|
|
resolver.ensureHook("undescribedRawFile"); |
|
|
resolver.ensureHook("rawFile"); |
|
|
resolver.ensureHook("file"); |
|
|
resolver.ensureHook("finalFile"); |
|
|
resolver.ensureHook("existingFile"); |
|
|
resolver.ensureHook("resolved"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resolver.hooks.newInteralResolve = resolver.hooks.newInternalResolve; |
|
|
|
|
|
|
|
|
for (const { source, resolveOptions } of [ |
|
|
{ source: "resolve", resolveOptions: { fullySpecified } }, |
|
|
{ source: "internal-resolve", resolveOptions: { fullySpecified: false } }, |
|
|
]) { |
|
|
if (unsafeCache) { |
|
|
plugins.push( |
|
|
new UnsafeCachePlugin( |
|
|
source, |
|
|
cachePredicate, |
|
|
(unsafeCache), |
|
|
cacheWithContext, |
|
|
`new-${source}`, |
|
|
), |
|
|
); |
|
|
plugins.push( |
|
|
new ParsePlugin(`new-${source}`, resolveOptions, "parsed-resolve"), |
|
|
); |
|
|
} else { |
|
|
plugins.push(new ParsePlugin(source, resolveOptions, "parsed-resolve")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new DescriptionFilePlugin( |
|
|
"parsed-resolve", |
|
|
descriptionFiles, |
|
|
false, |
|
|
"described-resolve", |
|
|
), |
|
|
); |
|
|
plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve")); |
|
|
|
|
|
|
|
|
plugins.push(new NextPlugin("described-resolve", "raw-resolve")); |
|
|
if (fallback.length > 0) { |
|
|
plugins.push( |
|
|
new AliasPlugin("described-resolve", fallback, "internal-resolve"), |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
if (alias.length > 0) { |
|
|
plugins.push(new AliasPlugin("raw-resolve", alias, "internal-resolve")); |
|
|
} |
|
|
for (const item of aliasFields) { |
|
|
plugins.push(new AliasFieldPlugin("raw-resolve", item, "internal-resolve")); |
|
|
} |
|
|
for (const item of extensionAlias) { |
|
|
plugins.push( |
|
|
new ExtensionAliasPlugin("raw-resolve", item, "normal-resolve"), |
|
|
); |
|
|
} |
|
|
plugins.push(new NextPlugin("raw-resolve", "normal-resolve")); |
|
|
|
|
|
|
|
|
if (preferRelative) { |
|
|
plugins.push(new JoinRequestPlugin("after-normal-resolve", "relative")); |
|
|
} |
|
|
plugins.push( |
|
|
new ConditionalPlugin( |
|
|
"after-normal-resolve", |
|
|
{ module: true }, |
|
|
"resolve as module", |
|
|
false, |
|
|
"raw-module", |
|
|
), |
|
|
); |
|
|
plugins.push( |
|
|
new ConditionalPlugin( |
|
|
"after-normal-resolve", |
|
|
{ internal: true }, |
|
|
"resolve as internal import", |
|
|
false, |
|
|
"internal", |
|
|
), |
|
|
); |
|
|
if (preferAbsolute) { |
|
|
plugins.push(new JoinRequestPlugin("after-normal-resolve", "relative")); |
|
|
} |
|
|
if (roots.size > 0) { |
|
|
plugins.push(new RootsPlugin("after-normal-resolve", roots, "relative")); |
|
|
} |
|
|
if (!preferRelative && !preferAbsolute) { |
|
|
plugins.push(new JoinRequestPlugin("after-normal-resolve", "relative")); |
|
|
} |
|
|
|
|
|
|
|
|
for (const importsField of importsFields) { |
|
|
plugins.push( |
|
|
new ImportsFieldPlugin( |
|
|
"internal", |
|
|
conditionNames, |
|
|
importsField, |
|
|
"relative", |
|
|
"internal-resolve", |
|
|
), |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
for (const exportsField of exportsFields) { |
|
|
plugins.push( |
|
|
new SelfReferencePlugin("raw-module", exportsField, "resolve-as-module"), |
|
|
); |
|
|
} |
|
|
for (const item of modules) { |
|
|
if (Array.isArray(item)) { |
|
|
if (item.includes("node_modules") && pnpApi) { |
|
|
plugins.push( |
|
|
new ModulesInHierarchicalDirectoriesPlugin( |
|
|
"raw-module", |
|
|
item.filter((i) => i !== "node_modules"), |
|
|
"module", |
|
|
), |
|
|
); |
|
|
plugins.push( |
|
|
new PnpPlugin( |
|
|
"raw-module", |
|
|
pnpApi, |
|
|
"undescribed-resolve-in-package", |
|
|
"alternate-raw-module", |
|
|
), |
|
|
); |
|
|
|
|
|
plugins.push( |
|
|
new ModulesInHierarchicalDirectoriesPlugin( |
|
|
"alternate-raw-module", |
|
|
["node_modules"], |
|
|
"module", |
|
|
), |
|
|
); |
|
|
} else { |
|
|
plugins.push( |
|
|
new ModulesInHierarchicalDirectoriesPlugin( |
|
|
"raw-module", |
|
|
item, |
|
|
"module", |
|
|
), |
|
|
); |
|
|
} |
|
|
} else { |
|
|
plugins.push(new ModulesInRootPlugin("raw-module", item, "module")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
plugins.push(new JoinRequestPartPlugin("module", "resolve-as-module")); |
|
|
|
|
|
|
|
|
if (!resolveToContext) { |
|
|
plugins.push( |
|
|
new ConditionalPlugin( |
|
|
"resolve-as-module", |
|
|
{ directory: false, request: "." }, |
|
|
"single file module", |
|
|
true, |
|
|
"undescribed-raw-file", |
|
|
), |
|
|
); |
|
|
} |
|
|
plugins.push( |
|
|
new DirectoryExistsPlugin( |
|
|
"resolve-as-module", |
|
|
"undescribed-resolve-in-package", |
|
|
), |
|
|
); |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new DescriptionFilePlugin( |
|
|
"undescribed-resolve-in-package", |
|
|
descriptionFiles, |
|
|
false, |
|
|
"resolve-in-package", |
|
|
), |
|
|
); |
|
|
plugins.push( |
|
|
new NextPlugin( |
|
|
"after-undescribed-resolve-in-package", |
|
|
"resolve-in-package", |
|
|
), |
|
|
); |
|
|
|
|
|
|
|
|
for (const exportsField of exportsFields) { |
|
|
plugins.push( |
|
|
new ExportsFieldPlugin( |
|
|
"resolve-in-package", |
|
|
conditionNames, |
|
|
exportsField, |
|
|
"relative", |
|
|
), |
|
|
); |
|
|
} |
|
|
plugins.push( |
|
|
new NextPlugin("resolve-in-package", "resolve-in-existing-directory"), |
|
|
); |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new JoinRequestPlugin("resolve-in-existing-directory", "relative"), |
|
|
); |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new DescriptionFilePlugin( |
|
|
"relative", |
|
|
descriptionFiles, |
|
|
true, |
|
|
"described-relative", |
|
|
), |
|
|
); |
|
|
plugins.push(new NextPlugin("after-relative", "described-relative")); |
|
|
|
|
|
|
|
|
if (resolveToContext) { |
|
|
plugins.push(new NextPlugin("described-relative", "directory")); |
|
|
} else { |
|
|
plugins.push( |
|
|
new ConditionalPlugin( |
|
|
"described-relative", |
|
|
{ directory: false }, |
|
|
null, |
|
|
true, |
|
|
"raw-file", |
|
|
), |
|
|
); |
|
|
plugins.push( |
|
|
new ConditionalPlugin( |
|
|
"described-relative", |
|
|
{ fullySpecified: false }, |
|
|
"as directory", |
|
|
true, |
|
|
"directory", |
|
|
), |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new DirectoryExistsPlugin("directory", "undescribed-existing-directory"), |
|
|
); |
|
|
|
|
|
if (resolveToContext) { |
|
|
|
|
|
plugins.push(new NextPlugin("undescribed-existing-directory", "resolved")); |
|
|
} else { |
|
|
|
|
|
plugins.push( |
|
|
new DescriptionFilePlugin( |
|
|
"undescribed-existing-directory", |
|
|
descriptionFiles, |
|
|
false, |
|
|
"existing-directory", |
|
|
), |
|
|
); |
|
|
for (const item of mainFiles) { |
|
|
plugins.push( |
|
|
new UseFilePlugin( |
|
|
"undescribed-existing-directory", |
|
|
item, |
|
|
"undescribed-raw-file", |
|
|
), |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
for (const item of mainFields) { |
|
|
plugins.push( |
|
|
new MainFieldPlugin( |
|
|
"existing-directory", |
|
|
item, |
|
|
"resolve-in-existing-directory", |
|
|
), |
|
|
); |
|
|
} |
|
|
for (const item of mainFiles) { |
|
|
plugins.push( |
|
|
new UseFilePlugin("existing-directory", item, "undescribed-raw-file"), |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new DescriptionFilePlugin( |
|
|
"undescribed-raw-file", |
|
|
descriptionFiles, |
|
|
true, |
|
|
"raw-file", |
|
|
), |
|
|
); |
|
|
plugins.push(new NextPlugin("after-undescribed-raw-file", "raw-file")); |
|
|
|
|
|
|
|
|
plugins.push( |
|
|
new ConditionalPlugin( |
|
|
"raw-file", |
|
|
{ fullySpecified: true }, |
|
|
null, |
|
|
false, |
|
|
"file", |
|
|
), |
|
|
); |
|
|
if (!enforceExtension) { |
|
|
plugins.push(new TryNextPlugin("raw-file", "no extension", "file")); |
|
|
} |
|
|
for (const item of extensions) { |
|
|
plugins.push(new AppendPlugin("raw-file", item, "file")); |
|
|
} |
|
|
|
|
|
|
|
|
if (alias.length > 0) { |
|
|
plugins.push(new AliasPlugin("file", alias, "internal-resolve")); |
|
|
} |
|
|
for (const item of aliasFields) { |
|
|
plugins.push(new AliasFieldPlugin("file", item, "internal-resolve")); |
|
|
} |
|
|
plugins.push(new NextPlugin("file", "final-file")); |
|
|
|
|
|
|
|
|
plugins.push(new FileExistsPlugin("final-file", "existing-file")); |
|
|
|
|
|
|
|
|
if (symlinks) { |
|
|
plugins.push(new SymlinkPlugin("existing-file", "existing-file")); |
|
|
} |
|
|
plugins.push(new NextPlugin("existing-file", "resolved")); |
|
|
} |
|
|
|
|
|
const { resolved } = |
|
|
|
|
|
(resolver.hooks); |
|
|
|
|
|
|
|
|
if (restrictions.size > 0) { |
|
|
plugins.push(new RestrictionsPlugin(resolved, restrictions)); |
|
|
} |
|
|
|
|
|
plugins.push(new ResultPlugin(resolved)); |
|
|
|
|
|
|
|
|
|
|
|
for (const plugin of plugins) { |
|
|
if (typeof plugin === "function") { |
|
|
|
|
|
(plugin).call(resolver, resolver); |
|
|
} else if (plugin) { |
|
|
plugin.apply(resolver); |
|
|
} |
|
|
} |
|
|
|
|
|
return resolver; |
|
|
}; |
|
|
|