source: frontend/node_modules/enhanced-resolve/lib/ResolverFactory.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 24.8 KB
RevLine 
[9af201e]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8// eslint-disable-next-line n/prefer-global/process
9const { versions } = require("process");
10
11const AliasFieldPlugin = require("./AliasFieldPlugin");
12const AliasPlugin = require("./AliasPlugin");
13const AppendPlugin = require("./AppendPlugin");
14const ConditionalPlugin = require("./ConditionalPlugin");
15const DescriptionFilePlugin = require("./DescriptionFilePlugin");
16const DirectoryExistsPlugin = require("./DirectoryExistsPlugin");
17const ExportsFieldPlugin = require("./ExportsFieldPlugin");
18const ExtensionAliasPlugin = require("./ExtensionAliasPlugin");
19const FileExistsPlugin = require("./FileExistsPlugin");
20const ImportsFieldPlugin = require("./ImportsFieldPlugin");
21const JoinRequestPartPlugin = require("./JoinRequestPartPlugin");
22const JoinRequestPlugin = require("./JoinRequestPlugin");
23const MainFieldPlugin = require("./MainFieldPlugin");
24const ModulesInHierarchicalDirectoriesPlugin = require("./ModulesInHierarchicalDirectoriesPlugin");
25const ModulesInRootPlugin = require("./ModulesInRootPlugin");
26const NextPlugin = require("./NextPlugin");
27const ParsePlugin = require("./ParsePlugin");
28const PnpPlugin = require("./PnpPlugin");
29const Resolver = require("./Resolver");
30const RestrictionsPlugin = require("./RestrictionsPlugin");
31const ResultPlugin = require("./ResultPlugin");
32const RootsPlugin = require("./RootsPlugin");
33const SelfReferencePlugin = require("./SelfReferencePlugin");
34const SymlinkPlugin = require("./SymlinkPlugin");
35const SyncAsyncFileSystemDecorator = require("./SyncAsyncFileSystemDecorator");
36const TryNextPlugin = require("./TryNextPlugin");
37const TsconfigPathsPlugin = require("./TsconfigPathsPlugin");
38const UnsafeCachePlugin = require("./UnsafeCachePlugin");
39const UseFilePlugin = require("./UseFilePlugin");
40const { PathType, getType } = require("./util/path");
41
42/** @typedef {import("./AliasPlugin").AliasOption} AliasOptionEntry */
43/** @typedef {import("./ExtensionAliasPlugin").ExtensionAliasOption} ExtensionAliasOption */
44/** @typedef {import("./PnpPlugin").PnpApiImpl} PnpApi */
45/** @typedef {import("./Resolver").EnsuredHooks} EnsuredHooks */
46/** @typedef {import("./Resolver").FileSystem} FileSystem */
47/** @typedef {import("./Resolver").KnownHooks} KnownHooks */
48/** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
49/** @typedef {import("./Resolver").SyncFileSystem} SyncFileSystem */
50/** @typedef {import("./UnsafeCachePlugin").Cache} Cache */
51
52/** @typedef {string | string[] | false} AliasOptionNewRequest */
53/** @typedef {{ [k: string]: AliasOptionNewRequest }} AliasOptions */
54/** @typedef {{ [k: string]: string | string[] }} ExtensionAliasOptions */
55/** @typedef {false | 0 | "" | null | undefined} Falsy */
56/** @typedef {{ apply: (resolver: Resolver) => void } | ((this: Resolver, resolver: Resolver) => void) | Falsy} Plugin */
57
58/**
59 * @typedef {object} TsconfigOptions
60 * @property {string=} configFile A relative path to the tsconfig file based on cwd, or an absolute path of tsconfig file
61 * @property {string[] | "auto"=} references References to other tsconfig files. 'auto' inherits from TypeScript config, or an array of relative/absolute paths
62 * @property {string=} baseUrl Override baseUrl from tsconfig.json. If provided, this value will be used instead of the baseUrl in the tsconfig file
63 */
64
65/**
66 * @typedef {object} UserResolveOptions
67 * @property {(AliasOptions | AliasOptionEntry[])=} alias A list of module alias configurations or an object which maps key to value
68 * @property {(AliasOptions | AliasOptionEntry[])=} fallback A list of module alias configurations or an object which maps key to value, applied only after modules option
69 * @property {ExtensionAliasOptions=} extensionAlias An object which maps extension to extension aliases
70 * @property {boolean=} extensionAliasForExports Also apply `extensionAlias` to paths resolved through the package.json `exports` field. Off by default (Node.js-aligned); when enabled, matches TypeScript's behavior for packages that ship TS sources alongside compiled JS.
71 * @property {(string | string[])[]=} aliasFields A list of alias fields in description files
72 * @property {((predicate: ResolveRequest) => boolean)=} cachePredicate A function which decides whether a request should be cached or not. An object is passed with at least `path` and `request` properties.
73 * @property {boolean=} cacheWithContext Whether or not the unsafeCache should include request context as part of the cache key.
74 * @property {string[]=} descriptionFiles A list of description files to read from
75 * @property {string[]=} conditionNames A list of exports field condition names.
76 * @property {boolean=} enforceExtension Enforce that a extension from extensions must be used
77 * @property {(string | string[])[]=} exportsFields A list of exports fields in description files
78 * @property {(string | string[])[]=} importsFields A list of imports fields in description files
79 * @property {string[]=} extensions A list of extensions which should be tried for files
80 * @property {FileSystem} fileSystem The file system which should be used
81 * @property {(Cache | boolean)=} unsafeCache Use this cache object to unsafely cache the successful requests
82 * @property {boolean=} symlinks Resolve symlinks to their symlinked location
83 * @property {Resolver=} resolver A prepared Resolver to which the plugins are attached
84 * @property {string[] | string=} modules A list of directories to resolve modules from, can be absolute path or folder name
85 * @property {(string | string[] | { name: string | string[], forceRelative: boolean })[]=} mainFields A list of main fields in description files
86 * @property {string[]=} mainFiles A list of main files in directories
87 * @property {Plugin[]=} plugins A list of additional resolve plugins which should be applied
88 * @property {PnpApi | null=} pnpApi A PnP API that should be used - null is "never", undefined is "auto"
89 * @property {string[]=} roots A list of root paths
90 * @property {boolean=} fullySpecified The request is already fully specified and no extensions or directories are resolved for it
91 * @property {boolean=} resolveToContext Resolve to a context instead of a file
92 * @property {(string | RegExp)[]=} restrictions A list of resolve restrictions
93 * @property {boolean=} useSyncFileSystemCalls Use only the sync constraints of the file system calls
94 * @property {boolean=} preferRelative Prefer to resolve module requests as relative requests before falling back to modules
95 * @property {boolean=} preferAbsolute Prefer to resolve server-relative urls as absolute paths before falling back to resolve in roots
96 * @property {string | boolean | TsconfigOptions=} tsconfig TypeScript config file path or config object with configFile and references
97 */
98
99/**
100 * @typedef {object} ResolveOptions
101 * @property {AliasOptionEntry[]} alias alias
102 * @property {AliasOptionEntry[]} fallback fallback
103 * @property {Set<string | string[]>} aliasFields alias fields
104 * @property {ExtensionAliasOption[]} extensionAlias extension alias
105 * @property {boolean} extensionAliasForExports apply extension alias to exports field targets
106 * @property {(predicate: ResolveRequest) => boolean} cachePredicate cache predicate
107 * @property {boolean} cacheWithContext cache with context
108 * @property {Set<string>} conditionNames A list of exports field condition names.
109 * @property {string[]} descriptionFiles description files
110 * @property {boolean} enforceExtension enforce extension
111 * @property {Set<string | string[]>} exportsFields exports fields
112 * @property {Set<string | string[]>} importsFields imports fields
113 * @property {Set<string>} extensions extensions
114 * @property {FileSystem} fileSystem fileSystem
115 * @property {Cache | false} unsafeCache unsafe cache
116 * @property {boolean} symlinks symlinks
117 * @property {Resolver=} resolver resolver
118 * @property {(string | string[])[]} modules modules
119 * @property {{ name: string[], forceRelative: boolean }[]} mainFields main fields
120 * @property {Set<string>} mainFiles main files
121 * @property {Plugin[]} plugins plugins
122 * @property {PnpApi | null} pnpApi pnp API
123 * @property {Set<string>} roots roots
124 * @property {boolean} fullySpecified fully specified
125 * @property {boolean} resolveToContext resolve to context
126 * @property {Set<string | RegExp>} restrictions restrictions
127 * @property {boolean} preferRelative prefer relative
128 * @property {boolean} preferAbsolute prefer absolute
129 * @property {string | boolean | TsconfigOptions} tsconfig tsconfig file path or config object
130 */
131
132/**
133 * @param {PnpApi | null=} option option
134 * @returns {PnpApi | null} processed option
135 */
136function processPnpApiOption(option) {
137 if (
138 option === undefined &&
139 /** @type {NodeJS.ProcessVersions & { pnp: string }} */ versions.pnp
140 ) {
141 const _findPnpApi =
142 /** @type {(issuer: string) => PnpApi | null}} */
143 (
144 // @ts-expect-error maybe nothing
145 require("module").findPnpApi
146 );
147
148 if (_findPnpApi) {
149 return {
150 resolveToUnqualified(request, issuer, opts) {
151 const pnpapi = _findPnpApi(issuer);
152
153 if (!pnpapi) {
154 // Issuer isn't managed by PnP
155 return null;
156 }
157
158 return pnpapi.resolveToUnqualified(request, issuer, opts);
159 },
160 };
161 }
162 }
163
164 return option || null;
165}
166
167/**
168 * @param {AliasOptions | AliasOptionEntry[] | undefined} alias alias
169 * @returns {AliasOptionEntry[]} normalized aliases
170 */
171function normalizeAlias(alias) {
172 return typeof alias === "object" && !Array.isArray(alias) && alias !== null
173 ? Object.keys(alias).map((key) => {
174 /** @type {AliasOptionEntry} */
175 const obj = { name: key, onlyModule: false, alias: alias[key] };
176
177 if (/\$$/.test(key)) {
178 obj.onlyModule = true;
179 obj.name = key.slice(0, -1);
180 }
181
182 return obj;
183 })
184 : /** @type {AliasOptionEntry[]} */ (alias) || [];
185}
186
187/**
188 * Merging filtered elements
189 * @param {string[]} array source array
190 * @param {(item: string) => boolean} filter predicate
191 * @returns {(string | string[])[]} merge result
192 */
193function mergeFilteredToArray(array, filter) {
194 /** @type {(string | string[])[]} */
195 const result = [];
196 const set = new Set(array);
197
198 for (const item of set) {
199 if (filter(item)) {
200 const lastElement =
201 result.length > 0 ? result[result.length - 1] : undefined;
202 if (Array.isArray(lastElement)) {
203 lastElement.push(item);
204 } else {
205 result.push([item]);
206 }
207 } else {
208 result.push(item);
209 }
210 }
211
212 return result;
213}
214
215/**
216 * @param {UserResolveOptions} options input options
217 * @returns {ResolveOptions} output options
218 */
219function createOptions(options) {
220 const mainFieldsSet = new Set(options.mainFields || ["main"]);
221 /** @type {ResolveOptions["mainFields"]} */
222 const mainFields = [];
223
224 for (const item of mainFieldsSet) {
225 if (typeof item === "string") {
226 mainFields.push({
227 name: [item],
228 forceRelative: true,
229 });
230 } else if (Array.isArray(item)) {
231 mainFields.push({
232 name: item,
233 forceRelative: true,
234 });
235 } else {
236 mainFields.push({
237 name: Array.isArray(item.name) ? item.name : [item.name],
238 forceRelative: item.forceRelative,
239 });
240 }
241 }
242
243 return {
244 alias: normalizeAlias(options.alias),
245 fallback: normalizeAlias(options.fallback),
246 aliasFields: new Set(options.aliasFields),
247 cachePredicate:
248 options.cachePredicate ||
249 function trueFn() {
250 return true;
251 },
252 cacheWithContext:
253 typeof options.cacheWithContext !== "undefined"
254 ? options.cacheWithContext
255 : true,
256 exportsFields: new Set(options.exportsFields || ["exports"]),
257 importsFields: new Set(options.importsFields || ["imports"]),
258 conditionNames: new Set(options.conditionNames),
259 descriptionFiles: [
260 ...new Set(options.descriptionFiles || ["package.json"]),
261 ],
262 enforceExtension:
263 options.enforceExtension === undefined
264 ? Boolean(options.extensions && options.extensions.includes(""))
265 : options.enforceExtension,
266 extensions: new Set(options.extensions || [".js", ".json", ".node"]),
267 extensionAlias: options.extensionAlias
268 ? Object.keys(options.extensionAlias).map((k) => ({
269 extension: k,
270 alias: /** @type {ExtensionAliasOptions} */ (options.extensionAlias)[
271 k
272 ],
273 }))
274 : [],
275 extensionAliasForExports: options.extensionAliasForExports || false,
276 fileSystem: options.useSyncFileSystemCalls
277 ? new SyncAsyncFileSystemDecorator(
278 /** @type {SyncFileSystem} */ (
279 /** @type {unknown} */ (options.fileSystem)
280 ),
281 )
282 : options.fileSystem,
283 unsafeCache:
284 options.unsafeCache && typeof options.unsafeCache !== "object"
285 ? /** @type {Cache} */ ({})
286 : options.unsafeCache || false,
287 symlinks: typeof options.symlinks !== "undefined" ? options.symlinks : true,
288 resolver: options.resolver,
289 modules: mergeFilteredToArray(
290 Array.isArray(options.modules)
291 ? options.modules
292 : options.modules
293 ? [options.modules]
294 : ["node_modules"],
295 (item) => {
296 const type = getType(item);
297 return type === PathType.Normal || type === PathType.Relative;
298 },
299 ),
300 mainFields,
301 mainFiles: new Set(options.mainFiles || ["index"]),
302 plugins: options.plugins || [],
303 pnpApi: processPnpApiOption(options.pnpApi),
304 roots: new Set(options.roots || undefined),
305 fullySpecified: options.fullySpecified || false,
306 resolveToContext: options.resolveToContext || false,
307 preferRelative: options.preferRelative || false,
308 preferAbsolute: options.preferAbsolute || false,
309 restrictions: new Set(options.restrictions),
310 tsconfig:
311 typeof options.tsconfig === "undefined" ? false : options.tsconfig,
312 };
313}
314
315/**
316 * @param {UserResolveOptions} options resolve options
317 * @returns {Resolver} created resolver
318 */
319module.exports.createResolver = function createResolver(options) {
320 const normalizedOptions = createOptions(options);
321
322 const {
323 alias,
324 fallback,
325 aliasFields,
326 extensionAliasForExports,
327 cachePredicate,
328 cacheWithContext,
329 conditionNames,
330 descriptionFiles,
331 enforceExtension,
332 exportsFields,
333 extensionAlias,
334 importsFields,
335 extensions,
336 fileSystem,
337 fullySpecified,
338 mainFields,
339 mainFiles,
340 modules,
341 plugins: userPlugins,
342 pnpApi,
343 resolveToContext,
344 preferRelative,
345 preferAbsolute,
346 symlinks,
347 unsafeCache,
348 resolver: customResolver,
349 restrictions,
350 roots,
351 tsconfig,
352 } = normalizedOptions;
353
354 const plugins = [...userPlugins];
355
356 const resolver =
357 customResolver || new Resolver(fileSystem, normalizedOptions);
358
359 // // pipeline ////
360
361 resolver.ensureHook("resolve");
362 resolver.ensureHook("internalResolve");
363 resolver.ensureHook("newInternalResolve");
364 resolver.ensureHook("importsResolve");
365 resolver.ensureHook("parsedResolve");
366 resolver.ensureHook("describedResolve");
367 resolver.ensureHook("rawResolve");
368 resolver.ensureHook("normalResolve");
369 resolver.ensureHook("internal");
370 resolver.ensureHook("rawModule");
371 resolver.ensureHook("alternateRawModule");
372 resolver.ensureHook("module");
373 resolver.ensureHook("resolveAsModule");
374 resolver.ensureHook("undescribedResolveInPackage");
375 resolver.ensureHook("resolveInPackage");
376 resolver.ensureHook("resolveInExistingDirectory");
377 resolver.ensureHook("importsFieldRelative");
378 if (extensionAliasForExports) {
379 resolver.ensureHook("exportsFieldRelative");
380 }
381 resolver.ensureHook("relative");
382 resolver.ensureHook("describedRelative");
383 resolver.ensureHook("directory");
384 resolver.ensureHook("undescribedExistingDirectory");
385 resolver.ensureHook("existingDirectory");
386 resolver.ensureHook("undescribedRawFile");
387 resolver.ensureHook("rawFile");
388 resolver.ensureHook("file");
389 resolver.ensureHook("finalFile");
390 resolver.ensureHook("existingFile");
391 resolver.ensureHook("resolved");
392
393 // TODO remove in next major
394 // cspell:word Interal
395 // Backward-compat
396 // @ts-expect-error
397 resolver.hooks.newInteralResolve = resolver.hooks.newInternalResolve;
398
399 // resolve
400 for (const { source, resolveOptions } of [
401 { source: "resolve", resolveOptions: { fullySpecified } },
402 { source: "internal-resolve", resolveOptions: { fullySpecified: false } },
403 // Entry point for non-relative targets from the imports field.
404 // Sets internal: false to prevent re-entering imports resolution,
405 // aligning with the Node.js ESM spec where PACKAGE_IMPORTS_RESOLVE
406 // does not recursively resolve # specifiers.
407 // https://nodejs.org/api/esm.html#resolution-algorithm-specification
408 {
409 source: "imports-resolve",
410 resolveOptions: { fullySpecified: false, internal: false },
411 },
412 ]) {
413 plugins.push(new ParsePlugin(source, resolveOptions, "parsed-resolve"));
414 }
415
416 // parsed-resolve
417 plugins.push(
418 new DescriptionFilePlugin(
419 "parsed-resolve",
420 descriptionFiles,
421 false,
422 "described-resolve",
423 ),
424 );
425 plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve"));
426
427 // described-resolve
428 if (unsafeCache) {
429 plugins.push(
430 new UnsafeCachePlugin(
431 "described-resolve",
432 cachePredicate,
433 /** @type {import("./UnsafeCachePlugin").Cache} */ (unsafeCache),
434 cacheWithContext,
435 "raw-resolve",
436 ),
437 );
438 } else {
439 plugins.push(new NextPlugin("described-resolve", "raw-resolve"));
440 }
441 if (fallback.length > 0) {
442 plugins.push(
443 new AliasPlugin("described-resolve", fallback, "internal-resolve"),
444 );
445 }
446 // raw-resolve
447 if (alias.length > 0) {
448 plugins.push(new AliasPlugin("raw-resolve", alias, "internal-resolve"));
449 }
450 if (tsconfig) {
451 plugins.push(new TsconfigPathsPlugin(tsconfig));
452 }
453 for (const item of aliasFields) {
454 plugins.push(new AliasFieldPlugin("raw-resolve", item, "internal-resolve"));
455 }
456 for (const item of extensionAlias) {
457 plugins.push(
458 new ExtensionAliasPlugin("raw-resolve", item, "normal-resolve"),
459 );
460 }
461 plugins.push(new NextPlugin("raw-resolve", "normal-resolve"));
462
463 // normal-resolve
464 if (preferRelative) {
465 plugins.push(new JoinRequestPlugin("after-normal-resolve", "relative"));
466 }
467 plugins.push(
468 new ConditionalPlugin(
469 "after-normal-resolve",
470 { module: true },
471 "resolve as module",
472 false,
473 "raw-module",
474 ),
475 );
476 plugins.push(
477 new ConditionalPlugin(
478 "after-normal-resolve",
479 { internal: true },
480 "resolve as internal import",
481 false,
482 "internal",
483 ),
484 );
485 if (preferAbsolute) {
486 plugins.push(new JoinRequestPlugin("after-normal-resolve", "relative"));
487 }
488 if (roots.size > 0) {
489 plugins.push(new RootsPlugin("after-normal-resolve", roots, "relative"));
490 }
491 if (!preferRelative && !preferAbsolute) {
492 plugins.push(new JoinRequestPlugin("after-normal-resolve", "relative"));
493 }
494
495 // internal
496 for (const importsField of importsFields) {
497 plugins.push(
498 new ImportsFieldPlugin(
499 "internal",
500 conditionNames,
501 importsField,
502 "imports-field-relative",
503 "imports-resolve",
504 ),
505 );
506 }
507 // imports-field-relative: apply extensionAlias to paths produced by the
508 // imports field (TypeScript-style extension substitution for self-package
509 // imports like `#foo` -> `./foo.js` -> `./foo.ts`). Unlike the exports
510 // field, the imports field is internal to the package, so applying the
511 // consumer's extension aliases does not expose files the package author
512 // did not intend to export. See issue #413.
513 for (const item of extensionAlias) {
514 plugins.push(
515 new ExtensionAliasPlugin("imports-field-relative", item, "relative"),
516 );
517 }
518 plugins.push(new NextPlugin("imports-field-relative", "relative"));
519
520 // raw-module
521 for (const exportsField of exportsFields) {
522 plugins.push(
523 new SelfReferencePlugin("raw-module", exportsField, "resolve-as-module"),
524 );
525 }
526 for (const item of modules) {
527 if (Array.isArray(item)) {
528 if (item.includes("node_modules") && pnpApi) {
529 plugins.push(
530 new ModulesInHierarchicalDirectoriesPlugin(
531 "raw-module",
532 item.filter((i) => i !== "node_modules"),
533 "module",
534 ),
535 );
536 plugins.push(
537 new PnpPlugin(
538 "raw-module",
539 pnpApi,
540 "undescribed-resolve-in-package",
541 "alternate-raw-module",
542 ),
543 );
544
545 plugins.push(
546 new ModulesInHierarchicalDirectoriesPlugin(
547 "alternate-raw-module",
548 ["node_modules"],
549 "module",
550 ),
551 );
552 } else {
553 plugins.push(
554 new ModulesInHierarchicalDirectoriesPlugin(
555 "raw-module",
556 item,
557 "module",
558 ),
559 );
560 }
561 } else {
562 plugins.push(new ModulesInRootPlugin("raw-module", item, "module"));
563 }
564 }
565
566 // module
567 plugins.push(new JoinRequestPartPlugin("module", "resolve-as-module"));
568
569 // resolve-as-module
570 if (!resolveToContext) {
571 plugins.push(
572 new ConditionalPlugin(
573 "resolve-as-module",
574 { directory: false, request: "." },
575 "single file module",
576 true,
577 "undescribed-raw-file",
578 ),
579 );
580 }
581 plugins.push(
582 new DirectoryExistsPlugin(
583 "resolve-as-module",
584 "undescribed-resolve-in-package",
585 ),
586 );
587
588 // undescribed-resolve-in-package
589 plugins.push(
590 new DescriptionFilePlugin(
591 "undescribed-resolve-in-package",
592 descriptionFiles,
593 false,
594 "resolve-in-package",
595 ),
596 );
597 plugins.push(
598 new NextPlugin(
599 "after-undescribed-resolve-in-package",
600 "resolve-in-package",
601 ),
602 );
603
604 // resolve-in-package
605 const exportsFieldTarget = extensionAliasForExports
606 ? "exports-field-relative"
607 : "relative";
608 for (const exportsField of exportsFields) {
609 plugins.push(
610 new ExportsFieldPlugin(
611 "resolve-in-package",
612 conditionNames,
613 exportsField,
614 exportsFieldTarget,
615 ),
616 );
617 }
618 plugins.push(
619 new NextPlugin("resolve-in-package", "resolve-in-existing-directory"),
620 );
621
622 // exports-field-relative (opt-in via `extensionAliasForExports`):
623 // apply `extensionAlias` to paths produced by the exports field. This is
624 // off by default to match Node.js (which does not substitute extensions on
625 // bare-module targets), and on opt-in aligns with TypeScript for packages
626 // that ship TS sources alongside the compiled JS they list in `exports`.
627 if (extensionAliasForExports) {
628 for (const item of extensionAlias) {
629 plugins.push(
630 new ExtensionAliasPlugin("exports-field-relative", item, "relative"),
631 );
632 }
633 plugins.push(new NextPlugin("exports-field-relative", "relative"));
634 }
635
636 // resolve-in-existing-directory
637 plugins.push(
638 new JoinRequestPlugin("resolve-in-existing-directory", "relative"),
639 );
640
641 // relative
642 plugins.push(
643 new DescriptionFilePlugin(
644 "relative",
645 descriptionFiles,
646 true,
647 "described-relative",
648 ),
649 );
650 plugins.push(new NextPlugin("after-relative", "described-relative"));
651
652 // described-relative
653 if (resolveToContext) {
654 plugins.push(new NextPlugin("described-relative", "directory"));
655 } else {
656 plugins.push(
657 new ConditionalPlugin(
658 "described-relative",
659 { directory: false },
660 null,
661 true,
662 "raw-file",
663 ),
664 );
665 plugins.push(
666 new ConditionalPlugin(
667 "described-relative",
668 { fullySpecified: false },
669 "as directory",
670 true,
671 "directory",
672 ),
673 );
674 }
675
676 // directory
677 plugins.push(
678 new DirectoryExistsPlugin("directory", "undescribed-existing-directory"),
679 );
680
681 if (resolveToContext) {
682 // undescribed-existing-directory
683 plugins.push(new NextPlugin("undescribed-existing-directory", "resolved"));
684 } else {
685 // undescribed-existing-directory
686 plugins.push(
687 new DescriptionFilePlugin(
688 "undescribed-existing-directory",
689 descriptionFiles,
690 false,
691 "existing-directory",
692 ),
693 );
694 for (const item of mainFiles) {
695 plugins.push(
696 new UseFilePlugin(
697 "undescribed-existing-directory",
698 item,
699 "undescribed-raw-file",
700 ),
701 );
702 }
703
704 // described-existing-directory
705 for (const item of mainFields) {
706 plugins.push(
707 new MainFieldPlugin(
708 "existing-directory",
709 item,
710 "resolve-in-existing-directory",
711 ),
712 );
713 }
714 for (const item of mainFiles) {
715 plugins.push(
716 new UseFilePlugin("existing-directory", item, "undescribed-raw-file"),
717 );
718 }
719
720 // undescribed-raw-file
721 plugins.push(
722 new DescriptionFilePlugin(
723 "undescribed-raw-file",
724 descriptionFiles,
725 true,
726 "raw-file",
727 ),
728 );
729 plugins.push(new NextPlugin("after-undescribed-raw-file", "raw-file"));
730
731 // raw-file
732 plugins.push(
733 new ConditionalPlugin(
734 "raw-file",
735 { fullySpecified: true },
736 null,
737 false,
738 "file",
739 ),
740 );
741 if (!enforceExtension) {
742 plugins.push(new TryNextPlugin("raw-file", "no extension", "file"));
743 }
744 for (const item of extensions) {
745 plugins.push(new AppendPlugin("raw-file", item, "file"));
746 }
747
748 // file
749 if (alias.length > 0) {
750 plugins.push(new AliasPlugin("file", alias, "internal-resolve"));
751 }
752 for (const item of aliasFields) {
753 plugins.push(new AliasFieldPlugin("file", item, "internal-resolve"));
754 }
755 plugins.push(new NextPlugin("file", "final-file"));
756
757 // final-file
758 plugins.push(new FileExistsPlugin("final-file", "existing-file"));
759
760 // existing-file
761 if (symlinks) {
762 plugins.push(new SymlinkPlugin("existing-file", "existing-file"));
763 }
764 plugins.push(new NextPlugin("existing-file", "resolved"));
765 }
766
767 const { resolved } =
768 /** @type {KnownHooks & EnsuredHooks} */
769 (resolver.hooks);
770
771 // resolved
772 if (restrictions.size > 0) {
773 plugins.push(new RestrictionsPlugin(resolved, restrictions));
774 }
775
776 plugins.push(new ResultPlugin(resolved));
777
778 // // RESOLVER ////
779
780 for (const plugin of plugins) {
781 if (typeof plugin === "function") {
782 /** @type {(this: Resolver, resolver: Resolver) => void} */
783 (plugin).call(resolver, resolver);
784 } else if (plugin) {
785 plugin.apply(resolver);
786 }
787 }
788
789 return resolver;
790};
Note: See TracBrowser for help on using the repository browser.