|
|
|
|
@@ -24,6 +24,13 @@ namespace ts {
|
|
|
|
|
return withPackageId(/*packageId*/ undefined, r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined {
|
|
|
|
|
if (r) {
|
|
|
|
|
Debug.assert(r.packageId === undefined);
|
|
|
|
|
return { path: r.path, ext: r.extension };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Result of trying to resolve a module. */
|
|
|
|
|
interface Resolved {
|
|
|
|
|
path: string;
|
|
|
|
|
@@ -82,13 +89,14 @@ namespace ts {
|
|
|
|
|
host: ModuleResolutionHost;
|
|
|
|
|
compilerOptions: CompilerOptions;
|
|
|
|
|
traceEnabled: boolean;
|
|
|
|
|
failedLookupLocations: Push<string>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Just the fields that we use for module resolution. */
|
|
|
|
|
interface PackageJsonPathFields {
|
|
|
|
|
typings?: string;
|
|
|
|
|
types?: string;
|
|
|
|
|
typesVersions?: MapLike<string>;
|
|
|
|
|
typesVersions?: MapLike<MapLike<string[]>>;
|
|
|
|
|
main?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -97,42 +105,89 @@ namespace ts {
|
|
|
|
|
version?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
|
|
|
|
|
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJsonPathFields, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
|
|
|
|
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
|
|
|
|
|
type MatchingKeys<TRecord, TMatch, K extends keyof TRecord = keyof TRecord> = K extends (TRecord[K] extends TMatch ? K : never) ? K : never;
|
|
|
|
|
|
|
|
|
|
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
|
|
|
|
|
if (!hasProperty(jsonContent, fieldName)) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fileName = jsonContent[fieldName];
|
|
|
|
|
if (!isString(fileName)) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, "string", typeof fileName);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const path = normalizePath(combinePaths(baseDirectory, fileName));
|
|
|
|
|
function readPackageJsonField<TMatch, K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
|
|
|
|
|
function readPackageJsonField<K extends MatchingKeys<PackageJson, object | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined;
|
|
|
|
|
function readPackageJsonField<K extends keyof PackageJson>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined {
|
|
|
|
|
if (!hasProperty(jsonContent, fieldName)) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
|
|
|
|
|
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const value = jsonContent[fieldName];
|
|
|
|
|
if (typeof value !== typeOfTag || value === null) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, typeOfTag, value === null ? "null" : typeof value);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* @internal */
|
|
|
|
|
export function getPackageJsonTypesVersionsOverride(typesVersions: MapLike<string>) {
|
|
|
|
|
return getPackageJsonTypesVersionsOverrideWithTrace(typesVersions, /*state*/ undefined);
|
|
|
|
|
function readPackageJsonPathField<K extends "typings" | "types" | "main">(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined {
|
|
|
|
|
const fileName = readPackageJsonField(jsonContent, fieldName, "string", state);
|
|
|
|
|
if (fileName === undefined) return;
|
|
|
|
|
const path = normalizePath(combinePaths(baseDirectory, fileName));
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readPackageJsonTypesFields(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
|
|
|
|
|
return readPackageJsonPathField(jsonContent, "typings", baseDirectory, state)
|
|
|
|
|
|| readPackageJsonPathField(jsonContent, "types", baseDirectory, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readPackageJsonMainField(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
|
|
|
|
|
return readPackageJsonPathField(jsonContent, "main", baseDirectory, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readPackageJsonTypesVersionsField(jsonContent: PackageJson, state: ModuleResolutionState) {
|
|
|
|
|
const typesVersions = readPackageJsonField(jsonContent, "typesVersions", "object", state);
|
|
|
|
|
if (typesVersions === undefined) return;
|
|
|
|
|
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_has_a_typesVersions_field_with_version_specific_path_mappings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return typesVersions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface VersionPaths {
|
|
|
|
|
version: string;
|
|
|
|
|
paths: MapLike<string[]>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: ModuleResolutionState): VersionPaths | undefined {
|
|
|
|
|
const typesVersions = readPackageJsonTypesVersionsField(jsonContent, state);
|
|
|
|
|
if (typesVersions === undefined) return;
|
|
|
|
|
|
|
|
|
|
const result = getPackageJsonTypesVersionsPaths(typesVersions);
|
|
|
|
|
if (!result) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { version: bestVersionKey, paths: bestVersionPaths } = result;
|
|
|
|
|
if (typeof bestVersionPaths !== "object") {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "object", typeof bestVersionPaths);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let typeScriptVersion: Version | undefined;
|
|
|
|
|
|
|
|
|
|
function getPackageJsonTypesVersionsOverrideWithTrace(typesVersions: MapLike<string>, state: ModuleResolutionState | undefined) {
|
|
|
|
|
/* @internal */
|
|
|
|
|
export function getPackageJsonTypesVersionsPaths(typesVersions: MapLike<MapLike<string[]>>) {
|
|
|
|
|
if (!typeScriptVersion) typeScriptVersion = new Version(versionMajorMinor);
|
|
|
|
|
|
|
|
|
|
let bestVersion: Version | undefined;
|
|
|
|
|
@@ -142,9 +197,6 @@ namespace ts {
|
|
|
|
|
|
|
|
|
|
const keyVersion = Version.tryParse(key);
|
|
|
|
|
if (keyVersion === undefined) {
|
|
|
|
|
if (state && state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_has_invalid_version_0_in_typesVersions_field, key);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -160,47 +212,7 @@ namespace ts {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { version: bestVersionKey, directory: typesVersions[bestVersionKey] };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tryReadPackageJsonTypesVersion(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
|
|
|
|
if (!hasProperty(jsonContent, "typesVersions")) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, "typesVersions");
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const typesVersions = jsonContent.typesVersions;
|
|
|
|
|
if (typeof typesVersions !== "object") {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, "typesVersions", "object", typeof typesVersions);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const result = getPackageJsonTypesVersionsOverrideWithTrace(typesVersions, state);
|
|
|
|
|
if (!result) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { version: bestVersionKey, directory: bestVersionPath } = result;
|
|
|
|
|
if (!isString(bestVersionPath)) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "string", typeof bestVersionPath);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
const path = normalizePath(combinePaths(baseDirectory, bestVersionPath));
|
|
|
|
|
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, `typesVersions['${bestVersionKey}']`, bestVersionPath, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bestVersionPath;
|
|
|
|
|
return { version: bestVersionKey, paths: typesVersions[bestVersionKey] };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined {
|
|
|
|
|
@@ -250,7 +262,8 @@ namespace ts {
|
|
|
|
|
*/
|
|
|
|
|
export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
|
|
|
|
const traceEnabled = isTraceEnabled(options, host);
|
|
|
|
|
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled };
|
|
|
|
|
const failedLookupLocations: string[] = [];
|
|
|
|
|
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations };
|
|
|
|
|
|
|
|
|
|
const typeRoots = getEffectiveTypeRoots(options, host);
|
|
|
|
|
if (traceEnabled) {
|
|
|
|
|
@@ -272,8 +285,6 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const failedLookupLocations: string[] = [];
|
|
|
|
|
|
|
|
|
|
let resolved = primaryLookup();
|
|
|
|
|
let primary = true;
|
|
|
|
|
if (!resolved) {
|
|
|
|
|
@@ -309,7 +320,7 @@ namespace ts {
|
|
|
|
|
trace(host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, candidateDirectory);
|
|
|
|
|
}
|
|
|
|
|
return resolvedTypeScriptOnly(
|
|
|
|
|
loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate, failedLookupLocations,
|
|
|
|
|
loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate,
|
|
|
|
|
!directoryExists, moduleResolutionState));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
@@ -328,7 +339,7 @@ namespace ts {
|
|
|
|
|
if (traceEnabled) {
|
|
|
|
|
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
|
|
|
|
|
}
|
|
|
|
|
const result = loadModuleFromNodeModules(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, failedLookupLocations, moduleResolutionState, /*cache*/ undefined);
|
|
|
|
|
const result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined);
|
|
|
|
|
const resolvedFile = resolvedTypeScriptOnly(result && result.value);
|
|
|
|
|
if (!resolvedFile && traceEnabled) {
|
|
|
|
|
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
|
|
|
|
|
@@ -366,7 +377,7 @@ namespace ts {
|
|
|
|
|
if (host.directoryExists(root)) {
|
|
|
|
|
for (const typeDirectivePath of host.getDirectories(root)) {
|
|
|
|
|
const normalized = normalizePath(typeDirectivePath);
|
|
|
|
|
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
|
|
|
|
|
const packageJsonPath = combinePaths(root, normalized, "package.json");
|
|
|
|
|
// `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
|
|
|
|
|
// See `createNotNeededPackageJSON` in the types-publisher` repo.
|
|
|
|
|
// tslint:disable-next-line:no-null-keyword
|
|
|
|
|
@@ -589,7 +600,7 @@ namespace ts {
|
|
|
|
|
* 'typings' entry or file 'index' with some supported extension
|
|
|
|
|
* - Classic loader will only try to interpret '/a/b/c' as file.
|
|
|
|
|
*/
|
|
|
|
|
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
|
|
|
|
|
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to
|
|
|
|
|
@@ -652,18 +663,18 @@ namespace ts {
|
|
|
|
|
* entries in 'rootDirs', use them to build absolute path out of (*) and try to resolve module from this location.
|
|
|
|
|
*/
|
|
|
|
|
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
|
|
|
|
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
|
|
|
|
|
if (!isExternalModuleNameRelative(moduleName)) {
|
|
|
|
|
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
|
|
|
|
|
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
|
|
|
|
|
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
|
|
|
|
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
|
|
|
|
|
if (!state.compilerOptions.rootDirs) {
|
|
|
|
|
return undefined;
|
|
|
|
|
@@ -708,7 +719,7 @@ namespace ts {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, matchedNormalizedPrefix, candidate);
|
|
|
|
|
}
|
|
|
|
|
const resolvedFileName = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(containingDirectory, state.host), state);
|
|
|
|
|
const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(containingDirectory, state.host), state);
|
|
|
|
|
if (resolvedFileName) {
|
|
|
|
|
return resolvedFileName;
|
|
|
|
|
}
|
|
|
|
|
@@ -727,7 +738,7 @@ namespace ts {
|
|
|
|
|
trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, rootDir, candidate);
|
|
|
|
|
}
|
|
|
|
|
const baseDirectory = getDirectoryPath(candidate);
|
|
|
|
|
const resolvedFileName = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(baseDirectory, state.host), state);
|
|
|
|
|
const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(baseDirectory, state.host), state);
|
|
|
|
|
if (resolvedFileName) {
|
|
|
|
|
return resolvedFileName;
|
|
|
|
|
}
|
|
|
|
|
@@ -739,59 +750,28 @@ namespace ts {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
if (!state.compilerOptions.baseUrl) {
|
|
|
|
|
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
const { baseUrl, paths } = state.compilerOptions;
|
|
|
|
|
if (!baseUrl) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, state.compilerOptions.baseUrl, moduleName);
|
|
|
|
|
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// string is for exact match
|
|
|
|
|
let matchedPattern: Pattern | string | undefined;
|
|
|
|
|
if (state.compilerOptions.paths) {
|
|
|
|
|
if (paths) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
|
|
|
|
|
}
|
|
|
|
|
matchedPattern = matchPatternOrExact(getOwnKeys(state.compilerOptions.paths), moduleName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (matchedPattern) {
|
|
|
|
|
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
|
|
|
|
|
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
|
|
|
|
|
const resolved = tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
|
|
|
|
|
if (resolved) {
|
|
|
|
|
return resolved.value;
|
|
|
|
|
}
|
|
|
|
|
return forEach(state.compilerOptions.paths![matchedPatternText], subst => {
|
|
|
|
|
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
|
|
|
|
|
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl!, path));
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
|
|
|
|
|
}
|
|
|
|
|
// A path mapping may have an extension, in contrast to an import, which should omit it.
|
|
|
|
|
const extension = tryGetExtensionFromPath(candidate);
|
|
|
|
|
if (extension !== undefined) {
|
|
|
|
|
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
|
|
|
|
if (path !== undefined) {
|
|
|
|
|
return noPackageId({ path, ext: extension });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, moduleName));
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, state.compilerOptions.baseUrl, candidate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
|
|
|
|
const candidate = normalizePath(combinePaths(baseUrl, moduleName));
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
|
|
|
|
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
|
|
|
|
|
return loader(extensions, candidate, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -809,11 +789,15 @@ namespace ts {
|
|
|
|
|
return resolvedModule.resolvedFileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
|
|
|
|
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function nodeModuleNameResolverWorker(moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, jsOnly: boolean): ResolvedModuleWithFailedLookupLocations {
|
|
|
|
|
const traceEnabled = isTraceEnabled(compilerOptions, host);
|
|
|
|
|
|
|
|
|
|
const failedLookupLocations: string[] = [];
|
|
|
|
|
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
|
|
|
|
|
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
|
|
|
|
|
|
|
|
|
|
const result = jsOnly ?
|
|
|
|
|
tryResolve(Extensions.JavaScript) :
|
|
|
|
|
@@ -827,8 +811,8 @@ namespace ts {
|
|
|
|
|
return { resolvedModule: undefined, failedLookupLocations };
|
|
|
|
|
|
|
|
|
|
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
|
|
|
|
|
const loader: ResolutionKindSpecificLoader = (extensions, candidate, failedLookupLocations, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ true);
|
|
|
|
|
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
|
|
|
|
|
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
|
|
|
|
|
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state);
|
|
|
|
|
if (resolved) {
|
|
|
|
|
return toSearchResult({ resolved, isExternalLibraryImport: stringContains(resolved.path, nodeModulesPathPart) });
|
|
|
|
|
}
|
|
|
|
|
@@ -837,7 +821,7 @@ namespace ts {
|
|
|
|
|
if (traceEnabled) {
|
|
|
|
|
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
|
|
|
|
|
}
|
|
|
|
|
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
|
|
|
|
|
const resolved = loadModuleFromNearestNodeModulesDirectory(extensions, moduleName, containingDirectory, state, cache);
|
|
|
|
|
if (!resolved) return undefined;
|
|
|
|
|
|
|
|
|
|
let resolvedValue = resolved.value;
|
|
|
|
|
@@ -851,7 +835,7 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
|
|
|
|
|
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
|
|
|
|
|
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
|
|
|
|
|
// Treat explicit "node_modules" import as an external library import.
|
|
|
|
|
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
|
|
|
|
|
}
|
|
|
|
|
@@ -871,7 +855,7 @@ namespace ts {
|
|
|
|
|
return real;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
|
|
|
|
|
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
|
|
|
|
|
}
|
|
|
|
|
@@ -885,10 +869,11 @@ namespace ts {
|
|
|
|
|
onlyRecordFailures = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
|
|
|
|
|
const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state);
|
|
|
|
|
if (resolvedFromFile) {
|
|
|
|
|
const nm = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile) : undefined;
|
|
|
|
|
const packageId = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, failedLookupLocations, /*onlyRecordFailures*/ false, state).packageId;
|
|
|
|
|
const packageInfo = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, /*onlyRecordFailures*/ false, state);
|
|
|
|
|
const packageId = packageInfo && packageInfo.packageId;
|
|
|
|
|
return withPackageId(packageId, resolvedFromFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -901,7 +886,7 @@ namespace ts {
|
|
|
|
|
onlyRecordFailures = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, considerPackageJson);
|
|
|
|
|
return loadNodeModuleFromDirectory(extensions, candidate, onlyRecordFailures, state, considerPackageJson);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*@internal*/
|
|
|
|
|
@@ -953,22 +938,22 @@ namespace ts {
|
|
|
|
|
return path + "/index.d.ts";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
|
|
|
|
|
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
|
|
|
|
function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
|
|
|
|
if (extensions === Extensions.Json) {
|
|
|
|
|
const extensionLess = tryRemoveExtension(candidate, Extension.Json);
|
|
|
|
|
return extensionLess === undefined ? undefined : tryAddingExtensions(extensionLess, extensions, failedLookupLocations, onlyRecordFailures, state);
|
|
|
|
|
return extensionLess === undefined ? undefined : tryAddingExtensions(extensionLess, extensions, onlyRecordFailures, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
|
|
|
|
|
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
|
|
|
|
|
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, onlyRecordFailures, state);
|
|
|
|
|
if (resolvedByAddingExtension) {
|
|
|
|
|
return resolvedByAddingExtension;
|
|
|
|
|
}
|
|
|
|
|
@@ -981,12 +966,12 @@ namespace ts {
|
|
|
|
|
const extension = candidate.substring(extensionless.length);
|
|
|
|
|
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
|
|
|
|
|
}
|
|
|
|
|
return tryAddingExtensions(extensionless, extensions, failedLookupLocations, onlyRecordFailures, state);
|
|
|
|
|
return tryAddingExtensions(extensionless, extensions, onlyRecordFailures, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
|
|
|
|
|
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
|
|
|
|
function tryAddingExtensions(candidate: string, extensions: Extensions, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
|
|
|
|
if (!onlyRecordFailures) {
|
|
|
|
|
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
|
|
|
|
const directory = getDirectoryPath(candidate);
|
|
|
|
|
@@ -1007,13 +992,13 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tryExtension(ext: Extension): PathAndExtension | undefined {
|
|
|
|
|
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
|
|
|
|
|
const path = tryFile(candidate + ext, onlyRecordFailures, state);
|
|
|
|
|
return path === undefined ? undefined : { path, ext };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Return the file if it exists. */
|
|
|
|
|
function tryFile(fileName: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
|
|
|
|
|
function tryFile(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
|
|
|
|
|
if (!onlyRecordFailures) {
|
|
|
|
|
if (state.host.fileExists(fileName)) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
@@ -1027,52 +1012,48 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
failedLookupLocations.push(fileName);
|
|
|
|
|
state.failedLookupLocations.push(fileName);
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
|
|
|
|
|
const { packageJsonContent, packageId, versionPath } = considerPackageJson
|
|
|
|
|
? getPackageJsonInfo(candidate, "", failedLookupLocations, onlyRecordFailures, state)
|
|
|
|
|
: { packageJsonContent: undefined, packageId: undefined, versionPath: undefined };
|
|
|
|
|
if (versionPath) {
|
|
|
|
|
candidate = normalizePath(combinePaths(candidate, versionPath));
|
|
|
|
|
}
|
|
|
|
|
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent));
|
|
|
|
|
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
|
|
|
|
|
const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, "", onlyRecordFailures, state) : undefined;
|
|
|
|
|
const packageId = packageInfo && packageInfo.packageId;
|
|
|
|
|
const packageJsonContent = packageInfo && packageInfo.packageJsonContent;
|
|
|
|
|
const versionPaths = packageJsonContent && readPackageJsonTypesVersionPaths(packageJsonContent, state);
|
|
|
|
|
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJsonPathFields | undefined): PathAndExtension | undefined {
|
|
|
|
|
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state);
|
|
|
|
|
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJsonPathFields | undefined, versionPaths: VersionPaths | undefined): PathAndExtension | undefined {
|
|
|
|
|
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, versionPaths, extensions, candidate, state);
|
|
|
|
|
if (fromPackageJson) {
|
|
|
|
|
return fromPackageJson;
|
|
|
|
|
}
|
|
|
|
|
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
|
|
|
|
|
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
|
|
|
|
|
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), !directoryExists, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getPackageJsonInfo(
|
|
|
|
|
nodeModuleDirectory: string,
|
|
|
|
|
subModuleName: string,
|
|
|
|
|
failedLookupLocations: Push<string>,
|
|
|
|
|
onlyRecordFailures: boolean,
|
|
|
|
|
state: ModuleResolutionState,
|
|
|
|
|
): { found: boolean, packageJsonContent: PackageJsonPathFields | undefined, packageId: PackageId | undefined, versionPath: string | undefined } {
|
|
|
|
|
interface PackageJsonInfo {
|
|
|
|
|
packageJsonContent: PackageJsonPathFields | undefined;
|
|
|
|
|
packageId: PackageId | undefined;
|
|
|
|
|
versionPaths: VersionPaths | undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getPackageJsonInfo(packageDirectory: string, subModuleName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
|
|
|
|
|
const { host, traceEnabled } = state;
|
|
|
|
|
const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host);
|
|
|
|
|
const packageJsonPath = pathToPackageJson(nodeModuleDirectory);
|
|
|
|
|
const directoryExists = !onlyRecordFailures && directoryProbablyExists(packageDirectory, host);
|
|
|
|
|
const packageJsonPath = combinePaths(packageDirectory, "package.json");
|
|
|
|
|
if (directoryExists && host.fileExists(packageJsonPath)) {
|
|
|
|
|
const packageJsonContent = readJson(packageJsonPath, host) as PackageJson;
|
|
|
|
|
const versionPath = tryReadPackageJsonTypesVersion(packageJsonContent, nodeModuleDirectory, state);
|
|
|
|
|
if (subModuleName === "") { // looking up the root - need to handle types/typings/main redirects for subModuleName
|
|
|
|
|
const versionDirectory = versionPath ? normalizePath(combinePaths(nodeModuleDirectory, versionPath)) : nodeModuleDirectory;
|
|
|
|
|
const path = tryReadPackageJsonFields(/*readTypes*/ true, packageJsonContent, versionDirectory, state);
|
|
|
|
|
const path = readPackageJsonTypesFields(packageJsonContent, packageDirectory, state);
|
|
|
|
|
if (typeof path === "string") {
|
|
|
|
|
subModuleName = addExtensionAndIndex(path.substring(versionDirectory.length + 1));
|
|
|
|
|
subModuleName = addExtensionAndIndex(path.substring(packageDirectory.length + 1));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const jsPath = tryReadPackageJsonFields(/*readTypes*/ false, packageJsonContent, nodeModuleDirectory, state);
|
|
|
|
|
if (typeof jsPath === "string" && jsPath.length > nodeModuleDirectory.length) {
|
|
|
|
|
const potentialSubModule = jsPath.substring(nodeModuleDirectory.length + 1);
|
|
|
|
|
const jsPath = readPackageJsonMainField(packageJsonContent, packageDirectory, state);
|
|
|
|
|
if (typeof jsPath === "string" && jsPath.length > packageDirectory.length) {
|
|
|
|
|
const potentialSubModule = jsPath.substring(packageDirectory.length + 1);
|
|
|
|
|
subModuleName = (forEach(supportedJavascriptExtensions, extension =>
|
|
|
|
|
tryRemoveExtension(potentialSubModule, extension)) || potentialSubModule) + Extension.Dts;
|
|
|
|
|
}
|
|
|
|
|
@@ -1082,13 +1063,11 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (versionPath) {
|
|
|
|
|
subModuleName = combinePaths(versionPath, subModuleName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!endsWith(subModuleName, Extension.Dts)) {
|
|
|
|
|
subModuleName = addExtensionAndIndex(subModuleName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state);
|
|
|
|
|
const packageId: PackageId | undefined = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
|
|
|
|
|
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
|
|
|
|
|
: undefined;
|
|
|
|
|
@@ -1100,7 +1079,8 @@ namespace ts {
|
|
|
|
|
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return { found: true, packageJsonContent, packageId, versionPath };
|
|
|
|
|
|
|
|
|
|
return { packageJsonContent, packageId, versionPaths };
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (directoryExists && traceEnabled) {
|
|
|
|
|
@@ -1108,17 +1088,18 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
|
|
|
|
|
failedLookupLocations.push(packageJsonPath);
|
|
|
|
|
return { found: false, packageJsonContent: undefined, packageId: undefined, versionPath: undefined };
|
|
|
|
|
state.failedLookupLocations.push(packageJsonPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
|
|
|
|
let file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript && extensions !== Extensions.Json, jsonContent, candidate, state);
|
|
|
|
|
function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, versionPaths: VersionPaths | undefined, extensions: Extensions, candidate: string, state: ModuleResolutionState): PathAndExtension | undefined {
|
|
|
|
|
let file = extensions !== Extensions.JavaScript && extensions !== Extensions.Json
|
|
|
|
|
? readPackageJsonTypesFields(jsonContent, candidate, state)
|
|
|
|
|
: readPackageJsonMainField(jsonContent, candidate, state);
|
|
|
|
|
if (!file) {
|
|
|
|
|
if (extensions === Extensions.TypeScript) {
|
|
|
|
|
// When resolving typescript modules, try resolving using main field as well
|
|
|
|
|
file = tryReadPackageJsonFields(/*readTypes*/ false, jsonContent, candidate, state);
|
|
|
|
|
file = readPackageJsonMainField(jsonContent, candidate, state);
|
|
|
|
|
if (!file) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
@@ -1128,27 +1109,39 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host);
|
|
|
|
|
const fromFile = tryFile(file, failedLookupLocations, onlyRecordFailures, state);
|
|
|
|
|
if (fromFile) {
|
|
|
|
|
const resolved = resolvedIfExtensionMatches(extensions, fromFile);
|
|
|
|
|
if (resolved) {
|
|
|
|
|
return resolved;
|
|
|
|
|
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
|
|
|
|
|
const fromFile = tryFile(candidate, onlyRecordFailures, state);
|
|
|
|
|
if (fromFile) {
|
|
|
|
|
const resolved = resolvedIfExtensionMatches(extensions, fromFile);
|
|
|
|
|
if (resolved) {
|
|
|
|
|
return noPackageId(resolved);
|
|
|
|
|
}
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
|
|
|
|
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
|
|
|
|
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
|
|
|
|
return nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host);
|
|
|
|
|
|
|
|
|
|
if (versionPaths && containsPath(candidate, file)) {
|
|
|
|
|
const moduleName = getRelativePathFromDirectory(candidate, file, /*ignoreCase*/ false);
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
|
|
|
|
|
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, versionMajorMinor, moduleName);
|
|
|
|
|
}
|
|
|
|
|
const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, loader, onlyRecordFailures, state);
|
|
|
|
|
if (result) {
|
|
|
|
|
return removeIgnoredPackageId(result.value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
|
|
|
|
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
|
|
|
|
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
|
|
|
|
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
|
|
|
|
if (result) {
|
|
|
|
|
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
|
|
|
|
Debug.assert(result.packageId === undefined);
|
|
|
|
|
return { path: result.path, ext: result.extension };
|
|
|
|
|
}
|
|
|
|
|
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
|
|
|
|
return removeIgnoredPackageId(loader(extensions, file, onlyRecordFailures, state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
|
|
|
|
|
@@ -1171,42 +1164,6 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pathToPackageJson(directory: string): string {
|
|
|
|
|
return combinePaths(directory, "package.json");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
let candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
|
|
|
|
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
|
|
|
|
|
let packageJsonContent: PackageJsonPathFields | undefined;
|
|
|
|
|
let versionPath: string | undefined;
|
|
|
|
|
let packageId: PackageId | undefined;
|
|
|
|
|
const packageInfo = getPackageJsonInfo(candidate, "", failedLookupLocations, /*onlyRecordFailures*/ !nodeModulesFolderExists, state);
|
|
|
|
|
if (packageInfo.found) {
|
|
|
|
|
({ packageJsonContent, packageId, versionPath } = packageInfo);
|
|
|
|
|
|
|
|
|
|
// If package.json supplied a typescript-version prefix path, apply it to the candidate.
|
|
|
|
|
if (versionPath) {
|
|
|
|
|
candidate = normalizePath(combinePaths(candidate, versionPath));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const { packageName, rest } = parsePackageName(moduleName);
|
|
|
|
|
if (rest !== "") { // If "rest" is empty, we just did this search above.
|
|
|
|
|
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
|
|
|
|
|
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId.
|
|
|
|
|
({ packageId, versionPath } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state));
|
|
|
|
|
// If package.json supplied a typescript-version prefix path, apply it to the candidate.
|
|
|
|
|
if (versionPath) {
|
|
|
|
|
candidate = normalizePath(combinePaths(packageRootPath, versionPath, rest));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
|
|
|
|
loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent);
|
|
|
|
|
return withPackageId(packageId, pathAndExtension);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* @internal */
|
|
|
|
|
export function parsePackageName(moduleName: string): { packageName: string, rest: string } {
|
|
|
|
|
let idx = moduleName.indexOf(directorySeparator);
|
|
|
|
|
@@ -1216,35 +1173,36 @@ namespace ts {
|
|
|
|
|
return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
|
|
|
|
return loadModuleFromNearestNodeModules(extensions, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ false, cache);
|
|
|
|
|
}
|
|
|
|
|
function loadModuleFromNodeModulesAtTypes(moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): SearchResult<Resolved> {
|
|
|
|
|
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
|
|
|
|
|
return loadModuleFromNearestNodeModules(Extensions.DtsOnly, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ true, /*cache*/ undefined);
|
|
|
|
|
function loadModuleFromNearestNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
|
|
|
|
return loadModuleFromNearestNodeModulesDirectoryWorker(extensions, moduleName, directory, state, /*typesScopeOnly*/ false, cache);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromNearestNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly: boolean, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
|
|
|
|
function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string, directory: string, state: ModuleResolutionState): SearchResult<Resolved> {
|
|
|
|
|
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
|
|
|
|
|
return loadModuleFromNearestNodeModulesDirectoryWorker(Extensions.DtsOnly, moduleName, directory, state, /*typesScopeOnly*/ true, /*cache*/ undefined);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
|
|
|
|
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
|
|
|
|
|
return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => {
|
|
|
|
|
if (getBaseFileName(ancestorDirectory) !== "node_modules") {
|
|
|
|
|
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state.traceEnabled, state.host, failedLookupLocations);
|
|
|
|
|
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state);
|
|
|
|
|
if (resolutionFromCache) {
|
|
|
|
|
return resolutionFromCache;
|
|
|
|
|
}
|
|
|
|
|
return toSearchResult(loadModuleFromImmediateNodeModules(extensions, moduleName, ancestorDirectory, failedLookupLocations, state, typesOnly));
|
|
|
|
|
return toSearchResult(loadModuleFromImmediateNodeModulesDirectory(extensions, moduleName, ancestorDirectory, state, typesScopeOnly));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromImmediateNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly: boolean): Resolved | undefined {
|
|
|
|
|
function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean): Resolved | undefined {
|
|
|
|
|
const nodeModulesFolder = combinePaths(directory, "node_modules");
|
|
|
|
|
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
|
|
|
|
|
if (!nodeModulesFolderExists && state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesFolder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const packageResult = typesOnly ? undefined : loadModuleFromNodeModulesFolder(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, failedLookupLocations, state);
|
|
|
|
|
const packageResult = typesScopeOnly ? undefined : loadModuleFromSpecificNodeModulesDirectory(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, state);
|
|
|
|
|
if (packageResult) {
|
|
|
|
|
return packageResult;
|
|
|
|
|
}
|
|
|
|
|
@@ -1257,7 +1215,84 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
nodeModulesAtTypesExists = false;
|
|
|
|
|
}
|
|
|
|
|
return loadModuleFromNodeModulesFolder(Extensions.DtsOnly, mangleScopedPackageNameWithTrace(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, failedLookupLocations, state);
|
|
|
|
|
return loadModuleFromSpecificNodeModulesDirectory(Extensions.DtsOnly, mangleScopedPackageNameWithTrace(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, moduleName: string, nodeModulesDirectory: string, nodeModulesDirectoryExists: boolean, state: ModuleResolutionState): Resolved | undefined {
|
|
|
|
|
const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName));
|
|
|
|
|
|
|
|
|
|
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
|
|
|
|
|
let packageJsonContent: PackageJsonPathFields | undefined;
|
|
|
|
|
let packageId: PackageId | undefined;
|
|
|
|
|
let versionPaths: VersionPaths | undefined;
|
|
|
|
|
|
|
|
|
|
const packageInfo = getPackageJsonInfo(candidate, "", !nodeModulesDirectoryExists, state);
|
|
|
|
|
if (packageInfo) {
|
|
|
|
|
({ packageJsonContent, packageId, versionPaths } = packageInfo);
|
|
|
|
|
const fromFile = loadModuleFromFile(extensions, candidate, !nodeModulesDirectoryExists, state);
|
|
|
|
|
if (fromFile) {
|
|
|
|
|
return noPackageId(fromFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fromDirectory = loadNodeModuleFromDirectoryWorker(extensions, candidate, !nodeModulesDirectoryExists, state, packageJsonContent, versionPaths);
|
|
|
|
|
return withPackageId(packageId, fromDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
|
|
|
|
|
const pathAndExtension =
|
|
|
|
|
loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) ||
|
|
|
|
|
loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths);
|
|
|
|
|
return withPackageId(packageId, pathAndExtension);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const { packageName, rest } = parsePackageName(moduleName);
|
|
|
|
|
if (rest !== "") { // If "rest" is empty, we just did this search above.
|
|
|
|
|
const packageDirectory = combinePaths(nodeModulesDirectory, packageName);
|
|
|
|
|
|
|
|
|
|
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId and path mappings.
|
|
|
|
|
const packageInfo = getPackageJsonInfo(packageDirectory, rest, !nodeModulesDirectoryExists, state);
|
|
|
|
|
if (packageInfo) ({ packageId, versionPaths } = packageInfo);
|
|
|
|
|
if (versionPaths) {
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
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, versionMajorMinor, rest);
|
|
|
|
|
}
|
|
|
|
|
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
|
|
|
|
|
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, loader, !packageDirectoryExists, state);
|
|
|
|
|
if (fromPaths) {
|
|
|
|
|
return fromPaths.value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return loader(extensions, candidate, !nodeModulesDirectoryExists, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike<string[]>, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult<Resolved> {
|
|
|
|
|
const matchedPattern = matchPatternOrExact(getOwnKeys(paths), moduleName);
|
|
|
|
|
if (matchedPattern) {
|
|
|
|
|
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
|
|
|
|
|
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
|
|
|
|
|
}
|
|
|
|
|
const resolved = forEach(paths[matchedPatternText], subst => {
|
|
|
|
|
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
|
|
|
|
|
const candidate = normalizePath(combinePaths(baseDirectory, path));
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
|
|
|
|
|
}
|
|
|
|
|
// A path mapping may have an extension, in contrast to an import, which should omit it.
|
|
|
|
|
const extension = tryGetExtensionFromPath(candidate);
|
|
|
|
|
if (extension !== undefined) {
|
|
|
|
|
const path = tryFile(candidate, onlyRecordFailures, state);
|
|
|
|
|
if (path !== undefined) {
|
|
|
|
|
return noPackageId({ path, ext: extension });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
|
|
|
|
});
|
|
|
|
|
return { value: resolved };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1305,21 +1340,21 @@ namespace ts {
|
|
|
|
|
typesPackageName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost, failedLookupLocations: Push<string>): SearchResult<Resolved> {
|
|
|
|
|
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, state: ModuleResolutionState): SearchResult<Resolved> {
|
|
|
|
|
const result = cache && cache.get(containingDirectory);
|
|
|
|
|
if (result) {
|
|
|
|
|
if (traceEnabled) {
|
|
|
|
|
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
|
|
|
|
|
if (state.traceEnabled) {
|
|
|
|
|
trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
|
|
|
|
|
}
|
|
|
|
|
failedLookupLocations.push(...result.failedLookupLocations);
|
|
|
|
|
state.failedLookupLocations.push(...result.failedLookupLocations);
|
|
|
|
|
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
|
|
|
|
const traceEnabled = isTraceEnabled(compilerOptions, host);
|
|
|
|
|
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
|
|
|
|
|
const failedLookupLocations: string[] = [];
|
|
|
|
|
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
|
|
|
|
|
const containingDirectory = getDirectoryPath(containingFile);
|
|
|
|
|
|
|
|
|
|
const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
|
|
|
|
|
@@ -1327,7 +1362,7 @@ namespace ts {
|
|
|
|
|
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
|
|
|
|
|
|
|
|
|
|
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
|
|
|
|
|
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
|
|
|
|
|
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state);
|
|
|
|
|
if (resolvedUsingSettings) {
|
|
|
|
|
return { value: resolvedUsingSettings };
|
|
|
|
|
}
|
|
|
|
|
@@ -1336,24 +1371,24 @@ namespace ts {
|
|
|
|
|
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
|
|
|
|
|
// Climb up parent directories looking for a module.
|
|
|
|
|
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
|
|
|
|
|
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host, failedLookupLocations);
|
|
|
|
|
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, state);
|
|
|
|
|
if (resolutionFromCache) {
|
|
|
|
|
return resolutionFromCache;
|
|
|
|
|
}
|
|
|
|
|
const searchName = normalizePath(combinePaths(directory, moduleName));
|
|
|
|
|
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
|
|
|
|
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state));
|
|
|
|
|
});
|
|
|
|
|
if (resolved) {
|
|
|
|
|
return resolved;
|
|
|
|
|
}
|
|
|
|
|
if (extensions === Extensions.TypeScript) {
|
|
|
|
|
// If we didn't find the file normally, look it up in @types.
|
|
|
|
|
return loadModuleFromNodeModulesAtTypes(moduleName, containingDirectory, failedLookupLocations, state);
|
|
|
|
|
return loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName, containingDirectory, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
|
|
|
|
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
|
|
|
|
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1368,9 +1403,9 @@ namespace ts {
|
|
|
|
|
if (traceEnabled) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
|
|
|
|
|
const failedLookupLocations: string[] = [];
|
|
|
|
|
const resolved = loadModuleFromImmediateNodeModules(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state, /*typesOnly*/ false);
|
|
|
|
|
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
|
|
|
|
|
const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false);
|
|
|
|
|
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|