mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-11 20:37:46 -05:00
When directory watcher is invoked with any file from node_modules package, invalidate for file paths in that package (#43974)
Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
@@ -1150,7 +1150,7 @@ namespace ts {
|
||||
}
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state);
|
||||
if (resolvedFromFile) {
|
||||
const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile) : undefined;
|
||||
const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile.path) : undefined;
|
||||
const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined;
|
||||
return withPackageId(packageInfo, resolvedFromFile);
|
||||
}
|
||||
@@ -1184,8 +1184,9 @@ namespace ts {
|
||||
* For `/node_modules/@types/foo/bar/index.d.ts` this is packageDirectory: "@types/foo"
|
||||
* For `/node_modules/foo/bar/index.d.ts` this is packageDirectory: "foo"
|
||||
*/
|
||||
function parseNodeModuleFromPath(resolved: PathAndExtension): string | undefined {
|
||||
const path = normalizePath(resolved.path);
|
||||
/* @internal */
|
||||
export function parseNodeModuleFromPath(resolved: string): string | undefined {
|
||||
const path = normalizePath(resolved);
|
||||
const idx = path.lastIndexOf(nodeModulesPathPart);
|
||||
if (idx === -1) {
|
||||
return undefined;
|
||||
|
||||
@@ -153,9 +153,9 @@ namespace ts {
|
||||
const resolvedFileToResolution = createMultiMap<ResolutionWithFailedLookupLocations>();
|
||||
|
||||
let hasChangedAutomaticTypeDirectiveNames = false;
|
||||
const failedLookupChecks: Path[] = [];
|
||||
const startsWithPathChecks: Path[] = [];
|
||||
const isInDirectoryChecks: Path[] = [];
|
||||
let failedLookupChecks: Path[] | undefined;
|
||||
let startsWithPathChecks: Set<Path> | undefined;
|
||||
let isInDirectoryChecks: Path[] | undefined;
|
||||
|
||||
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!()); // TODO: GH#18217
|
||||
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
|
||||
@@ -248,9 +248,9 @@ namespace ts {
|
||||
resolvedTypeReferenceDirectives.clear();
|
||||
resolvedFileToResolution.clear();
|
||||
resolutionsWithFailedLookups.length = 0;
|
||||
failedLookupChecks.length = 0;
|
||||
startsWithPathChecks.length = 0;
|
||||
isInDirectoryChecks.length = 0;
|
||||
failedLookupChecks = undefined;
|
||||
startsWithPathChecks = undefined;
|
||||
isInDirectoryChecks = undefined;
|
||||
// perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update
|
||||
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
|
||||
clearPerDirectoryResolutions();
|
||||
@@ -766,7 +766,7 @@ namespace ts {
|
||||
if (isCreatingWatchedDirectory) {
|
||||
// Watching directory is created
|
||||
// Invalidate any resolution has failed lookup in this directory
|
||||
isInDirectoryChecks.push(fileOrDirectoryPath);
|
||||
(isInDirectoryChecks ||= []).push(fileOrDirectoryPath);
|
||||
}
|
||||
else {
|
||||
// If something to do with folder/file starting with "." in node_modules folder, skip it
|
||||
@@ -785,8 +785,8 @@ namespace ts {
|
||||
if (isNodeModulesAtTypesDirectory(fileOrDirectoryPath) || isNodeModulesDirectory(fileOrDirectoryPath) ||
|
||||
isNodeModulesAtTypesDirectory(dirOfFileOrDirectory) || isNodeModulesDirectory(dirOfFileOrDirectory)) {
|
||||
// Invalidate any resolution from this directory
|
||||
failedLookupChecks.push(fileOrDirectoryPath);
|
||||
startsWithPathChecks.push(fileOrDirectoryPath);
|
||||
(failedLookupChecks ||= []).push(fileOrDirectoryPath);
|
||||
(startsWithPathChecks ||= new Set()).add(fileOrDirectoryPath);
|
||||
}
|
||||
else {
|
||||
if (!isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) && !customFailedLookupPaths.has(fileOrDirectoryPath)) {
|
||||
@@ -797,21 +797,27 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
// Resolution need to be invalidated if failed lookup location is same as the file or directory getting created
|
||||
failedLookupChecks.push(fileOrDirectoryPath);
|
||||
(failedLookupChecks ||= []).push(fileOrDirectoryPath);
|
||||
|
||||
// If the invalidated file is from a node_modules package, invalidate everything else
|
||||
// in the package since we might not get notifications for other files in the package.
|
||||
// This hardens our logic against unreliable file watchers.
|
||||
const packagePath = parseNodeModuleFromPath(fileOrDirectoryPath);
|
||||
if (packagePath) (startsWithPathChecks ||= new Set()).add(packagePath as Path);
|
||||
}
|
||||
}
|
||||
resolutionHost.scheduleInvalidateResolutionsOfFailedLookupLocations();
|
||||
}
|
||||
|
||||
function invalidateResolutionsOfFailedLookupLocations() {
|
||||
if (!failedLookupChecks.length && !startsWithPathChecks.length && !isInDirectoryChecks.length) {
|
||||
if (!failedLookupChecks && !startsWithPathChecks && !isInDirectoryChecks) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const invalidated = invalidateResolutions(resolutionsWithFailedLookups, canInvalidateFailedLookupResolution);
|
||||
failedLookupChecks.length = 0;
|
||||
startsWithPathChecks.length = 0;
|
||||
isInDirectoryChecks.length = 0;
|
||||
failedLookupChecks = undefined;
|
||||
startsWithPathChecks = undefined;
|
||||
isInDirectoryChecks = undefined;
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
@@ -819,8 +825,8 @@ namespace ts {
|
||||
return resolution.failedLookupLocations.some(location => {
|
||||
const locationPath = resolutionHost.toPath(location);
|
||||
return contains(failedLookupChecks, locationPath) ||
|
||||
startsWithPathChecks.some(fileOrDirectoryPath => startsWith(locationPath, fileOrDirectoryPath)) ||
|
||||
isInDirectoryChecks.some(fileOrDirectoryPath => isInDirectoryPath(fileOrDirectoryPath, locationPath));
|
||||
firstDefinedIterator(startsWithPathChecks?.keys() || emptyIterator, fileOrDirectoryPath => startsWith(locationPath, fileOrDirectoryPath) ? true : undefined) ||
|
||||
isInDirectoryChecks?.some(fileOrDirectoryPath => isInDirectoryPath(fileOrDirectoryPath, locationPath));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user