Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3771,7 +3771,7 @@ function specToDiagnostic(spec: CompilerOptionsValue, disallowTrailingRecursion?
/**
* Gets directories in a set of include patterns that should be watched for changes.
*/
function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> {
function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, basePath: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> {
// We watch a directory recursively if it contains a wildcard anywhere in a directory segment
// of the pattern:
//
Expand All @@ -3784,23 +3784,26 @@ function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExclu
//
// /a/b/* - Watch /a/b directly to catch any new file
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, basePath, "exclude");
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
const wildcardDirectories: MapLike<WatchDirectoryFlags> = {};
const wildCardKeyToPath = new Map<CanonicalKey, string>();
if (include !== undefined) {
const recursiveKeys: string[] = [];
const recursiveKeys: CanonicalKey[] = [];
for (const file of include) {
const spec = normalizePath(combinePaths(path, file));
const spec = normalizePath(combinePaths(basePath, file));
if (excludeRegex && excludeRegex.test(spec)) {
continue;
}

const match = getWildcardDirectoryFromSpec(spec, useCaseSensitiveFileNames);
if (match) {
const { key, flags } = match;
const existingFlags = wildcardDirectories[key];
const { key, path, flags } = match;
const existingPath = wildCardKeyToPath.get(key);
const existingFlags = existingPath !== undefined ? wildcardDirectories[existingPath] : undefined;
if (existingFlags === undefined || existingFlags < flags) {
wildcardDirectories[key] = flags;
wildcardDirectories[existingPath !== undefined ? existingPath : path] = flags;
if (existingPath === undefined) wildCardKeyToPath.set(key, path);
if (flags === WatchDirectoryFlags.Recursive) {
recursiveKeys.push(key);
}
Expand All @@ -3809,11 +3812,12 @@ function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExclu
}

// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) {
if (hasProperty(wildcardDirectories, key)) {
for (const path in wildcardDirectories) {
if (hasProperty(wildcardDirectories, path)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
const key = toCanonicalKey(path, useCaseSensitiveFileNames);
if (key !== recursiveKey && containsPath(recursiveKey, key, basePath, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[path];
}
}
}
Expand All @@ -3823,7 +3827,12 @@ function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExclu
return wildcardDirectories;
}

function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: string; flags: WatchDirectoryFlags; } | undefined {
type CanonicalKey = string & { __canonicalKey: never; };
function toCanonicalKey(path: string, useCaseSensitiveFileNames: boolean): CanonicalKey {
return (useCaseSensitiveFileNames ? path : toFileNameLowerCase(path)) as CanonicalKey;
}

function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: CanonicalKey; path: string; flags: WatchDirectoryFlags; } | undefined {
const match = wildcardDirectoryPattern.exec(spec);
if (match) {
// We check this with a few `indexOf` calls because 3 `indexOf`/`lastIndexOf` calls is
Expand All @@ -3834,15 +3843,18 @@ function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: b
const starWildcardIndex = spec.indexOf("*");
const lastDirectorySeperatorIndex = spec.lastIndexOf(directorySeparator);
return {
key: useCaseSensitiveFileNames ? match[0] : toFileNameLowerCase(match[0]),
key: toCanonicalKey(match[0], useCaseSensitiveFileNames),
path: match[0],
flags: (questionWildcardIndex !== -1 && questionWildcardIndex < lastDirectorySeperatorIndex)
|| (starWildcardIndex !== -1 && starWildcardIndex < lastDirectorySeperatorIndex)
? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None,
};
}
if (isImplicitGlob(spec.substring(spec.lastIndexOf(directorySeparator) + 1))) {
const path = removeTrailingDirectorySeparator(spec);
return {
key: removeTrailingDirectorySeparator(useCaseSensitiveFileNames ? spec : toFileNameLowerCase(spec)),
key: toCanonicalKey(path, useCaseSensitiveFileNames),
path,
flags: WatchDirectoryFlags.Recursive,
};
}
Expand Down
38 changes: 23 additions & 15 deletions src/compiler/moduleNameResolver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
append,
appendIfUnique,
arrayFrom,
arrayIsEqualTo,
changeAnyExtension,
CharacterCodes,
Expand Down Expand Up @@ -901,11 +900,24 @@ export interface NonRelativeModuleNameResolutionCache extends NonRelativeNameRes
getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
}

/** @internal */
export interface MissingPackageJsonInfo {
packageDirectory: string;
directoryExists: boolean;
}

/** @internal */
export type PackageJsonInfoCacheEntry = PackageJsonInfo | MissingPackageJsonInfo;

/** @internal */
export function isPackageJsonInfo(entry: PackageJsonInfoCacheEntry | undefined): entry is PackageJsonInfo {
return !!(entry as PackageJsonInfo | undefined)?.contents;
}

export interface PackageJsonInfoCache {
/** @internal */ getPackageJsonInfo(packageJsonPath: string): PackageJsonInfo | boolean | undefined;
/** @internal */ setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfo | boolean): void;
/** @internal */ entries(): [Path, PackageJsonInfo | boolean][];
/** @internal */ getInternalMap(): Map<Path, PackageJsonInfo | boolean> | undefined;
/** @internal */ getPackageJsonInfo(packageJsonPath: string): PackageJsonInfoCacheEntry | undefined;
/** @internal */ setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfoCacheEntry): void;
/** @internal */ getInternalMap(): Map<Path, PackageJsonInfoCacheEntry> | undefined;
clear(): void;
/** @internal */ isReadonly?: boolean;
}
Expand Down Expand Up @@ -1021,21 +1033,17 @@ export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | und
}

function createPackageJsonInfoCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): PackageJsonInfoCache {
let cache: Map<Path, PackageJsonInfo | boolean> | undefined;
return { getPackageJsonInfo, setPackageJsonInfo, clear, entries, getInternalMap };
let cache: Map<Path, PackageJsonInfoCacheEntry> | undefined;
return { getPackageJsonInfo, setPackageJsonInfo, clear, getInternalMap };
function getPackageJsonInfo(packageJsonPath: string) {
return cache?.get(toPath(packageJsonPath, currentDirectory, getCanonicalFileName));
}
function setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfo | boolean) {
function setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfoCacheEntry) {
(cache ||= new Map()).set(toPath(packageJsonPath, currentDirectory, getCanonicalFileName), info);
}
function clear() {
cache = undefined;
}
function entries() {
const iter = cache?.entries();
return iter ? arrayFrom(iter) : [];
}
function getInternalMap() {
return cache;
}
Expand Down Expand Up @@ -2391,15 +2399,15 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures:

const existing = state.packageJsonInfoCache?.getPackageJsonInfo(packageJsonPath);
if (existing !== undefined) {
if (typeof existing !== "boolean") {
if (isPackageJsonInfo(existing)) {
if (traceEnabled) trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath);
state.affectingLocations?.push(packageJsonPath);
return existing.packageDirectory === packageDirectory ?
existing :
{ packageDirectory, contents: existing.contents };
}
else {
if (existing && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath);
if (existing.directoryExists && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath);
state.failedLookupLocations?.push(packageJsonPath);
return undefined;
}
Expand All @@ -2419,7 +2427,7 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures:
if (directoryExists && traceEnabled) {
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
}
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, directoryExists);
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, { packageDirectory, directoryExists });
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
state.failedLookupLocations?.push(packageJsonPath);
}
Expand Down
Loading