• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    /* @internal */
3    export function trace(host: ModuleResolutionHost, message: DiagnosticMessage, ...args: any[]): void;
4    export function trace(host: ModuleResolutionHost): void {
5        host.trace!(formatMessage.apply(undefined, arguments));
6    }
7
8    /* @internal */
9    export function isTraceEnabled(compilerOptions: CompilerOptions, host: ModuleResolutionHost): boolean {
10        return !!compilerOptions.traceResolution && host.trace !== undefined;
11    }
12
13    function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExtension | undefined): Resolved | undefined {
14        let packageId: PackageId | undefined;
15        if (r && packageInfo) {
16            const packageJsonContent = packageInfo.contents.packageJsonContent as PackageJson;
17            if (typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string") {
18                packageId = {
19                    name: packageJsonContent.name,
20                    subModuleName: r.path.slice(packageInfo.packageDirectory.length + directorySeparator.length),
21                    version: packageJsonContent.version
22                };
23            }
24        }
25        return r && { path: r.path, extension: r.ext, packageId };
26    }
27
28    function noPackageId(r: PathAndExtension | undefined): Resolved | undefined {
29        return withPackageId(/*packageInfo*/ undefined, r);
30    }
31
32    function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined {
33        if (r) {
34            Debug.assert(r.packageId === undefined);
35            return { path: r.path, ext: r.extension };
36        }
37    }
38
39    /** Result of trying to resolve a module. */
40    interface Resolved {
41        path: string;
42        extension: Extension;
43        packageId: PackageId | undefined;
44        /**
45         * When the resolved is not created from cache, the value is
46         *  - string if it is symbolic link to the resolved `path`
47         *  - undefined if `path` is not a symbolic link
48         * When the resolved is created using value from cache of ResolvedModuleWithFailedLookupLocations, the value is:
49         *  - string if it is symbolic link to the resolved `path`
50         *  - true if `path` is not a symbolic link - this indicates that the `originalPath` calculation is already done and needs to be skipped
51         * Note: This is a file name with preserved original casing, not a normalized `Path`.
52         */
53        originalPath?: string | true;
54    }
55
56    /** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
57    interface PathAndExtension {
58        path: string;
59        // (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.)
60        ext: Extension;
61    }
62
63    /**
64     * Kinds of file that we are currently looking for.
65     * Typically there is one pass with Extensions.TypeScript, then a second pass with Extensions.JavaScript.
66     */
67    enum Extensions {
68        TypeScript, /** '.ts', '.tsx', '.d.ts', '.ets' or '.d.ets' */
69        JavaScript, /** '.js' or '.jsx' */
70        Json,       /** '.json' */
71        TSConfig,   /** '.json' with `tsconfig` used instead of `index` */
72        DtsOnly,    /** Only '.d.ts' */
73        TsOnly,     /** '.[cm]tsx?' but not .d.ts variants */
74    }
75
76    interface PathAndPackageId {
77        readonly fileName: string;
78        readonly packageId: PackageId | undefined;
79    }
80    /** Used with `Extensions.DtsOnly` to extract the path from TypeScript results. */
81    function resolvedTypeScriptOnly(resolved: Resolved | undefined): PathAndPackageId | undefined {
82        if (!resolved) {
83            return undefined;
84        }
85        Debug.assert(extensionIsTS(resolved.extension));
86        return { fileName: resolved.path, packageId: resolved.packageId };
87    }
88
89    function createResolvedModuleWithFailedLookupLocations(
90        resolved: Resolved | undefined,
91        isExternalLibraryImport: boolean | undefined,
92        failedLookupLocations: string[],
93        affectingLocations: string[],
94        diagnostics: Diagnostic[],
95        resultFromCache: ResolvedModuleWithFailedLookupLocations | undefined
96    ): ResolvedModuleWithFailedLookupLocations {
97        if (resultFromCache) {
98            resultFromCache.failedLookupLocations.push(...failedLookupLocations);
99            resultFromCache.affectingLocations.push(...affectingLocations);
100            return resultFromCache;
101        }
102        return {
103            resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
104            failedLookupLocations,
105            affectingLocations,
106            resolutionDiagnostics: diagnostics,
107        };
108    }
109
110    /*@internal*/
111    interface ModuleResolutionState {
112        host: ModuleResolutionHost;
113        compilerOptions: CompilerOptions;
114        traceEnabled: boolean;
115        failedLookupLocations: Push<string>;
116        affectingLocations: Push<string>;
117        resultFromCache?: ResolvedModuleWithFailedLookupLocations;
118        packageJsonInfoCache: PackageJsonInfoCache | undefined;
119        features: NodeResolutionFeatures;
120        conditions: readonly string[];
121        requestContainingDirectory: string | undefined;
122        reportDiagnostic: DiagnosticReporter;
123    }
124
125    /** Just the fields that we use for module resolution. */
126    /*@internal*/
127    interface PackageJsonPathFields {
128        typings?: string;
129        types?: string;
130        typesVersions?: MapLike<MapLike<string[]>>;
131        main?: string;
132        tsconfig?: string;
133        type?: string;
134        imports?: object;
135        exports?: object;
136        name?: string;
137    }
138
139    interface PackageJson extends PackageJsonPathFields {
140        name?: string;
141        version?: string;
142    }
143
144    function readPackageJsonField<TMatch, K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
145    function readPackageJsonField<K extends MatchingKeys<PackageJson, object | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined;
146    function readPackageJsonField<K extends keyof PackageJson>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined {
147        if (!hasProperty(jsonContent, fieldName)) {
148            if (state.traceEnabled) {
149                const message = isOhpm(state.compilerOptions.packageManagerType) ? Diagnostics.oh_package_json5_does_not_have_a_0_field : Diagnostics.package_json_does_not_have_a_0_field;
150                trace(state.host, message, fieldName);
151            }
152            return;
153        }
154        const value = jsonContent[fieldName];
155        if (typeof value !== typeOfTag || value === null) { // eslint-disable-line no-null/no-null
156            if (state.traceEnabled) {
157                // eslint-disable-next-line no-null/no-null
158                trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, typeOfTag, value === null ? "null" : typeof value);
159            }
160            return;
161        }
162        return value;
163    }
164
165    function readPackageJsonPathField<K extends "typings" | "types" | "main" | "tsconfig">(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined {
166        const fileName = readPackageJsonField(jsonContent, fieldName, "string", state);
167        if (fileName === undefined) {
168            return;
169        }
170        if (!fileName) {
171            if (state.traceEnabled) {
172                trace(state.host, Diagnostics.package_json_had_a_falsy_0_field, fieldName);
173            }
174            return;
175        }
176        const path = normalizePath(combinePaths(baseDirectory, fileName));
177        if (state.traceEnabled) {
178            const message = isOhpm(state.compilerOptions.packageManagerType) ? Diagnostics.oh_package_json5_has_0_field_1_that_references_2 : Diagnostics.package_json_has_0_field_1_that_references_2;
179            trace(state.host, message, fieldName, fileName, path);
180        }
181        return path;
182    }
183
184    function readPackageJsonTypesFields(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
185        return readPackageJsonPathField(jsonContent, "typings", baseDirectory, state)
186            || readPackageJsonPathField(jsonContent, "types", baseDirectory, state);
187    }
188
189    function readPackageJsonTSConfigField(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
190        return readPackageJsonPathField(jsonContent, "tsconfig", baseDirectory, state);
191    }
192
193    function readPackageJsonMainField(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
194        return readPackageJsonPathField(jsonContent, "main", baseDirectory, state);
195    }
196
197    function readPackageJsonTypesVersionsField(jsonContent: PackageJson, state: ModuleResolutionState) {
198        const typesVersions = readPackageJsonField(jsonContent, "typesVersions", "object", state);
199        if (typesVersions === undefined) return;
200
201        if (state.traceEnabled) {
202            trace(state.host, Diagnostics.package_json_has_a_typesVersions_field_with_version_specific_path_mappings);
203        }
204
205        return typesVersions;
206    }
207
208    /*@internal*/
209    interface VersionPaths {
210        version: string;
211        paths: MapLike<string[]>;
212    }
213
214    function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: ModuleResolutionState): VersionPaths | undefined {
215        const typesVersions = readPackageJsonTypesVersionsField(jsonContent, state);
216        if (typesVersions === undefined) return;
217
218        if (state.traceEnabled) {
219            for (const key in typesVersions) {
220                if (hasProperty(typesVersions, key) && !VersionRange.tryParse(key)) {
221                    trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, key);
222                }
223            }
224        }
225
226        const result = getPackageJsonTypesVersionsPaths(typesVersions);
227        if (!result) {
228            if (state.traceEnabled) {
229                trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor);
230            }
231            return;
232        }
233
234        const { version: bestVersionKey, paths: bestVersionPaths } = result;
235        if (typeof bestVersionPaths !== "object") {
236            if (state.traceEnabled) {
237                trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "object", typeof bestVersionPaths);
238            }
239            return;
240        }
241
242        return result;
243    }
244
245    let typeScriptVersion: Version | undefined;
246
247    /* @internal */
248    export function getPackageJsonTypesVersionsPaths(typesVersions: MapLike<MapLike<string[]>>) {
249        if (!typeScriptVersion) typeScriptVersion = new Version(version);
250
251        for (const key in typesVersions) {
252            if (!hasProperty(typesVersions, key)) continue;
253
254            const keyRange = VersionRange.tryParse(key);
255            if (keyRange === undefined) {
256                continue;
257            }
258
259            // return the first entry whose range matches the current compiler version.
260            if (keyRange.test(typeScriptVersion)) {
261                return { version: key, paths: typesVersions[key] };
262            }
263        }
264    }
265
266    export function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined {
267        if (options.typeRoots) {
268            return options.typeRoots;
269        }
270
271        let currentDirectory: string | undefined;
272        if (options.configFilePath) {
273            currentDirectory = getDirectoryPath(options.configFilePath);
274        }
275        else if (host.getCurrentDirectory) {
276            currentDirectory = host.getCurrentDirectory();
277        }
278
279        if (currentDirectory !== undefined) {
280            return getDefaultTypeRoots(currentDirectory, host, options.packageManagerType);
281        }
282    }
283
284    /**
285     * Returns the path to every node_modules/@types or oh_modules/@types directory from some ancestor directory.
286     * Returns undefined if there are none.
287     */
288    function getDefaultTypeRoots(currentDirectory: string, host: { directoryExists?: (directoryName: string) => boolean }, packageManagerType?: string): string[] | undefined {
289        const modulesAtTypes = combinePaths(getModuleByPMType(packageManagerType), "@types");
290
291        if (!host.directoryExists) {
292            return [combinePaths(currentDirectory, modulesAtTypes)];
293            // And if it doesn't exist, tough.
294        }
295
296        let typeRoots: string[] | undefined;
297        forEachAncestorDirectory(normalizePath(currentDirectory), directory => {
298            const atTypes = combinePaths(directory, modulesAtTypes);
299            if (host.directoryExists!(atTypes)) {
300                (typeRoots || (typeRoots = [])).push(atTypes);
301            }
302            return undefined;
303        });
304        return typeRoots;
305    }
306
307    function arePathsEqual(path1: string, path2: string, host: ModuleResolutionHost): boolean {
308        const useCaseSensitiveFileNames = typeof host.useCaseSensitiveFileNames === "function" ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames;
309        return comparePaths(path1, path2, !useCaseSensitiveFileNames) === Comparison.EqualTo;
310    }
311
312    /**
313     * @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown.
314     * This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups
315     * is assumed to be the same as root directory of the project.
316     */
317    export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference, cache?: TypeReferenceDirectiveResolutionCache, resolutionMode?: SourceFile["impliedNodeFormat"]): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
318        Debug.assert(typeof typeReferenceDirectiveName === "string", "Non-string value passed to `ts.resolveTypeReferenceDirective`, likely by a wrapping package working with an outdated `resolveTypeReferenceDirectives` signature. This is probably not a problem in TS itself.");
319        const traceEnabled = isTraceEnabled(options, host);
320        if (redirectedReference) {
321            options = redirectedReference.commandLine.options;
322        }
323
324        const containingDirectory = containingFile ? getDirectoryPath(containingFile) : undefined;
325        const perFolderCache = containingDirectory ? cache && cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference) : undefined;
326        let result = perFolderCache && perFolderCache.get(typeReferenceDirectiveName, /*mode*/ resolutionMode);
327        if (result) {
328            if (traceEnabled) {
329                trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1, typeReferenceDirectiveName, containingFile);
330                if (redirectedReference) trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName);
331                trace(host, Diagnostics.Resolution_for_type_reference_directive_0_was_found_in_cache_from_location_1, typeReferenceDirectiveName, containingDirectory);
332                traceResult(result);
333            }
334            return result;
335        }
336
337        const typeRoots = getEffectiveTypeRoots(options, host);
338        if (traceEnabled) {
339            if (containingFile === undefined) {
340                if (typeRoots === undefined) {
341                    trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, typeReferenceDirectiveName);
342                }
343                else {
344                    trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, typeRoots);
345                }
346            }
347            else {
348                if (typeRoots === undefined) {
349                    trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, typeReferenceDirectiveName, containingFile);
350                }
351                else {
352                    trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, typeRoots);
353                }
354            }
355            if (redirectedReference) {
356                trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName);
357            }
358        }
359
360        const failedLookupLocations: string[] = [];
361        const affectingLocations: string[] = [];
362        let features = getDefaultNodeResolutionFeatures(options);
363        // Unlike `import` statements, whose mode-calculating APIs are all guaranteed to return `undefined` if we're in an un-mode-ed module resolution
364        // setting, type references will return their target mode regardless of options because of how the parser works, so we guard against the mode being
365        // set in a non-modal module resolution setting here. Do note that our behavior is not particularly well defined when these mode-overriding imports
366        // are present in a non-modal project; while in theory we'd like to either ignore the mode or provide faithful modern resolution, depending on what we feel is best,
367        // in practice, not every cache has the options available to intelligently make the choice to ignore the mode request, and it's unclear how modern "faithful modern
368        // resolution" should be (`node16`? `nodenext`?). As such, witnessing a mode-overriding triple-slash reference in a non-modal module resolution
369        // context should _probably_ be an error - and that should likely be handled by the `Program` (which is what we do).
370        if (resolutionMode === ModuleKind.ESNext && (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext)) {
371            features |= NodeResolutionFeatures.EsmMode;
372        }
373        const conditions = features & NodeResolutionFeatures.Exports ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] : [];
374        const diagnostics: Diagnostic[] = [];
375        const moduleResolutionState: ModuleResolutionState = {
376            compilerOptions: options,
377            host,
378            traceEnabled,
379            failedLookupLocations,
380            affectingLocations,
381            packageJsonInfoCache: cache,
382            features,
383            conditions,
384            requestContainingDirectory: containingDirectory,
385            reportDiagnostic: diag => void diagnostics.push(diag),
386        };
387        let resolved = primaryLookup();
388        let primary = true;
389        if (!resolved) {
390            resolved = secondaryLookup();
391            primary = false;
392        }
393
394        let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
395        if (resolved) {
396            const { fileName, packageId } = resolved;
397            const resolvedFileName = options.preserveSymlinks ? fileName : realPath(fileName, host, traceEnabled);
398            const pathsAreEqual = arePathsEqual(fileName, resolvedFileName, host);
399            resolvedTypeReferenceDirective = {
400                primary,
401                // If the fileName and realpath are differing only in casing prefer fileName so that we can issue correct errors for casing under forceConsistentCasingInFileNames
402                resolvedFileName: pathsAreEqual ? fileName : resolvedFileName,
403                originalPath: pathsAreEqual ? undefined : fileName,
404                packageId,
405                isExternalLibraryImport: choosePathContainsModules(options.packageManagerType, fileName),
406            };
407        }
408        result = { resolvedTypeReferenceDirective, failedLookupLocations, affectingLocations, resolutionDiagnostics: diagnostics };
409        perFolderCache?.set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result);
410        if (traceEnabled) traceResult(result);
411        return result;
412
413        function traceResult(result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
414            if (!result.resolvedTypeReferenceDirective?.resolvedFileName) {
415                trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
416            }
417            else if (result.resolvedTypeReferenceDirective.packageId) {
418                trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_with_Package_ID_2_primary_Colon_3, typeReferenceDirectiveName, result.resolvedTypeReferenceDirective.resolvedFileName, packageIdToString(result.resolvedTypeReferenceDirective.packageId), result.resolvedTypeReferenceDirective.primary);
419            }
420            else {
421                trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, result.resolvedTypeReferenceDirective.resolvedFileName, result.resolvedTypeReferenceDirective.primary);
422            }
423        }
424
425        function primaryLookup(): PathAndPackageId | undefined {
426            // Check primary library paths
427            if (typeRoots && typeRoots.length) {
428                if (traceEnabled) {
429                    trace(host, Diagnostics.Resolving_with_primary_search_path_0, typeRoots.join(", "));
430                }
431                return firstDefined(typeRoots, typeRoot => {
432                    const candidate = combinePaths(typeRoot, typeReferenceDirectiveName);
433                    const candidateDirectory = getDirectoryPath(candidate);
434                    const directoryExists = directoryProbablyExists(candidateDirectory, host);
435                    if (!directoryExists && traceEnabled) {
436                        trace(host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, candidateDirectory);
437                    }
438                    return resolvedTypeScriptOnly(
439                        loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate,
440                            !directoryExists, moduleResolutionState));
441                });
442            }
443            else {
444                if (traceEnabled) {
445                    trace(host, Diagnostics.Root_directory_cannot_be_determined_skipping_primary_search_paths);
446                }
447            }
448        }
449
450        function secondaryLookup(): PathAndPackageId | undefined {
451            const initialLocationForSecondaryLookup = containingFile && getDirectoryPath(containingFile);
452            const packageManagerType = options.packageManagerType;
453            if (initialLocationForSecondaryLookup !== undefined) {
454                // check secondary locations
455                if (traceEnabled) {
456                    const message = isOhpm(packageManagerType) ? Diagnostics.Looking_up_in_oh_modules_folder_initial_location_0: Diagnostics.Looking_up_in_node_modules_folder_initial_location_0;
457                    trace(host, message, initialLocationForSecondaryLookup);
458                }
459                let result: Resolved | undefined;
460                if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
461                    const searchResult = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined);
462                    result = searchResult && searchResult.value;
463                }
464                else {
465                    const { path: candidate } = normalizePathForCJSResolution(initialLocationForSecondaryLookup, typeReferenceDirectiveName);
466                    result = nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true);
467                }
468                return resolvedTypeScriptOnly(result);
469            }
470            else {
471                if (traceEnabled) {
472                    const message = isOhpm(packageManagerType) ? Diagnostics.Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_oh_modules_folder :
473                      Diagnostics.Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder;
474                    trace(host, message);
475                }
476            }
477        }
478    }
479
480    function getDefaultNodeResolutionFeatures(options: CompilerOptions) {
481        return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 ? NodeResolutionFeatures.Node16Default :
482            getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext ? NodeResolutionFeatures.NodeNextDefault :
483                NodeResolutionFeatures.None;
484    }
485
486    /**
487     * @internal
488     * Does not try `@types/${packageName}` - use a second pass if needed.
489     */
490    export function resolvePackageNameToPackageJson(
491        packageName: string,
492        containingDirectory: string,
493        options: CompilerOptions,
494        host: ModuleResolutionHost,
495        cache: ModuleResolutionCache | undefined,
496    ): PackageJsonInfo | undefined {
497        const moduleResolutionState = getTemporaryModuleResolutionState(cache?.getPackageJsonInfoCache(), host, options);
498
499        return forEachAncestorDirectory(containingDirectory, ancestorDirectory => {
500            if (getBaseFileName(ancestorDirectory) !== "node_modules" && getBaseFileName(ancestorDirectory) !== "oh_modules") {
501                const modulePathPart = getModuleByPMType(options.packageManagerType)
502                const nodeModulesFolder = combinePaths(ancestorDirectory, modulePathPart);
503                const candidate = combinePaths(nodeModulesFolder, packageName);
504                return getPackageJsonInfo(candidate, /*onlyRecordFailures*/ false, moduleResolutionState);
505            }
506        });
507    }
508
509    /**
510     * Given a set of options, returns the set of type directive names
511     *   that should be included for this program automatically.
512     * This list could either come from the config file,
513     *   or from enumerating the types root + initial secondary types lookup location.
514     * More type directives might appear in the program later as a result of loading actual source files;
515     *   this list is only the set of defaults that are implicitly included.
516     */
517    export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: ModuleResolutionHost): string[] {
518        // Use explicit type list from tsconfig.json
519        if (options.types) {
520            return options.types;
521        }
522
523        // Walk the primary type lookup locations
524        const result: string[] = [];
525        if (host.directoryExists && host.getDirectories) {
526            const typeRoots = getEffectiveTypeRoots(options, host);
527            if (typeRoots) {
528                for (const root of typeRoots) {
529                    if (host.directoryExists(root)) {
530                        for (const typeDirectivePath of host.getDirectories(root)) {
531                            const normalized = normalizePath(typeDirectivePath);
532                            const packageJsonPath = combinePaths(root, normalized, getPackageJsonByPMType(options.packageManagerType));
533                            // `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
534                            // See `createNotNeededPackageJSON` in the types-publisher` repo.
535                            // eslint-disable-next-line no-null/no-null
536                            let isNotNeededPackage: boolean;
537                            if (isOhpm(options.packageManagerType)) {
538                                isNotNeededPackage = host.fileExists(packageJsonPath) && require("json5").parse(host.readFile!(packageJsonPath)!).typings === null;
539                            }
540                            else {
541                                isNotNeededPackage = host.fileExists(packageJsonPath) && (readJson(packageJsonPath, host) as PackageJson).typings === null;
542                            }
543                            if (!isNotNeededPackage) {
544                                const baseFileName = getBaseFileName(normalized);
545
546                                // At this stage, skip results with leading dot.
547                                if (baseFileName.charCodeAt(0) !== CharacterCodes.dot) {
548                                    // Return just the type directive names
549                                    result.push(baseFileName);
550                                }
551                            }
552                        }
553                    }
554                }
555            }
556        }
557        return result;
558    }
559
560    export interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>, PackageJsonInfoCache {
561        /*@internal*/ clearAllExceptPackageJsonInfoCache(): void;
562    }
563
564    export interface ModeAwareCache<T> {
565        get(key: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): T | undefined;
566        set(key: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, value: T): this;
567        delete(key: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): this;
568        has(key: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined): boolean;
569        forEach(cb: (elem: T, key: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined) => void): void;
570        size(): number;
571    }
572
573    /**
574     * Cached resolutions per containing directory.
575     * This assumes that any module id will have the same resolution for sibling files located in the same folder.
576     */
577    export interface PerDirectoryResolutionCache<T> {
578        getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache<T>;
579        clear(): void;
580        /**
581         *  Updates with the current compilerOptions the cache will operate with.
582         *  This updates the redirects map as well if needed so module resolutions are cached if they can across the projects
583         */
584        update(options: CompilerOptions): void;
585    }
586
587    export interface ModuleResolutionCache extends PerDirectoryResolutionCache<ResolvedModuleWithFailedLookupLocations>, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache {
588        getPackageJsonInfoCache(): PackageJsonInfoCache;
589        /*@internal*/ clearAllExceptPackageJsonInfoCache(): void;
590    }
591
592    /**
593     * Stored map from non-relative module name to a table: directory -> result of module lookup in this directory
594     * We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive.
595     */
596    export interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache {
597        getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
598    }
599
600    export interface PackageJsonInfoCache {
601        /*@internal*/ getPackageJsonInfo(packageJsonPath: string): PackageJsonInfo | boolean | undefined;
602        /*@internal*/ setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfo | boolean): void;
603        /*@internal*/ entries(): [Path, PackageJsonInfo | boolean][];
604        /*@internal*/ getInternalMap(): ESMap<Path, PackageJsonInfo | boolean> | undefined;
605        clear(): void;
606    }
607
608    export interface PerModuleNameCache {
609        get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined;
610        set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void;
611    }
612
613    /*@internal*/
614    export interface CacheWithRedirects<T> {
615        getOwnMap: () => ESMap<string, T>;
616        redirectsMap: ESMap<Path, ESMap<string, T>>;
617        getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): ESMap<string, T>;
618        clear(): void;
619        setOwnOptions(newOptions: CompilerOptions): void;
620        setOwnMap(newOwnMap: ESMap<string, T>): void;
621    }
622
623    /*@internal*/
624    export function createCacheWithRedirects<T>(options?: CompilerOptions): CacheWithRedirects<T> {
625        let ownMap: ESMap<string, T> = new Map();
626        const redirectsMap = new Map<Path, ESMap<string, T>>();
627        return {
628            getOwnMap,
629            redirectsMap,
630            getOrCreateMapOfCacheRedirects,
631            clear,
632            setOwnOptions,
633            setOwnMap
634        };
635
636        function getOwnMap() {
637            return ownMap;
638        }
639
640        function setOwnOptions(newOptions: CompilerOptions) {
641            options = newOptions;
642        }
643
644        function setOwnMap(newOwnMap: ESMap<string, T>) {
645            ownMap = newOwnMap;
646        }
647
648        function getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined) {
649            if (!redirectedReference) {
650                return ownMap;
651            }
652            const path = redirectedReference.sourceFile.path;
653            let redirects = redirectsMap.get(path);
654            if (!redirects) {
655                // Reuse map if redirected reference map uses same resolution
656                redirects = !options || optionsHaveModuleResolutionChanges(options, redirectedReference.commandLine.options) ? new Map() : ownMap;
657                redirectsMap.set(path, redirects);
658            }
659            return redirects;
660        }
661
662        function clear() {
663            ownMap.clear();
664            redirectsMap.clear();
665        }
666    }
667
668    function createPackageJsonInfoCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): PackageJsonInfoCache {
669        let cache: ESMap<Path, PackageJsonInfo | boolean> | undefined;
670        return { getPackageJsonInfo, setPackageJsonInfo, clear, entries, getInternalMap };
671        function getPackageJsonInfo(packageJsonPath: string) {
672            return cache?.get(toPath(packageJsonPath, currentDirectory, getCanonicalFileName));
673        }
674        function setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfo | boolean) {
675            (cache ||= new Map()).set(toPath(packageJsonPath, currentDirectory, getCanonicalFileName), info);
676        }
677        function clear() {
678            cache = undefined;
679        }
680        function entries() {
681            const iter = cache?.entries();
682            return iter ? arrayFrom(iter) : [];
683        }
684        function getInternalMap() {
685            return cache;
686        }
687    }
688
689    function getOrCreateCache<T>(cacheWithRedirects: CacheWithRedirects<T>, redirectedReference: ResolvedProjectReference | undefined, key: string, create: () => T): T {
690        const cache = cacheWithRedirects.getOrCreateMapOfCacheRedirects(redirectedReference);
691        let result = cache.get(key);
692        if (!result) {
693            result = create();
694            cache.set(key, result);
695        }
696        return result;
697    }
698
699    function updateRedirectsMap<T>(
700        options: CompilerOptions,
701        directoryToModuleNameMap: CacheWithRedirects<ModeAwareCache<T>>,
702        moduleNameToDirectoryMap?: CacheWithRedirects<PerModuleNameCache>
703    ) {
704        if (!options.configFile) return;
705        if (directoryToModuleNameMap.redirectsMap.size === 0) {
706            // The own map will be for projectCompilerOptions
707            Debug.assert(!moduleNameToDirectoryMap || moduleNameToDirectoryMap.redirectsMap.size === 0);
708            Debug.assert(directoryToModuleNameMap.getOwnMap().size === 0);
709            Debug.assert(!moduleNameToDirectoryMap || moduleNameToDirectoryMap.getOwnMap().size === 0);
710            directoryToModuleNameMap.redirectsMap.set(options.configFile.path, directoryToModuleNameMap.getOwnMap());
711            moduleNameToDirectoryMap?.redirectsMap.set(options.configFile.path, moduleNameToDirectoryMap.getOwnMap());
712        }
713        else {
714            // Set correct own map
715            Debug.assert(!moduleNameToDirectoryMap || moduleNameToDirectoryMap.redirectsMap.size > 0);
716            const ref: ResolvedProjectReference = {
717                sourceFile: options.configFile,
718                commandLine: { options } as ParsedCommandLine
719            };
720            directoryToModuleNameMap.setOwnMap(directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(ref));
721            moduleNameToDirectoryMap?.setOwnMap(moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(ref));
722        }
723        directoryToModuleNameMap.setOwnOptions(options);
724        moduleNameToDirectoryMap?.setOwnOptions(options);
725    }
726
727    function createPerDirectoryResolutionCache<T>(currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, directoryToModuleNameMap: CacheWithRedirects<ModeAwareCache<T>>): PerDirectoryResolutionCache<T> {
728        return {
729            getOrCreateCacheForDirectory,
730            clear,
731            update,
732        };
733
734        function clear() {
735            directoryToModuleNameMap.clear();
736        }
737
738        function update(options: CompilerOptions) {
739            updateRedirectsMap(options, directoryToModuleNameMap);
740        }
741
742        function getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference) {
743            const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
744            return getOrCreateCache<ModeAwareCache<T>>(directoryToModuleNameMap, redirectedReference, path, () => createModeAwareCache());
745        }
746    }
747
748    /* @internal */
749    export function createModeAwareCache<T>(): ModeAwareCache<T> {
750        const underlying = new Map<string, T>();
751        const memoizedReverseKeys = new Map<string, [specifier: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined]>();
752
753        const cache: ModeAwareCache<T> = {
754            get(specifier, mode) {
755                return underlying.get(getUnderlyingCacheKey(specifier, mode));
756            },
757            set(specifier, mode, value) {
758                underlying.set(getUnderlyingCacheKey(specifier, mode), value);
759                return cache;
760            },
761            delete(specifier, mode) {
762                underlying.delete(getUnderlyingCacheKey(specifier, mode));
763                return cache;
764            },
765            has(specifier, mode) {
766                return underlying.has(getUnderlyingCacheKey(specifier, mode));
767            },
768            forEach(cb) {
769                return underlying.forEach((elem, key) => {
770                    const [specifier, mode] = memoizedReverseKeys.get(key)!;
771                    return cb(elem, specifier, mode);
772                });
773            },
774            size() {
775                return underlying.size;
776            }
777        };
778        return cache;
779
780        function getUnderlyingCacheKey(specifier: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined) {
781            const result = mode === undefined ? specifier : `${mode}|${specifier}`;
782            memoizedReverseKeys.set(result, [specifier, mode]);
783            return result;
784        }
785    }
786
787    /* @internal */
788    export function zipToModeAwareCache<V>(file: SourceFile, keys: readonly string[] | readonly FileReference[], values: readonly V[]): ModeAwareCache<V> {
789        Debug.assert(keys.length === values.length);
790        const map = createModeAwareCache<V>();
791        for (let i = 0; i < keys.length; ++i) {
792            const entry = keys[i];
793            // We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
794            const name = !isString(entry) ? entry.fileName.toLowerCase() : entry;
795            const mode = !isString(entry) ? entry.resolutionMode || file.impliedNodeFormat : getModeForResolutionAtIndex(file, i);
796            map.set(name, mode, values[i]);
797        }
798        return map;
799    }
800
801    export function createModuleResolutionCache(
802        currentDirectory: string,
803        getCanonicalFileName: (s: string) => string,
804        options?: CompilerOptions
805    ): ModuleResolutionCache;
806    /*@internal*/
807    export function createModuleResolutionCache(
808        currentDirectory: string,
809        getCanonicalFileName: GetCanonicalFileName,
810        options: undefined,
811        directoryToModuleNameMap: CacheWithRedirects<ModeAwareCache<ResolvedModuleWithFailedLookupLocations>>,
812        moduleNameToDirectoryMap: CacheWithRedirects<PerModuleNameCache>,
813    ): ModuleResolutionCache;
814    export function createModuleResolutionCache(
815        currentDirectory: string,
816        getCanonicalFileName: GetCanonicalFileName,
817        options?: CompilerOptions,
818        directoryToModuleNameMap?: CacheWithRedirects<ModeAwareCache<ResolvedModuleWithFailedLookupLocations>>,
819        moduleNameToDirectoryMap?: CacheWithRedirects<PerModuleNameCache>,
820    ): ModuleResolutionCache {
821        const perDirectoryResolutionCache = createPerDirectoryResolutionCache(currentDirectory, getCanonicalFileName, directoryToModuleNameMap ||= createCacheWithRedirects(options));
822        moduleNameToDirectoryMap ||= createCacheWithRedirects(options);
823        const packageJsonInfoCache = createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
824
825        return {
826            ...packageJsonInfoCache,
827            ...perDirectoryResolutionCache,
828            getOrCreateCacheForModuleName,
829            clear,
830            update,
831            getPackageJsonInfoCache: () => packageJsonInfoCache,
832            clearAllExceptPackageJsonInfoCache,
833        };
834
835        function clear() {
836            clearAllExceptPackageJsonInfoCache();
837            packageJsonInfoCache.clear();
838        }
839
840        function clearAllExceptPackageJsonInfoCache() {
841            perDirectoryResolutionCache.clear();
842            moduleNameToDirectoryMap!.clear();
843        }
844
845        function update(options: CompilerOptions) {
846            updateRedirectsMap(options, directoryToModuleNameMap!, moduleNameToDirectoryMap);
847        }
848
849        function getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ModuleKind.CommonJS | ModuleKind.ESNext | undefined, redirectedReference?: ResolvedProjectReference): PerModuleNameCache {
850            Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
851            return getOrCreateCache(moduleNameToDirectoryMap!, redirectedReference, mode === undefined ? nonRelativeModuleName : `${mode}|${nonRelativeModuleName}`, createPerModuleNameCache);
852        }
853
854        function createPerModuleNameCache(): PerModuleNameCache {
855            const directoryPathMap = new Map<string, ResolvedModuleWithFailedLookupLocations>();
856
857            return { get, set };
858
859            function get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined {
860                return directoryPathMap.get(toPath(directory, currentDirectory, getCanonicalFileName));
861            }
862
863            /**
864             * At first this function add entry directory -> module resolution result to the table.
865             * Then it computes the set of parent folders for 'directory' that should have the same module resolution result
866             * and for every parent folder in set it adds entry: parent -> module resolution. .
867             * Lets say we first directory name: /a/b/c/d/e and resolution result is: /a/b/bar.ts.
868             * Set of parent folders that should have the same result will be:
869             * [
870             *     /a/b/c/d, /a/b/c, /a/b
871             * ]
872             * this means that request for module resolution from file in any of these folder will be immediately found in cache.
873             */
874            function set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void {
875                const path = toPath(directory, currentDirectory, getCanonicalFileName);
876                // if entry is already in cache do nothing
877                if (directoryPathMap.has(path)) {
878                    return;
879                }
880                directoryPathMap.set(path, result);
881
882                const resolvedFileName = result.resolvedModule &&
883                    (result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName);
884                // find common prefix between directory and resolved file name
885                // this common prefix should be the shortest path that has the same resolution
886                // directory: /a/b/c/d/e
887                // resolvedFileName: /a/b/foo.d.ts
888                // commonPrefix: /a/b
889                // for failed lookups cache the result for every directory up to root
890                const commonPrefix = resolvedFileName && getCommonPrefix(path, resolvedFileName);
891                let current = path;
892                while (current !== commonPrefix) {
893                    const parent = getDirectoryPath(current);
894                    if (parent === current || directoryPathMap.has(parent)) {
895                        break;
896                    }
897                    directoryPathMap.set(parent, result);
898                    current = parent;
899                }
900            }
901
902            function getCommonPrefix(directory: Path, resolution: string) {
903                const resolutionDirectory = toPath(getDirectoryPath(resolution), currentDirectory, getCanonicalFileName);
904
905                // find first position where directory and resolution differs
906                let i = 0;
907                const limit = Math.min(directory.length, resolutionDirectory.length);
908                while (i < limit && directory.charCodeAt(i) === resolutionDirectory.charCodeAt(i)) {
909                    i++;
910                }
911                if (i === directory.length && (resolutionDirectory.length === i || resolutionDirectory[i] === directorySeparator)) {
912                    return directory;
913                }
914                const rootLength = getRootLength(directory);
915                if (i < rootLength) {
916                    return undefined;
917                }
918                const sep = directory.lastIndexOf(directorySeparator, i - 1);
919                if (sep === -1) {
920                    return undefined;
921                }
922                return directory.substr(0, Math.max(sep, rootLength));
923            }
924        }
925    }
926
927    export function createTypeReferenceDirectiveResolutionCache(
928        currentDirectory: string,
929        getCanonicalFileName: (s: string) => string,
930        options?: CompilerOptions,
931        packageJsonInfoCache?: PackageJsonInfoCache,
932    ): TypeReferenceDirectiveResolutionCache;
933    /*@internal*/
934    export function createTypeReferenceDirectiveResolutionCache(
935        currentDirectory: string,
936        getCanonicalFileName: GetCanonicalFileName,
937        options: undefined,
938        packageJsonInfoCache: PackageJsonInfoCache | undefined,
939        directoryToModuleNameMap: CacheWithRedirects<ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>,
940    ): TypeReferenceDirectiveResolutionCache;
941    export function createTypeReferenceDirectiveResolutionCache(
942        currentDirectory: string,
943        getCanonicalFileName: GetCanonicalFileName,
944        options?: CompilerOptions,
945        packageJsonInfoCache?: PackageJsonInfoCache | undefined,
946        directoryToModuleNameMap?: CacheWithRedirects<ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>,
947    ): TypeReferenceDirectiveResolutionCache {
948        const perDirectoryResolutionCache = createPerDirectoryResolutionCache(currentDirectory, getCanonicalFileName, directoryToModuleNameMap ||= createCacheWithRedirects(options));
949        packageJsonInfoCache ||= createPackageJsonInfoCache(currentDirectory, getCanonicalFileName);
950
951        return {
952            ...packageJsonInfoCache,
953            ...perDirectoryResolutionCache,
954            clear,
955            clearAllExceptPackageJsonInfoCache,
956        };
957
958        function clear() {
959            clearAllExceptPackageJsonInfoCache();
960            packageJsonInfoCache!.clear();
961        }
962
963        function clearAllExceptPackageJsonInfoCache() {
964            perDirectoryResolutionCache.clear();
965        }
966    }
967
968    export function resolveModuleNameFromCache(moduleName: string, containingFile: string, cache: ModuleResolutionCache, mode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations | undefined {
969        const containingDirectory = getDirectoryPath(containingFile);
970        const perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory);
971        if (!perFolderCache) return undefined;
972        return perFolderCache.get(moduleName, mode);
973    }
974
975    export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations {
976        const traceEnabled = isTraceEnabled(compilerOptions, host);
977        if (redirectedReference) {
978            compilerOptions = redirectedReference.commandLine.options;
979        }
980        if (traceEnabled) {
981            trace(host, Diagnostics.Resolving_module_0_from_1, moduleName, containingFile);
982            if (redirectedReference) {
983                trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName);
984            }
985        }
986        const containingDirectory = getDirectoryPath(containingFile);
987        const perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory, redirectedReference);
988        let result = perFolderCache && perFolderCache.get(moduleName, resolutionMode);
989
990        if (result) {
991            if (traceEnabled) {
992                trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
993            }
994        }
995        else {
996            let moduleResolution = compilerOptions.moduleResolution;
997            if (moduleResolution === undefined) {
998                switch (getEmitModuleKind(compilerOptions)) {
999                    case ModuleKind.CommonJS:
1000                        moduleResolution = ModuleResolutionKind.NodeJs;
1001                        break;
1002                    case ModuleKind.Node16:
1003                        moduleResolution = ModuleResolutionKind.Node16;
1004                        break;
1005                    case ModuleKind.NodeNext:
1006                        moduleResolution = ModuleResolutionKind.NodeNext;
1007                        break;
1008                    default:
1009                        moduleResolution = ModuleResolutionKind.Classic;
1010                        break;
1011                }
1012                if (traceEnabled) {
1013                    trace(host, Diagnostics.Module_resolution_kind_is_not_specified_using_0, ModuleResolutionKind[moduleResolution]);
1014                }
1015            }
1016            else {
1017                if (traceEnabled) {
1018                    trace(host, Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, ModuleResolutionKind[moduleResolution]);
1019                }
1020            }
1021
1022            perfLogger.logStartResolveModule(moduleName /* , containingFile, ModuleResolutionKind[moduleResolution]*/);
1023            switch (moduleResolution) {
1024                case ModuleResolutionKind.Node16:
1025                    result = node16ModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode);
1026                    break;
1027                case ModuleResolutionKind.NodeNext:
1028                    result = nodeNextModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode);
1029                    break;
1030                case ModuleResolutionKind.NodeJs:
1031                    result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
1032                    break;
1033                case ModuleResolutionKind.Classic:
1034                    result = classicNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
1035                    break;
1036                default:
1037                    return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`);
1038            }
1039            if (result && result.resolvedModule) perfLogger.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`);
1040            perfLogger.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null");
1041
1042            if (perFolderCache) {
1043                perFolderCache.set(moduleName, resolutionMode, result);
1044                if (!isExternalModuleNameRelative(moduleName)) {
1045                    // put result in per-module name cache
1046                    cache.getOrCreateCacheForModuleName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result);
1047                }
1048            }
1049        }
1050
1051        if (traceEnabled) {
1052            if (result.resolvedModule) {
1053                if (result.resolvedModule.packageId) {
1054                    trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1_with_Package_ID_2, moduleName, result.resolvedModule.resolvedFileName, packageIdToString(result.resolvedModule.packageId));
1055                }
1056                else {
1057                    trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1, moduleName, result.resolvedModule.resolvedFileName);
1058                }
1059            }
1060            else {
1061                trace(host, Diagnostics.Module_name_0_was_not_resolved, moduleName);
1062            }
1063        }
1064
1065        return result;
1066    }
1067
1068    /*
1069     * Every module resolution kind can has its specific understanding how to load module from a specific path on disk
1070     * I.e. for path '/a/b/c':
1071     * - Node loader will first to try to check if '/a/b/c' points to a file with some supported extension and if this fails
1072     * it will try to load module from directory: directory '/a/b/c' should exist and it should have either 'package.json' with
1073     * 'typings' entry or file 'index' with some supported extension
1074     * - Classic loader will only try to interpret '/a/b/c' as file.
1075     */
1076    type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
1077
1078    /**
1079     * Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to
1080     * mitigate differences between design time structure of the project and its runtime counterpart so the same import name
1081     * can be resolved successfully by TypeScript compiler and runtime module loader.
1082     * If these settings are set then loading procedure will try to use them to resolve module name and it can of failure it will
1083     * fallback to standard resolution routine.
1084     *
1085     * - baseUrl - this setting controls how non-relative module names are resolved. If this setting is specified then non-relative
1086     * names will be resolved relative to baseUrl: i.e. if baseUrl is '/a/b' then candidate location to resolve module name 'c/d' will
1087     * be '/a/b/c/d'
1088     * - paths - this setting can only be used when baseUrl is specified. allows to tune how non-relative module names
1089     * will be resolved based on the content of the module name.
1090     * Structure of 'paths' compiler options
1091     * 'paths': {
1092     *    pattern-1: [...substitutions],
1093     *    pattern-2: [...substitutions],
1094     *    ...
1095     *    pattern-n: [...substitutions]
1096     * }
1097     * Pattern here is a string that can contain zero or one '*' character. During module resolution module name will be matched against
1098     * all patterns in the list. Matching for patterns that don't contain '*' means that module name must be equal to pattern respecting the case.
1099     * If pattern contains '*' then to match pattern "<prefix>*<suffix>" module name must start with the <prefix> and end with <suffix>.
1100     * <MatchedStar> denotes part of the module name between <prefix> and <suffix>.
1101     * If module name can be matches with multiple patterns then pattern with the longest prefix will be picked.
1102     * After selecting pattern we'll use list of substitutions to get candidate locations of the module and the try to load module
1103     * from the candidate location.
1104     * Substitution is a string that can contain zero or one '*'. To get candidate location from substitution we'll pick every
1105     * substitution in the list and replace '*' with <MatchedStar> string. If candidate location is not rooted it
1106     * will be converted to absolute using baseUrl.
1107     * For example:
1108     * baseUrl: /a/b/c
1109     * "paths": {
1110     *     // match all module names
1111     *     "*": [
1112     *         "*",        // use matched name as is,
1113     *                     // <matched name> will be looked as /a/b/c/<matched name>
1114     *
1115     *         "folder1/*" // substitution will convert matched name to 'folder1/<matched name>',
1116     *                     // since it is not rooted then final candidate location will be /a/b/c/folder1/<matched name>
1117     *     ],
1118     *     // match module names that start with 'components/'
1119     *     "components/*": [ "/root/components/*" ] // substitution will convert /components/folder1/<matched name> to '/root/components/folder1/<matched name>',
1120     *                                              // it is rooted so it will be final candidate location
1121     * }
1122     *
1123     * 'rootDirs' allows the project to be spreaded across multiple locations and resolve modules with relative names as if
1124     * they were in the same location. For example lets say there are two files
1125     * '/local/src/content/file1.ts'
1126     * '/shared/components/contracts/src/content/protocols/file2.ts'
1127     * After bundling content of '/shared/components/contracts/src' will be merged with '/local/src' so
1128     * if file1 has the following import 'import {x} from "./protocols/file2"' it will be resolved successfully in runtime.
1129     * 'rootDirs' provides the way to tell compiler that in order to get the whole project it should behave as if content of all
1130     * root dirs were merged together.
1131     * I.e. for the example above 'rootDirs' will have two entries: [ '/local/src', '/shared/components/contracts/src' ].
1132     * Compiler will first convert './protocols/file2' into absolute path relative to the location of containing file:
1133     * '/local/src/content/protocols/file2' and try to load it - failure.
1134     * Then it will search 'rootDirs' looking for a longest matching prefix of this absolute path and if such prefix is found - absolute path will
1135     * be converted to a path relative to found rootDir entry './content/protocols/file2' (*). As a last step compiler will check all remaining
1136     * entries in 'rootDirs', use them to build absolute path out of (*) and try to resolve module from this location.
1137     */
1138    function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
1139        state: ModuleResolutionState): Resolved | undefined {
1140
1141        const resolved = tryLoadModuleUsingPathsIfEligible(extensions, moduleName, loader, state);
1142        if (resolved) return resolved.value;
1143
1144        if (!isExternalModuleNameRelative(moduleName)) {
1145            return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
1146        }
1147        else {
1148            return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, state);
1149        }
1150    }
1151
1152    function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) {
1153        const { baseUrl, paths, configFile } = state.compilerOptions;
1154        if (paths && !pathIsRelative(moduleName)) {
1155            if (state.traceEnabled) {
1156                if (baseUrl) {
1157                    trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
1158                }
1159                trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
1160            }
1161            const baseDirectory = getPathsBasePath(state.compilerOptions, state.host)!; // Always defined when 'paths' is defined
1162            const pathPatterns = configFile?.configFileSpecs ? configFile.configFileSpecs.pathPatterns ||= tryParsePatterns(paths) : undefined;
1163            return tryLoadModuleUsingPaths(extensions, moduleName, baseDirectory, paths, pathPatterns, loader, /*onlyRecordFailures*/ false, state);
1164        }
1165    }
1166
1167    function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
1168        state: ModuleResolutionState): Resolved | undefined {
1169
1170        if (!state.compilerOptions.rootDirs) {
1171            return undefined;
1172        }
1173
1174        if (state.traceEnabled) {
1175            trace(state.host, Diagnostics.rootDirs_option_is_set_using_it_to_resolve_relative_module_name_0, moduleName);
1176        }
1177
1178        const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
1179
1180        let matchedRootDir: string | undefined;
1181        let matchedNormalizedPrefix: string | undefined;
1182        for (const rootDir of state.compilerOptions.rootDirs) {
1183            // rootDirs are expected to be absolute
1184            // in case of tsconfig.json this will happen automatically - compiler will expand relative names
1185            // using location of tsconfig.json as base location
1186            let normalizedRoot = normalizePath(rootDir);
1187            if (!endsWith(normalizedRoot, directorySeparator)) {
1188                normalizedRoot += directorySeparator;
1189            }
1190            const isLongestMatchingPrefix =
1191                startsWith(candidate, normalizedRoot) &&
1192                (matchedNormalizedPrefix === undefined || matchedNormalizedPrefix.length < normalizedRoot.length);
1193
1194            if (state.traceEnabled) {
1195                trace(state.host, Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, normalizedRoot, candidate, isLongestMatchingPrefix);
1196            }
1197
1198            if (isLongestMatchingPrefix) {
1199                matchedNormalizedPrefix = normalizedRoot;
1200                matchedRootDir = rootDir;
1201            }
1202        }
1203        if (matchedNormalizedPrefix) {
1204            if (state.traceEnabled) {
1205                trace(state.host, Diagnostics.Longest_matching_prefix_for_0_is_1, candidate, matchedNormalizedPrefix);
1206            }
1207            const suffix = candidate.substr(matchedNormalizedPrefix.length);
1208
1209            // first - try to load from a initial location
1210            if (state.traceEnabled) {
1211                trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, matchedNormalizedPrefix, candidate);
1212            }
1213            const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(containingDirectory, state.host), state);
1214            if (resolvedFileName) {
1215                return resolvedFileName;
1216            }
1217
1218            if (state.traceEnabled) {
1219                trace(state.host, Diagnostics.Trying_other_entries_in_rootDirs);
1220            }
1221            // then try to resolve using remaining entries in rootDirs
1222            for (const rootDir of state.compilerOptions.rootDirs) {
1223                if (rootDir === matchedRootDir) {
1224                    // skip the initially matched entry
1225                    continue;
1226                }
1227                const candidate = combinePaths(normalizePath(rootDir), suffix);
1228                if (state.traceEnabled) {
1229                    trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, rootDir, candidate);
1230                }
1231                const baseDirectory = getDirectoryPath(candidate);
1232                const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(baseDirectory, state.host), state);
1233                if (resolvedFileName) {
1234                    return resolvedFileName;
1235                }
1236            }
1237            if (state.traceEnabled) {
1238                trace(state.host, Diagnostics.Module_resolution_using_rootDirs_has_failed);
1239            }
1240        }
1241        return undefined;
1242    }
1243
1244    function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
1245        const { baseUrl } = state.compilerOptions;
1246        if (!baseUrl) {
1247            return undefined;
1248        }
1249        if (state.traceEnabled) {
1250            trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
1251        }
1252        const candidate = normalizePath(combinePaths(baseUrl, moduleName));
1253        if (state.traceEnabled) {
1254            trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);
1255        }
1256        return loader(extensions, candidate, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
1257    }
1258
1259    /**
1260     * Expose resolution logic to allow us to use Node module resolution logic from arbitrary locations.
1261     * No way to do this with `require()`: https://github.com/nodejs/node/issues/5963
1262     * Throws an error if the module can't be resolved.
1263     */
1264    /* @internal */
1265    export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
1266        const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host);
1267        if (!resolvedModule) {
1268            throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
1269        }
1270        return resolvedModule.resolvedFileName;
1271    }
1272
1273    /* @internal */
1274    enum NodeResolutionFeatures {
1275        None = 0,
1276        // resolving `#local` names in your own package.json
1277        Imports = 1 << 1,
1278        // resolving `your-own-name` from your own package.json
1279        SelfName = 1 << 2,
1280        // respecting the `.exports` member of packages' package.json files and its (conditional) mappings of export names
1281        Exports = 1 << 3,
1282        // allowing `*` in the LHS of an export to be followed by more content, eg `"./whatever/*.js"`
1283        // not supported in node 12 - https://github.com/nodejs/Release/issues/690
1284        ExportsPatternTrailers = 1 << 4,
1285        AllFeatures = Imports | SelfName | Exports | ExportsPatternTrailers,
1286
1287        Node16Default = Imports | SelfName | Exports | ExportsPatternTrailers,
1288
1289        NodeNextDefault = AllFeatures,
1290
1291        EsmMode = 1 << 5,
1292    }
1293
1294    function node16ModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions,
1295            host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference,
1296            resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations {
1297        return nodeNextModuleNameResolverWorker(
1298            NodeResolutionFeatures.Node16Default,
1299            moduleName,
1300            containingFile,
1301            compilerOptions,
1302            host,
1303            cache,
1304            redirectedReference,
1305            resolutionMode
1306        );
1307    }
1308
1309    function nodeNextModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions,
1310            host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference,
1311            resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations {
1312        return nodeNextModuleNameResolverWorker(
1313            NodeResolutionFeatures.NodeNextDefault,
1314            moduleName,
1315            containingFile,
1316            compilerOptions,
1317            host,
1318            cache,
1319            redirectedReference,
1320            resolutionMode
1321        );
1322    }
1323
1324    const jsOnlyExtensions = [Extensions.JavaScript];
1325    const tsExtensions = [Extensions.TypeScript, Extensions.JavaScript];
1326    const tsPlusJsonExtensions = [...tsExtensions, Extensions.Json];
1327    const tsconfigExtensions = [Extensions.TSConfig];
1328    function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations {
1329        const containingDirectory = getDirectoryPath(containingFile);
1330
1331        // es module file or cjs-like input file, use a variant of the legacy cjs resolver that supports the selected modern features
1332        const esmMode = resolutionMode === ModuleKind.ESNext ? NodeResolutionFeatures.EsmMode : 0;
1333        let extensions = compilerOptions.noDtsResolution ? [Extensions.TsOnly, Extensions.JavaScript] : tsExtensions;
1334        if (compilerOptions.resolveJsonModule) {
1335            extensions = [...extensions, Extensions.Json];
1336        }
1337        return nodeModuleNameResolverWorker(features | esmMode, moduleName, containingDirectory, compilerOptions, host, cache, extensions, redirectedReference);
1338    }
1339
1340    function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
1341        return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, jsOnlyExtensions, /*redirectedReferences*/ undefined);
1342    }
1343
1344    export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
1345    /* @internal */ export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures
1346    export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations {
1347        let extensions;
1348        if (lookupConfig) {
1349            extensions = tsconfigExtensions;
1350        }
1351        else if (compilerOptions.noDtsResolution) {
1352            extensions = [Extensions.TsOnly];
1353            if (compilerOptions.allowJs) extensions.push(Extensions.JavaScript);
1354            if (compilerOptions.resolveJsonModule) extensions.push(Extensions.Json);
1355        }
1356        else {
1357            extensions = compilerOptions.resolveJsonModule ? tsPlusJsonExtensions : tsExtensions;
1358        }
1359        return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, extensions, redirectedReference);
1360    }
1361
1362    function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, extensions: Extensions[], redirectedReference: ResolvedProjectReference | undefined): ResolvedModuleWithFailedLookupLocations {
1363        const traceEnabled = isTraceEnabled(compilerOptions, host);
1364
1365        const failedLookupLocations: string[] = [];
1366        const affectingLocations: string[] = [];
1367        // conditions are only used by the node16/nodenext resolver - there's no priority order in the list,
1368        //it's essentially a set (priority is determined by object insertion order in the object we look at).
1369        const conditions = features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"];
1370        if (compilerOptions.noDtsResolution) {
1371            conditions.pop();
1372        }
1373
1374        const diagnostics: Diagnostic[] = [];
1375        const state: ModuleResolutionState = {
1376            compilerOptions,
1377            host,
1378            traceEnabled,
1379            failedLookupLocations,
1380            affectingLocations,
1381            packageJsonInfoCache: cache,
1382            features,
1383            conditions,
1384            requestContainingDirectory: containingDirectory,
1385            reportDiagnostic: diag => void diagnostics.push(diag),
1386        };
1387
1388        if (traceEnabled && getEmitModuleResolutionKind(compilerOptions) >= ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) <= ModuleResolutionKind.NodeNext) {
1389            trace(host, Diagnostics.Resolving_in_0_mode_with_conditions_1, features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", conditions.map(c => `'${c}'`).join(", "));
1390        }
1391
1392        const result = forEach(extensions, ext => tryResolve(ext));
1393        return createResolvedModuleWithFailedLookupLocations(
1394            result?.value?.resolved,
1395            result?.value?.isExternalLibraryImport,
1396            failedLookupLocations,
1397            affectingLocations,
1398            diagnostics,
1399            state.resultFromCache
1400        );
1401
1402        function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
1403            const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
1404            const isOHModules: boolean = isOhpm(compilerOptions.packageManagerType);
1405            const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state);
1406            if (resolved) {
1407                return toSearchResult({ resolved, isExternalLibraryImport: isOHModules ? pathContainsOHModules(resolved.path) :
1408                  pathContainsNodeModules(resolved.path) });
1409            }
1410
1411            if (!isExternalModuleNameRelative(moduleName)) {
1412                let resolved: SearchResult<Resolved> | undefined;
1413                if (features & NodeResolutionFeatures.Imports && startsWith(moduleName, "#")) {
1414                    resolved = loadModuleFromImports(extensions, moduleName, containingDirectory, state, cache, redirectedReference);
1415                }
1416                if (!resolved && features & NodeResolutionFeatures.SelfName) {
1417                    resolved = loadModuleFromSelfNameReference(extensions, moduleName, containingDirectory, state, cache, redirectedReference);
1418                }
1419                if (!resolved) {
1420                    if (traceEnabled) {
1421                        const message = isOHModules ? Diagnostics.Loading_module_0_from_oh_modules_folder_target_file_type_1 : Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1;
1422                        trace(host, message, moduleName, Extensions[extensions]);
1423                    }
1424                    resolved = loadModuleFromNearestNodeModulesDirectory(extensions, moduleName, containingDirectory, state, cache, redirectedReference);
1425                }
1426                if (!resolved) return undefined;
1427
1428                let resolvedValue = resolved.value;
1429                if (!compilerOptions.preserveSymlinks && resolvedValue && !resolvedValue.originalPath) {
1430                    const path = realPath(resolvedValue.path, host, traceEnabled);
1431                    const pathsAreEqual = arePathsEqual(path, resolvedValue.path, host);
1432                    const originalPath = pathsAreEqual ? undefined : resolvedValue.path;
1433                    // If the path and realpath are differing only in casing prefer path so that we can issue correct errors for casing under forceConsistentCasingInFileNames
1434                    resolvedValue = { ...resolvedValue, path: pathsAreEqual ? resolvedValue.path : path, originalPath };
1435                }
1436                // For node_modules or oh_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
1437                return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
1438            }
1439            else {
1440                const { path: candidate, parts } = normalizePathForCJSResolution(containingDirectory, moduleName);
1441                const resolved = nodeLoadModuleByRelativeName(extensions, candidate, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
1442                // Treat explicit "node_modules" or "oh_modules" import as an external library import.
1443                return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, getModuleByPMType(compilerOptions.packageManagerType)) });
1444            }
1445        }
1446
1447    }
1448
1449    // If you import from "." inside a containing directory "/foo", the result of `normalizePath`
1450    // would be "/foo", but this loses the information that `foo` is a directory and we intended
1451    // to look inside of it. The Node CommonJS resolution algorithm doesn't call this out
1452    // (https://nodejs.org/api/modules.html#all-together), but it seems that module paths ending
1453    // in `.` are actually normalized to `./` before proceeding with the resolution algorithm.
1454    function normalizePathForCJSResolution(containingDirectory: string, moduleName: string) {
1455        const combined = combinePaths(containingDirectory, moduleName);
1456        const parts = getPathComponents(combined);
1457        const lastPart = lastOrUndefined(parts);
1458        const path = lastPart === "." || lastPart === ".." ? ensureTrailingDirectorySeparator(normalizePath(combined)) : normalizePath(combined);
1459        return { path, parts };
1460    }
1461
1462    function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
1463        if (!host.realpath) {
1464            return path;
1465        }
1466
1467        const real = normalizePath(host.realpath(path));
1468        if (traceEnabled) {
1469            trace(host, Diagnostics.Resolving_real_path_for_0_result_1, path, real);
1470        }
1471        Debug.assert(host.fileExists(real), `${path} linked to nonexistent file ${real}`);
1472        return real;
1473    }
1474
1475    function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
1476        if (state.traceEnabled) {
1477            trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
1478        }
1479        if (!hasTrailingDirectorySeparator(candidate)) {
1480            if (!onlyRecordFailures) {
1481                const parentOfCandidate = getDirectoryPath(candidate);
1482                if (!directoryProbablyExists(parentOfCandidate, state.host)) {
1483                    if (state.traceEnabled) {
1484                        trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, parentOfCandidate);
1485                    }
1486                    onlyRecordFailures = true;
1487                }
1488            }
1489            const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state);
1490            if (resolvedFromFile) {
1491                const packageDirectory = considerPackageJson ? parseModuleFromPath(resolvedFromFile.path, state.compilerOptions.packageManagerType) : undefined;
1492                const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined;
1493                return withPackageId(packageInfo, resolvedFromFile);
1494            }
1495        }
1496        if (!onlyRecordFailures) {
1497            const candidateExists = directoryProbablyExists(candidate, state.host);
1498            if (!candidateExists) {
1499                if (state.traceEnabled) {
1500                    trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, candidate);
1501                }
1502                onlyRecordFailures = true;
1503            }
1504        }
1505        // esm mode relative imports shouldn't do any directory lookups (either inside `package.json`
1506        // files or implicit `index.js`es). This is a notable depature from cjs norms, where `./foo/pkg`
1507        // could have been redirected by `./foo/pkg/package.json` to an arbitrary location!
1508        if (!(state.features & NodeResolutionFeatures.EsmMode)) {
1509            return loadNodeModuleFromDirectory(extensions, candidate, onlyRecordFailures, state, considerPackageJson);
1510        }
1511        return undefined;
1512    }
1513
1514    /*@internal*/
1515    export const nodeModulesPathPart = "/node_modules/";
1516
1517    /*@internal*/
1518    export function pathContainsNodeModules(path: string): boolean {
1519        return stringContains(path, nodeModulesPathPart);
1520    }
1521
1522    /**
1523     * This will be called on the successfully resolved path from `loadModuleFromFile`.
1524     * (Not needed for `loadModuleFromNodeModules` as that looks up the `package.json` or `oh-package.json5` as part of resolution.)
1525     *
1526     * packageDirectory is the directory of the package itself.
1527     *   For `blah/node_modules/foo/index.d.ts` this is packageDirectory: "foo"
1528     *   For `/node_modules/foo/bar.d.ts` this is packageDirectory: "foo"
1529     *   For `/node_modules/@types/foo/bar/index.d.ts` this is packageDirectory: "@types/foo"
1530     *   For `/node_modules/foo/bar/index.d.ts` this is packageDirectory: "foo"
1531     */
1532    export function parseModuleFromPath(resolved: string, packageManagerType?: string): string | undefined {
1533        const modulesPathPart = getModulePathPartByPMType(packageManagerType);
1534        const path = normalizePath(resolved);
1535        const idx = path.lastIndexOf(modulesPathPart);
1536        if (idx === -1) {
1537            return undefined;
1538        }
1539
1540        const indexAfterModules = idx + modulesPathPart.length;
1541        let indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterModules);
1542        if (path.charCodeAt(indexAfterModules) === CharacterCodes.at) {
1543            indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterPackageName);
1544        }
1545        return path.slice(0, indexAfterPackageName);
1546    }
1547
1548    function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number): number {
1549        const nextSeparatorIndex = path.indexOf(directorySeparator, prevSeparatorIndex + 1);
1550        return nextSeparatorIndex === -1 ? prevSeparatorIndex : nextSeparatorIndex;
1551    }
1552
1553    function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
1554        return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state));
1555    }
1556
1557    /**
1558     * @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
1559     * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
1560     */
1561    function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
1562        if (extensions === Extensions.Json || extensions === Extensions.TSConfig) {
1563            const extensionLess = tryRemoveExtension(candidate, Extension.Json);
1564            const extension = extensionLess ? candidate.substring(extensionLess.length) : "";
1565            return (extensionLess === undefined && extensions === Extensions.Json) ? undefined : tryAddingExtensions(extensionLess || candidate, extensions, extension, onlyRecordFailures, state);
1566        }
1567
1568        // esm mode resolutions don't include automatic extension lookup (without additional flags, at least)
1569        if (!(state.features & NodeResolutionFeatures.EsmMode)) {
1570            // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
1571            const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, "", onlyRecordFailures, state);
1572            if (resolvedByAddingExtension) {
1573                return resolvedByAddingExtension;
1574            }
1575        }
1576
1577        return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state);
1578    }
1579
1580    function loadModuleFromFileNoImplicitExtensions(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
1581        // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one;
1582        // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
1583        if (hasJSFileExtension(candidate) || (fileExtensionIs(candidate, Extension.Json) && state.compilerOptions.resolveJsonModule)) {
1584            const extensionless = removeFileExtension(candidate);
1585            const extension = candidate.substring(extensionless.length);
1586            if (state.traceEnabled) {
1587                trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
1588            }
1589            return tryAddingExtensions(extensionless, extensions, extension, onlyRecordFailures, state);
1590        }
1591    }
1592
1593    function loadJSOrExactTSFileName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
1594        if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && fileExtensionIsOneOf(candidate, supportedTSExtensionsFlat)) {
1595            const result = tryFile(candidate, onlyRecordFailures, state);
1596            return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension } : undefined;
1597        }
1598
1599        return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state);
1600    }
1601
1602    /** Try to return an existing file that adds one of the `extensions` to `candidate`. */
1603    function tryAddingExtensions(candidate: string, extensions: Extensions, originalExtension: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
1604        if (!onlyRecordFailures) {
1605            // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
1606            const directory = getDirectoryPath(candidate);
1607            if (directory) {
1608                onlyRecordFailures = !directoryProbablyExists(directory, state.host);
1609            }
1610        }
1611
1612        switch (extensions) {
1613            case Extensions.DtsOnly:
1614                switch (originalExtension) {
1615                    case Extension.Mjs:
1616                    case Extension.Mts:
1617                    case Extension.Dmts:
1618                        return tryExtension(Extension.Dmts);
1619                    case Extension.Cjs:
1620                    case Extension.Cts:
1621                    case Extension.Dcts:
1622                        return tryExtension(Extension.Dcts);
1623                    case Extension.Json:
1624                        candidate += Extension.Json;
1625                        return tryExtension(Extension.Dts);
1626                    default: return state.compilerOptions.ets ? tryExtension(Extension.Dets) || tryExtension(Extension.Dts) : tryExtension(Extension.Dts);
1627                }
1628            case Extensions.TypeScript:
1629            case Extensions.TsOnly:
1630                const useDts = extensions === Extensions.TypeScript;
1631                switch (originalExtension) {
1632                    case Extension.Mjs:
1633                    case Extension.Mts:
1634                    case Extension.Dmts:
1635                        return tryExtension(Extension.Mts) || (useDts ? tryExtension(Extension.Dmts) : undefined);
1636                    case Extension.Cjs:
1637                    case Extension.Cts:
1638                    case Extension.Dcts:
1639                        return tryExtension(Extension.Cts) || (useDts ? tryExtension(Extension.Dcts) : undefined);
1640                    case Extension.Json:
1641                        candidate += Extension.Json;
1642                        return useDts ? tryExtension(Extension.Dts) : undefined;
1643                    default:
1644                        if (state.compilerOptions.ets) {
1645                            return tryExtension(Extension.Ets) || tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || (useDts ? tryExtension(Extension.Dets) || tryExtension(Extension.Dts) : undefined);
1646                        }
1647                        else {
1648                            return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || (useDts ? tryExtension(Extension.Dts) || tryExtension(Extension.Ets) || tryExtension(Extension.Dets) : undefined);
1649                        }
1650                }
1651            case Extensions.JavaScript:
1652                switch (originalExtension) {
1653                    case Extension.Mjs:
1654                    case Extension.Mts:
1655                    case Extension.Dmts:
1656                        return tryExtension(Extension.Mjs);
1657                    case Extension.Cjs:
1658                    case Extension.Cts:
1659                    case Extension.Dcts:
1660                        return tryExtension(Extension.Cjs);
1661                    case Extension.Json:
1662                        return tryExtension(Extension.Json);
1663                    default:
1664                        return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
1665                }
1666            case Extensions.TSConfig:
1667            case Extensions.Json:
1668                return tryExtension(Extension.Json);
1669        }
1670
1671        function tryExtension(ext: Extension): PathAndExtension | undefined {
1672            const path = tryFile(candidate + ext, onlyRecordFailures, state);
1673            return path === undefined ? undefined : { path, ext };
1674        }
1675    }
1676
1677    /** Return the file if it exists. */
1678    function tryFile(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
1679        if (!state.compilerOptions.moduleSuffixes?.length) {
1680            return tryFileLookup(fileName, onlyRecordFailures, state);
1681        }
1682
1683        const ext = tryGetExtensionFromPath(fileName) ?? "";
1684        const fileNameNoExtension = ext ? removeExtension(fileName, ext) : fileName;
1685        return forEach(state.compilerOptions.moduleSuffixes, suffix => tryFileLookup(fileNameNoExtension + suffix + ext, onlyRecordFailures, state));
1686    }
1687
1688    function tryFileLookup(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
1689        if (!onlyRecordFailures) {
1690            if (state.host.fileExists(fileName)) {
1691                if (state.traceEnabled) {
1692                    trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName);
1693                }
1694                return fileName;
1695            }
1696            else {
1697                if (state.traceEnabled) {
1698                    trace(state.host, Diagnostics.File_0_does_not_exist, fileName);
1699                }
1700            }
1701        }
1702        state.failedLookupLocations.push(fileName);
1703        return undefined;
1704    }
1705
1706    function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
1707        const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, onlyRecordFailures, state) : undefined;
1708        const packageJsonContent = packageInfo && packageInfo.contents.packageJsonContent;
1709        const versionPaths = packageInfo && packageInfo.contents.versionPaths;
1710        return withPackageId(packageInfo, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
1711    }
1712
1713    /* @internal */
1714    export function getEntrypointsFromPackageJsonInfo(
1715        packageJsonInfo: PackageJsonInfo,
1716        options: CompilerOptions,
1717        host: ModuleResolutionHost,
1718        cache: ModuleResolutionCache | undefined,
1719        resolveJs?: boolean,
1720    ): string[] | false {
1721        if (!resolveJs && packageJsonInfo.contents.resolvedEntrypoints !== undefined) {
1722            // Cached value excludes resolutions to JS files - those could be
1723            // cached separately, but they're used rarely.
1724            return packageJsonInfo.contents.resolvedEntrypoints;
1725        }
1726
1727        let entrypoints: string[] | undefined;
1728        const extensions = resolveJs ? Extensions.JavaScript : Extensions.TypeScript;
1729        const features = getDefaultNodeResolutionFeatures(options);
1730        const requireState = getTemporaryModuleResolutionState(cache?.getPackageJsonInfoCache(), host, options);
1731        requireState.conditions = ["node", "require", "types"];
1732        requireState.requestContainingDirectory = packageJsonInfo.packageDirectory;
1733        const requireResolution = loadNodeModuleFromDirectoryWorker(
1734            extensions,
1735            packageJsonInfo.packageDirectory,
1736            /*onlyRecordFailures*/ false,
1737            requireState,
1738            packageJsonInfo.contents.packageJsonContent,
1739            packageJsonInfo.contents.versionPaths);
1740        entrypoints = append(entrypoints, requireResolution?.path);
1741
1742        if (features & NodeResolutionFeatures.Exports && packageJsonInfo.contents.packageJsonContent.exports) {
1743            for (const conditions of [["node", "import", "types"], ["node", "require", "types"]]) {
1744                const exportState = { ...requireState, failedLookupLocations: [], conditions };
1745                const exportResolutions = loadEntrypointsFromExportMap(
1746                    packageJsonInfo,
1747                    packageJsonInfo.contents.packageJsonContent.exports,
1748                    exportState,
1749                    extensions);
1750                if (exportResolutions) {
1751                    for (const resolution of exportResolutions) {
1752                        entrypoints = appendIfUnique(entrypoints, resolution.path);
1753                    }
1754                }
1755            }
1756        }
1757
1758        return packageJsonInfo.contents.resolvedEntrypoints = entrypoints || false;
1759    }
1760
1761    function loadEntrypointsFromExportMap(
1762        scope: PackageJsonInfo,
1763        exports: object,
1764        state: ModuleResolutionState,
1765        extensions: Extensions,
1766    ): PathAndExtension[] | undefined {
1767        let entrypoints: PathAndExtension[] | undefined;
1768        if (isArray(exports)) {
1769            for (const target of exports) {
1770                loadEntrypointsFromTargetExports(target);
1771            }
1772        }
1773        // eslint-disable-next-line no-null/no-null
1774        else if (typeof exports === "object" && exports !== null && allKeysStartWithDot(exports as MapLike<unknown>)) {
1775            for (const key in exports) {
1776                loadEntrypointsFromTargetExports((exports as MapLike<unknown>)[key]);
1777            }
1778        }
1779        else {
1780            loadEntrypointsFromTargetExports(exports);
1781        }
1782        return entrypoints;
1783
1784        function loadEntrypointsFromTargetExports(target: unknown): boolean | undefined {
1785            if (typeof target === "string" && startsWith(target, "./") && target.indexOf("*") === -1) {
1786                const partsAfterFirst = getPathComponents(target).slice(2);
1787                if (partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 || partsAfterFirst.indexOf("node_modules") >= 0 || partsAfterFirst.indexOf("oh_modules") >= 0) {
1788                    return false;
1789                }
1790                const resolvedTarget = combinePaths(scope.packageDirectory, target);
1791                const finalPath = getNormalizedAbsolutePath(resolvedTarget, state.host.getCurrentDirectory?.());
1792                const result = loadJSOrExactTSFileName(extensions, finalPath, /*recordOnlyFailures*/ false, state);
1793                if (result) {
1794                    entrypoints = appendIfUnique(entrypoints, result, (a, b) => a.path === b.path);
1795                    return true;
1796                }
1797            }
1798            else if (Array.isArray(target)) {
1799                for (const t of target) {
1800                    const success = loadEntrypointsFromTargetExports(t);
1801                    if (success) {
1802                        return true;
1803                    }
1804                }
1805            }
1806            // eslint-disable-next-line no-null/no-null
1807            else if (typeof target === "object" && target !== null) {
1808                return forEach(getOwnKeys(target as MapLike<unknown>), key => {
1809                    if (key === "default" || contains(state.conditions, key) || isApplicableVersionedTypesKey(state.conditions, key)) {
1810                        loadEntrypointsFromTargetExports((target as MapLike<unknown>)[key]);
1811                        return true;
1812                    }
1813                });
1814            }
1815        }
1816    }
1817
1818    /*@internal*/
1819    export function getTemporaryModuleResolutionState(packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ModuleResolutionState {
1820        return {
1821            host,
1822            compilerOptions: options,
1823            traceEnabled: isTraceEnabled(options, host),
1824            failedLookupLocations: noopPush,
1825            affectingLocations: noopPush,
1826            packageJsonInfoCache,
1827            features: NodeResolutionFeatures.None,
1828            conditions: emptyArray,
1829            requestContainingDirectory: undefined,
1830            reportDiagnostic: noop
1831        };
1832    }
1833
1834    /*@internal*/
1835    export interface PackageJsonInfo {
1836        packageDirectory: string;
1837        contents: PackageJsonInfoContents;
1838    }
1839    /*@internal*/
1840    export interface PackageJsonInfoContents {
1841        packageJsonContent: PackageJsonPathFields;
1842        versionPaths: VersionPaths | undefined;
1843        /** false: resolved to nothing. undefined: not yet resolved */
1844        resolvedEntrypoints: string[] | false | undefined;
1845    }
1846
1847    /**
1848     * A function for locating the package.json scope for a given path
1849     */
1850    /*@internal*/
1851     export function getPackageScopeForPath(fileName: string, state: ModuleResolutionState): PackageJsonInfo | undefined {
1852        const parts = getPathComponents(fileName);
1853        parts.pop();
1854        while (parts.length > 0) {
1855            const pkg = getPackageJsonInfo(getPathFromPathComponents(parts), /*onlyRecordFailures*/ false, state);
1856            if (pkg) {
1857                return pkg;
1858            }
1859            parts.pop();
1860        }
1861        return undefined;
1862    }
1863
1864    /*@internal*/
1865    export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
1866        const { host, traceEnabled } = state;
1867        const packageJsonPath = combinePaths(packageDirectory, getPackageJsonByPMType(state.compilerOptions.packageManagerType));
1868        if (onlyRecordFailures) {
1869            state.failedLookupLocations.push(packageJsonPath);
1870            return undefined;
1871        }
1872
1873        const existing = state.packageJsonInfoCache?.getPackageJsonInfo(packageJsonPath);
1874        if (existing !== undefined) {
1875            if (typeof existing !== "boolean") {
1876                if (traceEnabled) trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath);
1877                state.affectingLocations.push(packageJsonPath);
1878                return existing.packageDirectory === packageDirectory ?
1879                    existing :
1880                    { packageDirectory, contents: existing.contents };
1881            }
1882            else {
1883                if (existing && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath);
1884                state.failedLookupLocations.push(packageJsonPath);
1885                return undefined;
1886            }
1887        }
1888        const directoryExists = directoryProbablyExists(packageDirectory, host);
1889        if (directoryExists && host.fileExists(packageJsonPath)) {
1890            const isOHModules: boolean = isOhpm(state.compilerOptions.packageManagerType);
1891            const packageJsonContent = isOHModules ? require("json5").parse(host.readFile!(packageJsonPath)!) : readJson(packageJsonPath, host) as PackageJson;
1892            if (traceEnabled) {
1893                const message = isOHModules ? Diagnostics.Found_oh_package_json5_at_0 : Diagnostics.Found_package_json_at_0;
1894                trace(host, message, packageJsonPath);
1895            }
1896            const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state);
1897            const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths, resolvedEntrypoints: undefined } };
1898            state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, result);
1899            state.affectingLocations.push(packageJsonPath);
1900            return result;
1901        }
1902        else {
1903            if (directoryExists && traceEnabled) {
1904                trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
1905            }
1906            state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, directoryExists);
1907            // record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
1908            state.failedLookupLocations.push(packageJsonPath);
1909        }
1910    }
1911
1912    function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, jsonContent: PackageJsonPathFields | undefined, versionPaths: VersionPaths | undefined): PathAndExtension | undefined {
1913        let packageFile: string | undefined;
1914        if (jsonContent) {
1915            switch (extensions) {
1916                case Extensions.JavaScript:
1917                case Extensions.Json:
1918                case Extensions.TsOnly:
1919                    packageFile = readPackageJsonMainField(jsonContent, candidate, state);
1920                    break;
1921                case Extensions.TypeScript:
1922                    // When resolving typescript modules, try resolving using main field as well
1923                    packageFile = readPackageJsonTypesFields(jsonContent, candidate, state) || readPackageJsonMainField(jsonContent, candidate, state);
1924                    break;
1925                case Extensions.DtsOnly:
1926                    packageFile = readPackageJsonTypesFields(jsonContent, candidate, state);
1927                    break;
1928                case Extensions.TSConfig:
1929                    packageFile = readPackageJsonTSConfigField(jsonContent, candidate, state);
1930                    break;
1931                default:
1932                    return Debug.assertNever(extensions);
1933            }
1934        }
1935
1936        const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
1937            const fromFile = tryFile(candidate, onlyRecordFailures, state);
1938            if (fromFile) {
1939                const resolved = resolvedIfExtensionMatches(extensions, fromFile);
1940                if (resolved) {
1941                    return noPackageId(resolved);
1942                }
1943                if (state.traceEnabled) {
1944                    trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
1945                }
1946            }
1947
1948            // Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
1949            const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
1950            // Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
1951
1952            // Disable `EsmMode` for the resolution of the package path for cjs-mode packages (so the `main` field can omit extensions)
1953            // (technically it only emits a deprecation warning in esm packages right now, but that's probably
1954            // enough to mean we don't need to support it)
1955            const features = state.features;
1956            if (jsonContent?.type !== "module") {
1957                state.features &= ~NodeResolutionFeatures.EsmMode;
1958            }
1959            const result = nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false);
1960            state.features = features;
1961            return result;
1962        };
1963
1964        const onlyRecordFailuresForPackageFile = packageFile ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined;
1965        const onlyRecordFailuresForIndex = onlyRecordFailures || !directoryProbablyExists(candidate, state.host);
1966        const indexPath = combinePaths(candidate, extensions === Extensions.TSConfig ? "tsconfig" : "index");
1967
1968        if (versionPaths && (!packageFile || containsPath(candidate, packageFile))) {
1969            const moduleName = getRelativePathFromDirectory(candidate, packageFile || indexPath, /*ignoreCase*/ false);
1970            if (state.traceEnabled) {
1971                trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, moduleName);
1972            }
1973            const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, /*pathPatterns*/ undefined, loader, onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, state);
1974            if (result) {
1975                return removeIgnoredPackageId(result.value);
1976            }
1977        }
1978
1979        // It won't have a `packageId` set, because we disabled `considerPackageJson`.
1980        const packageFileResult = packageFile && removeIgnoredPackageId(loader(extensions, packageFile, onlyRecordFailuresForPackageFile!, state));
1981        if (packageFileResult) return packageFileResult;
1982
1983        // esm mode resolutions don't do package `index` lookups
1984        if (!(state.features & NodeResolutionFeatures.EsmMode)) {
1985            return loadModuleFromFile(extensions, indexPath, onlyRecordFailuresForIndex, state);
1986        }
1987    }
1988
1989    /** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
1990    function resolvedIfExtensionMatches(extensions: Extensions, path: string): PathAndExtension | undefined {
1991        const ext = tryGetExtensionFromPath(path);
1992        return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext } : undefined;
1993    }
1994
1995    /** True if `extension` is one of the supported `extensions`. */
1996    function extensionIsOk(extensions: Extensions, extension: Extension): boolean {
1997        switch (extensions) {
1998            case Extensions.JavaScript:
1999                return extension === Extension.Js || extension === Extension.Jsx || extension === Extension.Mjs || extension === Extension.Cjs;
2000            case Extensions.TSConfig:
2001            case Extensions.Json:
2002                return extension === Extension.Json;
2003            case Extensions.TypeScript:
2004                return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts || extension === Extension.Cts || extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts || extension === Extension.Ets || extension === Extension.Dets;
2005            case Extensions.TsOnly:
2006                return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts || extension === Extension.Cts || extension === Extension.Ets;
2007            case Extensions.DtsOnly:
2008                return extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts || extension === Extension.Dets;
2009        }
2010    }
2011
2012    /* @internal */
2013    export function parsePackageName(moduleName: string): { packageName: string, rest: string } {
2014        let idx = moduleName.indexOf(directorySeparator);
2015        if (moduleName[0] === "@") {
2016            idx = moduleName.indexOf(directorySeparator, idx + 1);
2017        }
2018        return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) };
2019    }
2020
2021    /* @internal */
2022    export function allKeysStartWithDot(obj: MapLike<unknown>) {
2023        return every(getOwnKeys(obj), k => startsWith(k, "."));
2024    }
2025
2026    function noKeyStartsWithDot(obj: MapLike<unknown>) {
2027        return !some(getOwnKeys(obj), k => startsWith(k, "."));
2028    }
2029
2030    function loadModuleFromSelfNameReference(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
2031        const directoryPath = getNormalizedAbsolutePath(combinePaths(directory, "dummy"), state.host.getCurrentDirectory?.());
2032        const scope = getPackageScopeForPath(directoryPath, state);
2033        if (!scope || !scope.contents.packageJsonContent.exports) {
2034            return undefined;
2035        }
2036        if (typeof scope.contents.packageJsonContent.name !== "string") {
2037            return undefined;
2038        }
2039        const parts = getPathComponents(moduleName); // unrooted paths should have `""` as their 0th entry
2040        const nameParts = getPathComponents(scope.contents.packageJsonContent.name);
2041        if (!every(nameParts, (p, i) => parts[i] === p)) {
2042            return undefined;
2043        }
2044        const trailingParts = parts.slice(nameParts.length);
2045        return loadModuleFromExports(scope, extensions, !length(trailingParts) ? "." : `.${directorySeparator}${trailingParts.join(directorySeparator)}`, state, cache, redirectedReference);
2046    }
2047
2048    function loadModuleFromExports(scope: PackageJsonInfo, extensions: Extensions, subpath: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
2049        if (!scope.contents.packageJsonContent.exports) {
2050            return undefined;
2051        }
2052
2053        if (subpath === ".") {
2054            let mainExport;
2055            if (typeof scope.contents.packageJsonContent.exports === "string" || Array.isArray(scope.contents.packageJsonContent.exports) || (typeof scope.contents.packageJsonContent.exports === "object" && noKeyStartsWithDot(scope.contents.packageJsonContent.exports as MapLike<unknown>))) {
2056                mainExport = scope.contents.packageJsonContent.exports;
2057            }
2058            else if (hasProperty(scope.contents.packageJsonContent.exports as MapLike<unknown>, ".")) {
2059                mainExport = (scope.contents.packageJsonContent.exports as MapLike<unknown>)["."];
2060            }
2061            if (mainExport) {
2062                const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, subpath, scope, /*isImports*/ false);
2063                return loadModuleFromTargetImportOrExport(mainExport, "", /*pattern*/ false, ".");
2064            }
2065        }
2066        else if (allKeysStartWithDot(scope.contents.packageJsonContent.exports as MapLike<unknown>)) {
2067            if (typeof scope.contents.packageJsonContent.exports !== "object") {
2068                if (state.traceEnabled) {
2069                    trace(state.host, Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, subpath, scope.packageDirectory);
2070                }
2071                return toSearchResult(/*value*/ undefined);
2072            }
2073            const result = loadModuleFromImportsOrExports(extensions, state, cache, redirectedReference, subpath, scope.contents.packageJsonContent.exports, scope, /*isImports*/ false);
2074            if (result) {
2075                return result;
2076            }
2077        }
2078
2079        if (state.traceEnabled) {
2080            trace(state.host, Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, subpath, scope.packageDirectory);
2081        }
2082        return toSearchResult(/*value*/ undefined);
2083    }
2084
2085    function loadModuleFromImports(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
2086        if (moduleName === "#" || startsWith(moduleName, "#/")) {
2087            if (state.traceEnabled) {
2088                trace(state.host, Diagnostics.Invalid_import_specifier_0_has_no_possible_resolutions, moduleName);
2089            }
2090            return toSearchResult(/*value*/ undefined);
2091        }
2092        const directoryPath = getNormalizedAbsolutePath(combinePaths(directory, "dummy"), state.host.getCurrentDirectory?.());
2093        const scope = getPackageScopeForPath(directoryPath, state);
2094        if (!scope) {
2095            if (state.traceEnabled) {
2096                trace(state.host, Diagnostics.Directory_0_has_no_containing_package_json_scope_Imports_will_not_resolve, directoryPath);
2097            }
2098            return toSearchResult(/*value*/ undefined);
2099        }
2100        if (!scope.contents.packageJsonContent.imports) {
2101            if (state.traceEnabled) {
2102                trace(state.host, Diagnostics.package_json_scope_0_has_no_imports_defined, scope.packageDirectory);
2103            }
2104            return toSearchResult(/*value*/ undefined);
2105        }
2106
2107        const result = loadModuleFromImportsOrExports(extensions, state, cache, redirectedReference, moduleName, scope.contents.packageJsonContent.imports, scope, /*isImports*/ true);
2108        if (result) {
2109            return result;
2110        }
2111
2112        if (state.traceEnabled) {
2113            trace(state.host, Diagnostics.Import_specifier_0_does_not_exist_in_package_json_scope_at_path_1, moduleName, scope.packageDirectory);
2114        }
2115        return toSearchResult(/*value*/ undefined);
2116    }
2117
2118    /**
2119     * @internal
2120     * From https://github.com/nodejs/node/blob/8f39f51cbbd3b2de14b9ee896e26421cc5b20121/lib/internal/modules/esm/resolve.js#L722 -
2121     * "longest" has some nuance as to what "longest" means in the presence of pattern trailers
2122     */
2123    export function comparePatternKeys(a: string, b: string) {
2124        const aPatternIndex = a.indexOf("*");
2125        const bPatternIndex = b.indexOf("*");
2126        const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
2127        const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
2128        if (baseLenA > baseLenB) return -1;
2129        if (baseLenB > baseLenA) return 1;
2130        if (aPatternIndex === -1) return 1;
2131        if (bPatternIndex === -1) return -1;
2132        if (a.length > b.length) return -1;
2133        if (b.length > a.length) return 1;
2134        return 0;
2135    }
2136
2137    function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, lookupTable: object, scope: PackageJsonInfo, isImports: boolean): SearchResult<Resolved> | undefined {
2138        const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, moduleName, scope, isImports);
2139
2140        if (!endsWith(moduleName, directorySeparator) && moduleName.indexOf("*") === -1 && hasProperty(lookupTable, moduleName)) {
2141            const target = (lookupTable as {[idx: string]: unknown})[moduleName];
2142            return loadModuleFromTargetImportOrExport(target, /*subpath*/ "", /*pattern*/ false, moduleName);
2143        }
2144        const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => k.indexOf("*") !== -1 || endsWith(k, "/")), comparePatternKeys);
2145        for (const potentialTarget of expandingKeys) {
2146            if (state.features & NodeResolutionFeatures.ExportsPatternTrailers && matchesPatternWithTrailer(potentialTarget, moduleName)) {
2147                const target = (lookupTable as {[idx: string]: unknown})[potentialTarget];
2148                const starPos = potentialTarget.indexOf("*");
2149                const subpath = moduleName.substring(potentialTarget.substring(0, starPos).length, moduleName.length - (potentialTarget.length - 1 - starPos));
2150                return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ true, potentialTarget);
2151            }
2152            else if (endsWith(potentialTarget, "*") && startsWith(moduleName, potentialTarget.substring(0, potentialTarget.length - 1))) {
2153                const target = (lookupTable as {[idx: string]: unknown})[potentialTarget];
2154                const subpath = moduleName.substring(potentialTarget.length - 1);
2155                return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ true, potentialTarget);
2156            }
2157            else if (startsWith(moduleName, potentialTarget)) {
2158                const target = (lookupTable as {[idx: string]: unknown})[potentialTarget];
2159                const subpath = moduleName.substring(potentialTarget.length);
2160                return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ false, potentialTarget);
2161            }
2162        }
2163
2164        function matchesPatternWithTrailer(target: string, name: string) {
2165            if (endsWith(target, "*")) return false; // handled by next case in loop
2166            const starPos = target.indexOf("*");
2167            if (starPos === -1) return false; // handled by last case in loop
2168            return startsWith(name, target.substring(0, starPos)) && endsWith(name, target.substring(starPos + 1));
2169        }
2170    }
2171
2172    /**
2173     * Gets the self-recursive function specialized to retrieving the targeted import/export element for the given resolution configuration
2174     */
2175    function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, scope: PackageJsonInfo, isImports: boolean) {
2176        return loadModuleFromTargetImportOrExport;
2177        function loadModuleFromTargetImportOrExport(target: unknown, subpath: string, pattern: boolean, key: string): SearchResult<Resolved> | undefined {
2178            if (typeof target === "string") {
2179                if (!pattern && subpath.length > 0 && !endsWith(target, "/")) {
2180                    if (state.traceEnabled) {
2181                        trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName);
2182                    }
2183                    return toSearchResult(/*value*/ undefined);
2184                }
2185                if (!startsWith(target, "./")) {
2186                    if (isImports && !startsWith(target, "../") && !startsWith(target, "/") && !isRootedDiskPath(target)) {
2187                        const combinedLookup = pattern ? target.replace(/\*/g, subpath) : target + subpath;
2188                        traceIfEnabled(state, Diagnostics.Using_0_subpath_1_with_target_2, "imports", key, combinedLookup);
2189                        traceIfEnabled(state, Diagnostics.Resolving_module_0_from_1, combinedLookup, scope.packageDirectory + "/");
2190                        const result = nodeModuleNameResolverWorker(state.features, combinedLookup, scope.packageDirectory + "/", state.compilerOptions, state.host, cache, [extensions], redirectedReference);
2191                        return toSearchResult(result.resolvedModule ? { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId, originalPath: result.resolvedModule.originalPath } : undefined);
2192                    }
2193                    if (state.traceEnabled) {
2194                        trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName);
2195                    }
2196                    return toSearchResult(/*value*/ undefined);
2197                }
2198                const parts = pathIsRelative(target) ? getPathComponents(target).slice(1) : getPathComponents(target);
2199                const partsAfterFirst = parts.slice(1);
2200                if (partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 || partsAfterFirst.indexOf("node_modules") >= 0 || partsAfterFirst.indexOf("oh_modules") >= 0) {
2201                    if (state.traceEnabled) {
2202                        trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName);
2203                    }
2204                    return toSearchResult(/*value*/ undefined);
2205                }
2206                const resolvedTarget = combinePaths(scope.packageDirectory, target);
2207                // TODO: Assert that `resolvedTarget` is actually within the package directory? That's what the spec says.... but I'm not sure we need
2208                // to be in the business of validating everyone's import and export map correctness.
2209                const subpathParts = getPathComponents(subpath);
2210                if (subpathParts.indexOf("..") >= 0 || subpathParts.indexOf(".") >= 0 || subpathParts.indexOf("node_modules") >= 0 || subpathParts.indexOf("oh_modules") >= 0) {
2211                    if (state.traceEnabled) {
2212                        trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName);
2213                    }
2214                    return toSearchResult(/*value*/ undefined);
2215                }
2216
2217                if (state.traceEnabled) {
2218                    trace(state.host,
2219                        Diagnostics.Using_0_subpath_1_with_target_2,
2220                        isImports ? "imports" : "exports",
2221                        key,
2222                        pattern ? target.replace(/\*/g, subpath) : target + subpath);
2223                }
2224                const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath);
2225                const inputLink = tryLoadInputFileForPath(finalPath, subpath, combinePaths(scope.packageDirectory, "package.json"), isImports);
2226                if (inputLink) return inputLink;
2227                return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, finalPath, /*onlyRecordFailures*/ false, state)));
2228            }
2229            else if (typeof target === "object" && target !== null) { // eslint-disable-line no-null/no-null
2230                if (!Array.isArray(target)) {
2231                    for (const condition of getOwnKeys(target as MapLike<unknown>)) {
2232                        if (condition === "default" || state.conditions.indexOf(condition) >= 0 || isApplicableVersionedTypesKey(state.conditions, condition)) {
2233                            traceIfEnabled(state, Diagnostics.Matched_0_condition_1, isImports ? "imports" : "exports", condition);
2234                            const subTarget = (target as MapLike<unknown>)[condition];
2235                            const result = loadModuleFromTargetImportOrExport(subTarget, subpath, pattern, key);
2236                            if (result) {
2237                                return result;
2238                            }
2239                        }
2240                        else {
2241                            traceIfEnabled(state, Diagnostics.Saw_non_matching_condition_0, condition);
2242                        }
2243                    }
2244                    return undefined;
2245                }
2246                else {
2247                    if (!length(target)) {
2248                        if (state.traceEnabled) {
2249                            trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName);
2250                        }
2251                        return toSearchResult(/*value*/ undefined);
2252                    }
2253                    for (const elem of target) {
2254                        const result = loadModuleFromTargetImportOrExport(elem, subpath, pattern, key);
2255                        if (result) {
2256                            return result;
2257                        }
2258                    }
2259                }
2260            }
2261            else if (target === null) { // eslint-disable-line no-null/no-null
2262                if (state.traceEnabled) {
2263                    trace(state.host, Diagnostics.package_json_scope_0_explicitly_maps_specifier_1_to_null, scope.packageDirectory, moduleName);
2264                }
2265                return toSearchResult(/*value*/ undefined);
2266            }
2267            if (state.traceEnabled) {
2268                trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName);
2269            }
2270            return toSearchResult(/*value*/ undefined);
2271
2272            function toAbsolutePath(path: string): string;
2273            function toAbsolutePath(path: string | undefined): string | undefined;
2274            function toAbsolutePath(path: string | undefined): string | undefined {
2275                if (path === undefined) return path;
2276                return getNormalizedAbsolutePath(path, state.host.getCurrentDirectory?.());
2277            }
2278
2279            function combineDirectoryPath(root: string, dir: string) {
2280                return ensureTrailingDirectorySeparator(combinePaths(root, dir));
2281            }
2282
2283            function useCaseSensitiveFileNames() {
2284                return !state.host.useCaseSensitiveFileNames ? true :
2285                    typeof state.host.useCaseSensitiveFileNames === "boolean" ? state.host.useCaseSensitiveFileNames :
2286                    state.host.useCaseSensitiveFileNames();
2287            }
2288
2289            function tryLoadInputFileForPath(finalPath: string, entry: string, packagePath: string, isImports: boolean) {
2290                // Replace any references to outputs for files in the program with the input files to support package self-names used with outDir
2291                // PROBLEM: We don't know how to calculate the output paths yet, because the "common source directory" we use as the base of the file structure
2292                // we reproduce into the output directory is based on the set of input files, which we're still in the process of traversing and resolving!
2293                // _Given that_, we have to guess what the base of the output directory is (obviously the user wrote the export map, so has some idea what it is!).
2294                // We are going to probe _so many_ possible paths. We limit where we'll do this to try to reduce the possibilities of false positive lookups.
2295                if ((extensions === Extensions.TypeScript || extensions === Extensions.JavaScript || extensions === Extensions.Json)
2296                    && (state.compilerOptions.declarationDir || state.compilerOptions.outDir)
2297                    && (finalPath.indexOf("/node_modules/") === -1 && finalPath.indexOf("/oh_modules/") === -1)
2298                    && (state.compilerOptions.configFile ? containsPath(scope.packageDirectory, toAbsolutePath(state.compilerOptions.configFile.fileName), !useCaseSensitiveFileNames()) : true)
2299                ) {
2300                    // So that all means we'll only try these guesses for files outside `node_modules` in a directory where the `package.json` and `tsconfig.json` are siblings.
2301                    // Even with all that, we still don't know if the root of the output file structure will be (relative to the package file)
2302                    // `.`, `./src` or any other deeper directory structure. (If project references are used, it's definitely `.` by fiat, so that should be pretty common.)
2303
2304                    const getCanonicalFileName = hostGetCanonicalFileName({ useCaseSensitiveFileNames });
2305                    const commonSourceDirGuesses: string[] = [];
2306                    // A `rootDir` compiler option strongly indicates the root location
2307                    // A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations
2308                    if (state.compilerOptions.rootDir || (state.compilerOptions.composite && state.compilerOptions.configFilePath)) {
2309                        const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [], state.host.getCurrentDirectory?.() || "", getCanonicalFileName));
2310                        commonSourceDirGuesses.push(commonDir);
2311                    }
2312                    else if (state.requestContainingDirectory) {
2313                        // However without either of those set we're in the dark. Let's say you have
2314                        //
2315                        // ./tools/index.ts
2316                        // ./src/index.ts
2317                        // ./dist/index.js
2318                        // ./package.json <-- references ./dist/index.js
2319                        // ./tsconfig.json <-- loads ./src/index.ts
2320                        //
2321                        // How do we know `./src` is the common src dir, and not `./tools`, given only the `./dist` out dir and `./dist/index.js` filename?
2322                        // Answer: We... don't. We know we're looking for an `index.ts` input file, but we have _no clue_ which subfolder it's supposed to be loaded from
2323                        // without more context.
2324                        // But we do have more context! Just a tiny bit more! We're resolving an import _for some other input file_! And that input file, too
2325                        // must be inside the common source directory! So we propagate that tidbit of info all the way to here via state.requestContainingDirectory
2326
2327                        const requestingFile = toAbsolutePath(combinePaths(state.requestContainingDirectory, "index.ts"));
2328                        // And we can try every folder above the common folder for the request folder and the config/package base directory
2329                        // This technically can be wrong - we may load ./src/index.ts when ./src/sub/index.ts was right because we don't
2330                        // know if only `./src/sub` files were loaded by the program; but this has the best chance to be right of just about anything
2331                        // else we have. And, given that we're about to load `./src/index.ts` because we choose it as likely correct, there will then
2332                        // be a file outside of `./src/sub` in the program (the file we resolved to), making us de-facto right. So this fallback lookup
2333                        // logic may influence what files are pulled in by self-names, which in turn influences the output path shape, but it's all
2334                        // internally consistent so the paths should be stable so long as we prefer the "most general" (meaning: top-most-level directory) possible results first.
2335                        const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [requestingFile, toAbsolutePath(packagePath)], state.host.getCurrentDirectory?.() || "", getCanonicalFileName));
2336                        commonSourceDirGuesses.push(commonDir);
2337
2338                        let fragment = ensureTrailingDirectorySeparator(commonDir);
2339                        while (fragment && fragment.length > 1) {
2340                            const parts = getPathComponents(fragment);
2341                            parts.pop(); // remove a directory
2342                            const commonDir = getPathFromPathComponents(parts);
2343                            commonSourceDirGuesses.unshift(commonDir);
2344                            fragment = ensureTrailingDirectorySeparator(commonDir);
2345                        }
2346                    }
2347                    if (commonSourceDirGuesses.length > 1) {
2348                        state.reportDiagnostic(createCompilerDiagnostic(
2349                            isImports
2350                                ? Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate
2351                                : Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate,
2352                            entry === "" ? "." : entry, // replace empty string with `.` - the reverse of the operation done when entries are built - so main entrypoint errors don't look weird
2353                            packagePath
2354                        ));
2355                    }
2356                    for (const commonSourceDirGuess of commonSourceDirGuesses) {
2357                        const candidateDirectories = getOutputDirectoriesForBaseDirectory(commonSourceDirGuess);
2358                        for (const candidateDir of candidateDirectories) {
2359                            if (containsPath(candidateDir, finalPath, !useCaseSensitiveFileNames())) {
2360                                // The matched export is looking up something in either the out declaration or js dir, now map the written path back into the source dir and source extension
2361                                const pathFragment = finalPath.slice(candidateDir.length + 1); // +1 to also remove directory seperator
2362                                const possibleInputBase = combinePaths(commonSourceDirGuess, pathFragment);
2363                                const jsAndDtsExtensions = [Extension.Mjs, Extension.Cjs, Extension.Js, Extension.Json, Extension.Dmts, Extension.Dcts, Extension.Dts];
2364                                for (const ext of jsAndDtsExtensions) {
2365                                    if (fileExtensionIs(possibleInputBase, ext)) {
2366                                        const inputExts = getPossibleOriginalInputExtensionForExtension(possibleInputBase);
2367                                        for (const possibleExt of inputExts) {
2368                                            const possibleInputWithInputExtension = changeAnyExtension(possibleInputBase, possibleExt, ext, !useCaseSensitiveFileNames());
2369                                            if ((extensions === Extensions.TypeScript && hasJSFileExtension(possibleInputWithInputExtension)) ||
2370                                                (extensions === Extensions.JavaScript && hasTSFileExtension(possibleInputWithInputExtension))) {
2371                                                continue;
2372                                            }
2373                                            if (state.host.fileExists(possibleInputWithInputExtension)) {
2374                                                return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state)));
2375                                            }
2376                                        }
2377                                    }
2378                                }
2379                            }
2380                        }
2381                    }
2382                }
2383                return undefined;
2384
2385                function getOutputDirectoriesForBaseDirectory(commonSourceDirGuess: string) {
2386                    // Config file ouput paths are processed to be relative to the host's current directory, while
2387                    // otherwise the paths are resolved relative to the common source dir the compiler puts together
2388                    const currentDir = state.compilerOptions.configFile ? state.host.getCurrentDirectory?.() || "" : commonSourceDirGuess;
2389                    const candidateDirectories = [];
2390                    if (state.compilerOptions.declarationDir) {
2391                        candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.declarationDir)));
2392                    }
2393                    if (state.compilerOptions.outDir && state.compilerOptions.outDir !== state.compilerOptions.declarationDir) {
2394                        candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.outDir)));
2395                    }
2396                    return candidateDirectories;
2397                }
2398            }
2399        }
2400    }
2401
2402    /* @internal */
2403    export function isApplicableVersionedTypesKey(conditions: readonly string[], key: string) {
2404        if (conditions.indexOf("types") === -1) return false; // only apply versioned types conditions if the types condition is applied
2405        if (!startsWith(key, "types@")) return false;
2406        const range = VersionRange.tryParse(key.substring("types@".length));
2407        if (!range) return false;
2408        return range.test(version);
2409    }
2410
2411    function loadModuleFromNearestNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
2412        return loadModuleFromNearestNodeModulesDirectoryWorker(extensions, moduleName, directory, state, /*typesScopeOnly*/ false, cache, redirectedReference);
2413    }
2414
2415    function loadModuleFromNearestModulesDirectoryTypesScope(moduleName: string, directory: string, state: ModuleResolutionState): SearchResult<Resolved> {
2416        // Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
2417        return loadModuleFromNearestNodeModulesDirectoryWorker(Extensions.DtsOnly, moduleName, directory, state, /*typesScopeOnly*/ true, /*cache*/ undefined, /*redirectedReference*/ undefined);
2418    }
2419
2420    function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
2421        const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName, state.features === 0 ? undefined : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS, redirectedReference);
2422        const packageManagerType = state.compilerOptions.packageManagerType;
2423        const modulePathPart = getModuleByPMType(packageManagerType);
2424        return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => {
2425            if (getBaseFileName(ancestorDirectory) !== modulePathPart) {
2426                const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state);
2427                if (resolutionFromCache) {
2428                    return resolutionFromCache;
2429                }
2430                return toSearchResult(loadModuleFromImmediateNodeModulesDirectory(extensions, moduleName, ancestorDirectory, state, typesScopeOnly, cache, redirectedReference));
2431            }
2432        });
2433    }
2434
2435    function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): Resolved | undefined {
2436        const nodeModulesFolder = combinePaths(directory, getModuleByPMType(state.compilerOptions.packageManagerType));
2437        const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
2438        if (!nodeModulesFolderExists && state.traceEnabled) {
2439            trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesFolder);
2440        }
2441
2442        const packageResult = typesScopeOnly ? undefined : loadModuleFromSpecificNodeModulesDirectory(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, state, cache, redirectedReference);
2443        if (packageResult) {
2444            return packageResult;
2445        }
2446        if (extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) {
2447            const modulesAtTypes = combinePaths(nodeModulesFolder, "@types");
2448            let nodeModulesAtTypesExists = nodeModulesFolderExists;
2449            if (nodeModulesFolderExists && !directoryProbablyExists(modulesAtTypes, state.host)) {
2450                if (state.traceEnabled) {
2451                    trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, modulesAtTypes);
2452                }
2453                nodeModulesAtTypesExists = false;
2454            }
2455            return loadModuleFromSpecificNodeModulesDirectory(Extensions.DtsOnly, mangleScopedPackageNameWithTrace(moduleName, state), modulesAtTypes, nodeModulesAtTypesExists, state, cache, redirectedReference);
2456        }
2457    }
2458
2459    function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, moduleName: string, nodeModulesDirectory: string, nodeModulesDirectoryExists: boolean, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): Resolved | undefined {
2460        const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName));
2461
2462        // If oh_modules exist, look for a nested oh-package.json5, as in `oh_modules/foo/bar/oh-package.json5`.
2463        // Otherwise, look for a nested package.json, as in `node_modules/foo/bar/package.json`.
2464        let packageInfo = getPackageJsonInfo(candidate, !nodeModulesDirectoryExists, state);
2465        // But only if we're not respecting export maps (if we are, we might redirect around this location)
2466        if (!(state.features & NodeResolutionFeatures.Exports)) {
2467            if (packageInfo) {
2468                const fromFile = loadModuleFromFile(extensions, candidate, !nodeModulesDirectoryExists, state);
2469                if (fromFile) {
2470                    return noPackageId(fromFile);
2471                }
2472
2473                const fromDirectory = loadNodeModuleFromDirectoryWorker(
2474                    extensions,
2475                    candidate,
2476                    !nodeModulesDirectoryExists,
2477                    state,
2478                    packageInfo.contents.packageJsonContent,
2479                    packageInfo.contents.versionPaths
2480                );
2481                return withPackageId(packageInfo, fromDirectory);
2482            }
2483        }
2484
2485        const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
2486            let pathAndExtension =
2487                loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) ||
2488                loadNodeModuleFromDirectoryWorker(
2489                    extensions,
2490                    candidate,
2491                    onlyRecordFailures,
2492                    state,
2493                    packageInfo && packageInfo.contents.packageJsonContent,
2494                    packageInfo && packageInfo.contents.versionPaths
2495                );
2496            if (
2497                !pathAndExtension && packageInfo
2498                // eslint-disable-next-line no-null/no-null
2499                && (packageInfo.contents.packageJsonContent.exports === undefined || packageInfo.contents.packageJsonContent.exports === null)
2500                && state.features & NodeResolutionFeatures.EsmMode
2501            ) {
2502                // EsmMode disables index lookup in `loadNodeModuleFromDirectoryWorker` generally, however non-relative package resolutions still assume
2503                // a default `index.js` entrypoint if no `main` or `exports` are present
2504                pathAndExtension = loadModuleFromFile(extensions, combinePaths(candidate, "index.js"), onlyRecordFailures, state);
2505            }
2506            return withPackageId(packageInfo, pathAndExtension);
2507        };
2508
2509        const { packageName, rest } = parsePackageName(moduleName);
2510        const packageDirectory = combinePaths(nodeModulesDirectory, packageName);
2511        if (rest !== "") {
2512            // Previous `packageInfo` may have been from a nested package.json; ensure we have the one from the package root now.
2513            packageInfo = getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state);
2514        }
2515        // package exports are higher priority than file/directory/typesVersions lookups and (and, if there's exports present, blocks them)
2516        if (packageInfo && packageInfo.contents.packageJsonContent.exports && state.features & NodeResolutionFeatures.Exports) {
2517            return loadModuleFromExports(packageInfo, extensions, combinePaths(".", rest), state, cache, redirectedReference)?.value;
2518        }
2519        if (rest !== "" && packageInfo && packageInfo.contents.versionPaths) {
2520            if (state.traceEnabled) {
2521                trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, packageInfo.contents.versionPaths.version, version, rest);
2522            }
2523            const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
2524            const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, packageInfo.contents.versionPaths.paths, /*pathPatterns*/ undefined, loader, !packageDirectoryExists, state);
2525            if (fromPaths) {
2526                return fromPaths.value;
2527            }
2528        }
2529
2530        return loader(extensions, candidate, !nodeModulesDirectoryExists, state);
2531    }
2532
2533    function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike<string[]>, pathPatterns: readonly (string | Pattern)[] | undefined, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult<Resolved> {
2534        pathPatterns ||= tryParsePatterns(paths);
2535        const matchedPattern = matchPatternOrExact(pathPatterns, moduleName);
2536        if (matchedPattern) {
2537            const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
2538            const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
2539            if (state.traceEnabled) {
2540                trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
2541            }
2542            const resolved = forEach(paths[matchedPatternText], subst => {
2543                const path = matchedStar ? subst.replace("*", matchedStar) : subst;
2544                // When baseUrl is not specified, the command line parser resolves relative paths to the config file location.
2545                const candidate = normalizePath(combinePaths(baseDirectory, path));
2546                if (state.traceEnabled) {
2547                    trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
2548                }
2549                // A path mapping may have an extension, in contrast to an import, which should omit it.
2550                const extension = tryGetExtensionFromPath(subst);
2551                if (extension !== undefined) {
2552                    const path = tryFile(candidate, onlyRecordFailures, state);
2553                    if (path !== undefined) {
2554                        return noPackageId({ path, ext: extension });
2555                    }
2556                }
2557                return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
2558            });
2559            return { value: resolved };
2560        }
2561    }
2562
2563    /** Double underscores are used in DefinitelyTyped to delimit scoped packages. */
2564    const mangledScopedPackageSeparator = "__";
2565
2566    /** For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`. */
2567    function mangleScopedPackageNameWithTrace(packageName: string, state: ModuleResolutionState): string {
2568        const mangled = mangleScopedPackageName(packageName);
2569        if (state.traceEnabled && mangled !== packageName) {
2570            trace(state.host, Diagnostics.Scoped_package_detected_looking_in_0, mangled);
2571        }
2572        return mangled;
2573    }
2574
2575    /* @internal */
2576    export function getTypesPackageName(packageName: string): string {
2577        return `@types/${mangleScopedPackageName(packageName)}`;
2578    }
2579
2580    /* @internal */
2581    export function mangleScopedPackageName(packageName: string): string {
2582        if (startsWith(packageName, "@")) {
2583            const replaceSlash = packageName.replace(directorySeparator, mangledScopedPackageSeparator);
2584            if (replaceSlash !== packageName) {
2585                return replaceSlash.slice(1); // Take off the "@"
2586            }
2587        }
2588        return packageName;
2589    }
2590
2591    /* @internal */
2592    export function getPackageNameFromTypesPackageName(mangledName: string): string {
2593        const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
2594        if (withoutAtTypePrefix !== mangledName) {
2595            return unmangleScopedPackageName(withoutAtTypePrefix);
2596        }
2597        return mangledName;
2598    }
2599
2600    /* @internal */
2601    export function unmangleScopedPackageName(typesPackageName: string): string {
2602        return stringContains(typesPackageName, mangledScopedPackageSeparator) ?
2603            "@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) :
2604            typesPackageName;
2605    }
2606
2607    function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, state: ModuleResolutionState): SearchResult<Resolved> {
2608        const result = cache && cache.get(containingDirectory);
2609        if (result) {
2610            if (state.traceEnabled) {
2611                trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
2612            }
2613            state.resultFromCache = result;
2614            return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
2615        }
2616    }
2617
2618    export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations {
2619        const traceEnabled = isTraceEnabled(compilerOptions, host);
2620        const failedLookupLocations: string[] = [];
2621        const affectingLocations: string[] = [];
2622        const containingDirectory = getDirectoryPath(containingFile);
2623        const diagnostics: Diagnostic[] = [];
2624        const state: ModuleResolutionState = {
2625            compilerOptions,
2626            host,
2627            traceEnabled,
2628            failedLookupLocations,
2629            affectingLocations, packageJsonInfoCache: cache,
2630            features: NodeResolutionFeatures.None,
2631            conditions: [],
2632            requestContainingDirectory: containingDirectory,
2633            reportDiagnostic: diag => void diagnostics.push(diag),
2634        };
2635
2636        const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
2637        // No originalPath because classic resolution doesn't resolve realPath
2638        return createResolvedModuleWithFailedLookupLocations(
2639            resolved && resolved.value,
2640             /*isExternalLibraryImport*/ false,
2641            failedLookupLocations,
2642            affectingLocations,
2643            diagnostics,
2644            state.resultFromCache
2645        );
2646
2647        function tryResolve(extensions: Extensions): SearchResult<Resolved> {
2648            const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state);
2649            if (resolvedUsingSettings) {
2650                return { value: resolvedUsingSettings };
2651            }
2652
2653            if (!isExternalModuleNameRelative(moduleName)) {
2654                const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName, /*mode*/ undefined, redirectedReference);
2655                // Climb up parent directories looking for a module.
2656                const resolved = forEachAncestorDirectory(containingDirectory, directory => {
2657                    const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, state);
2658                    if (resolutionFromCache) {
2659                        return resolutionFromCache;
2660                    }
2661                    const searchName = normalizePath(combinePaths(directory, moduleName));
2662                    return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state));
2663                });
2664                if (resolved) {
2665                    return resolved;
2666                }
2667                if (extensions === Extensions.TypeScript) {
2668                    // If we didn't find the file normally, look it up in @types.
2669                    return loadModuleFromNearestModulesDirectoryTypesScope(moduleName, containingDirectory, state);
2670                }
2671            }
2672            else {
2673                const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
2674                return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state));
2675            }
2676        }
2677    }
2678
2679    /**
2680     * A host may load a module from a global cache of typings.
2681     * This is the minumum code needed to expose that functionality; the rest is in the host.
2682     */
2683    /* @internal */
2684    export function loadModuleFromGlobalCache(moduleName: string, projectName: string | undefined, compilerOptions: CompilerOptions, host: ModuleResolutionHost, globalCache: string, packageJsonInfoCache: PackageJsonInfoCache): ResolvedModuleWithFailedLookupLocations {
2685        const traceEnabled = isTraceEnabled(compilerOptions, host);
2686        if (traceEnabled) {
2687            trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache);
2688        }
2689        const failedLookupLocations: string[] = [];
2690        const affectingLocations: string[] = [];
2691        const diagnostics: Diagnostic[] = [];
2692        const state: ModuleResolutionState = {
2693            compilerOptions,
2694            host,
2695            traceEnabled,
2696            failedLookupLocations,
2697            affectingLocations,
2698            packageJsonInfoCache,
2699            features: NodeResolutionFeatures.None,
2700            conditions: [],
2701            requestContainingDirectory: undefined,
2702            reportDiagnostic: diag => void diagnostics.push(diag),
2703        };
2704        const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false, /*cache*/ undefined, /*redirectedReference*/ undefined);
2705        return createResolvedModuleWithFailedLookupLocations(
2706            resolved,
2707            /*isExternalLibraryImport*/ true,
2708            failedLookupLocations,
2709            affectingLocations,
2710            diagnostics,
2711            state.resultFromCache
2712        );
2713    }
2714
2715    /**
2716     * Represents result of search. Normally when searching among several alternatives we treat value `undefined` as indicator
2717     * that search fails and we should try another option.
2718     * However this does not allow us to represent final result that should be used instead of further searching (i.e. a final result that was found in cache).
2719     * SearchResult is used to deal with this issue, its values represents following outcomes:
2720     * - undefined - not found, continue searching
2721     * - { value: undefined } - not found - stop searching
2722     * - { value: <some-value> } - found - stop searching
2723     */
2724    type SearchResult<T> = { value: T | undefined } | undefined;
2725
2726    /**
2727     * Wraps value to SearchResult.
2728     * @returns undefined if value is undefined or { value } otherwise
2729     */
2730    function toSearchResult<T>(value: T | undefined): SearchResult<T> {
2731        return value !== undefined ? { value } : undefined;
2732    }
2733
2734    function traceIfEnabled(state: ModuleResolutionState, diagnostic: DiagnosticMessage, ...args: string[]) {
2735        if (state.traceEnabled) {
2736            trace(state.host, diagnostic, ...args);
2737        }
2738    }
2739}
2740