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