Skip to content

Commit d7ce95d

Browse files
committed
Watch node_modules if possible
1 parent 16cf7c4 commit d7ce95d

File tree

1 file changed

+62
-41
lines changed

1 file changed

+62
-41
lines changed

src/compiler/resolutionCache.ts

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ namespace ts {
5050
writeLog(s: string): void;
5151
}
5252

53-
const MAX_DIRPATHS_TO_RECURSE = 5;
54-
5553
export function createResolutionCache(resolutionHost: ResolutionCacheHost): ResolutionCache {
5654
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
5755
let filesWithInvalidatedResolutions: Map<true> | undefined;
@@ -264,7 +262,6 @@ namespace ts {
264262
}
265263

266264
function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
267-
resolutionHost.writeLog(`resolveTypeReferenceDirectives: ${typeDirectiveNames} in ${containingFile}`);
268265
return resolveNamesWithLocalCache(
269266
typeDirectiveNames, containingFile,
270267
resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives,
@@ -274,7 +271,6 @@ namespace ts {
274271
}
275272

276273
function resolveModuleNames(moduleNames: string[], containingFile: string, logChanges: boolean): ResolvedModuleFull[] {
277-
resolutionHost.writeLog(`resolveModuleNames: ${moduleNames} in ${containingFile}`);
278274
return resolveNamesWithLocalCache(
279275
moduleNames, containingFile,
280276
resolvedModuleNames, perDirectoryResolvedModuleNames,
@@ -284,48 +280,64 @@ namespace ts {
284280
}
285281

286282
function watchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path) {
287-
const cachedDir = failedLookupLocationToDirPath.get(failedLookupLocationPath);
288-
if (cachedDir) {
289-
watchFailedLookupLocationInDirectory(cachedDir, failedLookupLocationPath, /*dir*/ undefined);
283+
const failedLocationDirPath = getDirectoryPath(failedLookupLocationPath);
284+
const cachedDirPath = failedLookupLocationToDirPath.get(failedLocationDirPath);
285+
if (cachedDirPath) {
286+
watchFailedLookupLocationInDirectory(cachedDirPath, failedLookupLocationPath, /*dir*/ undefined);
290287
return;
291288
}
292289

293290
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
294291
// Watch in directory of rootPath
292+
failedLookupLocationToDirPath.set(failedLocationDirPath, rootPath);
295293
watchFailedLookupLocationInDirectory(rootPath, failedLookupLocationPath, rootDir);
296294
return;
297295
}
298296

299-
let dirPath = getDirectoryPath(failedLookupLocationPath);
300-
let dir = getDirectoryPath(getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory()));
301-
for (let i = 0; i < MAX_DIRPATHS_TO_RECURSE; i++) {
302-
const parentPath = getDirectoryPath(dirPath);
303-
if (directoryWatchesOfFailedLookups.has(dirPath) || parentPath === dirPath) {
304-
watchFailedLookupLocationInDirectory(dirPath, failedLookupLocationPath, dir);
305-
return;
306-
}
307-
dirPath = parentPath;
308-
dir = getDirectoryPath(dir);
309-
}
297+
const { dir, dirPath } = getDirectoryToWatchWhenNotInRootPath(
298+
getDirectoryPath(getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory())),
299+
getDirectoryPath(failedLookupLocationPath)
300+
);
301+
failedLookupLocationToDirPath.set(failedLocationDirPath, dirPath);
302+
watchFailedLookupLocationInDirectory(dirPath, failedLookupLocationPath, dir);
303+
}
310304

311-
// Verify there are no watches in parent directory
312-
const ancestorDirPath = getAncestorDirectoryWithWatches(dirPath);
313-
// We wont need directory if we are using ancestor since its already cached
314-
watchFailedLookupLocationInDirectory(ancestorDirPath || dirPath, failedLookupLocationPath, dir);
305+
function isNodeModulesDirectory(dirPath: Path) {
306+
const nodemodules = "/node_modules";
307+
return endsWith(dirPath, nodemodules);
315308
}
316309

317-
function getAncestorDirectoryWithWatches(dirPath: Path) {
318-
for (let parentDirPath = getDirectoryPath(dirPath); parentDirPath !== dirPath; parentDirPath = getDirectoryPath(parentDirPath)) {
319-
if (directoryWatchesOfFailedLookups.has(parentDirPath)) {
320-
return parentDirPath;
310+
function getDirectoryToWatchWhenNotInRootPath(dir: string, dirPath: Path): { dir: string, dirPath: Path } {
311+
// If the directory is node_modules use it to watch
312+
if (isNodeModulesDirectory(dirPath)) {
313+
return { dir, dirPath };
314+
}
315+
316+
// If directory path contains node module, get the node_modules directory for watching
317+
if (dirPath.indexOf("/node_modules/") !== -1) {
318+
while (!isNodeModulesDirectory(dirPath)) {
319+
dir = getDirectoryPath(dir);
320+
dirPath = getDirectoryPath(dirPath);
321+
}
322+
return { dir, dirPath };
323+
}
324+
325+
// Use some ancestor of the root directory
326+
if (rootPath !== undefined) {
327+
while (!isInDirectoryPath(dirPath, rootPath)) {
328+
const parentPath = getDirectoryPath(dirPath);
329+
if (parentPath === dirPath) {
330+
break;
331+
}
332+
dirPath = parentPath;
333+
dir = getDirectoryPath(dir);
321334
}
322-
dirPath = parentDirPath;
323335
}
324-
return undefined;
336+
337+
return { dir, dirPath };
325338
}
326339

327340
function watchFailedLookupLocationInDirectory(dirPath: Path, failedLookupLocationPath: Path, dir: string | undefined) {
328-
failedLookupLocationToDirPath.set(failedLookupLocationPath, dirPath);
329341
const watches = directoryWatchesOfFailedLookups.get(dirPath);
330342
if (watches) {
331343
const existingCount = watches.mapLocations.get(failedLookupLocationPath) || 0;
@@ -350,31 +362,37 @@ namespace ts {
350362
resolutionHost.getCachedPartialSystem().addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath);
351363
}
352364

353-
// If the location results in update to failed lookup, schedule program update
354-
if (dirPath === fileOrFolderPath) {
355-
onAddOrRemoveDirectoryOfFailedLookup(dirPath);
356-
resolutionHost.onInvalidatedResolution();
357-
}
358-
else if (onFileAddOrRemoveInDirectoryOfFailedLookup(dirPath, fileOrFolderPath)) {
359-
resolutionHost.onInvalidatedResolution();
365+
// If the files are added to project root or node_modules directory, always run through the invalidation process
366+
// Otherwise run through invalidation only if adding to the immediate directory
367+
if (dirPath === rootPath || isNodeModulesDirectory(dirPath) || getDirectoryPath(fileOrFolderPath) === dirPath) {
368+
// If the location results in update to failed lookup, schedule program update
369+
if (dirPath === fileOrFolderPath) {
370+
if (onAddOrRemoveDirectoryOfFailedLookup(dirPath)) {
371+
resolutionHost.onInvalidatedResolution();
372+
}
373+
}
374+
else if (onFileAddOrRemoveInDirectoryOfFailedLookup(dirPath, fileOrFolderPath)) {
375+
resolutionHost.onInvalidatedResolution();
376+
}
360377
}
361378
}, WatchDirectoryFlags.Recursive);
362379
}
363380

364381
function closeFailedLookupLocationWatcher(_failedLookupLocation: string, failedLookupLocationPath: Path) {
365-
const dirPath = failedLookupLocationToDirPath.get(failedLookupLocationPath);
382+
const failedLookupDirectory = getDirectoryPath(failedLookupLocationPath);
383+
const dirPath = failedLookupLocationToDirPath.get(failedLookupDirectory);
366384
const watches = directoryWatchesOfFailedLookups.get(dirPath);
367385
const refCount = watches.mapLocations.get(failedLookupLocationPath);
368386
if (refCount === 1) {
369387
// If this was last failed lookup location being tracked by the dir watcher,
370388
// remove the failed lookup location path to dir Path entry
371389
watches.mapLocations.delete(failedLookupLocationPath);
372-
failedLookupLocationToDirPath.delete(failedLookupLocationPath);
373390

374391
// If there are no more files that need this watcher alive, close the watcher
375392
if (watches.mapLocations.size === 0) {
376393
watches.watcher.close();
377394
directoryWatchesOfFailedLookups.delete(dirPath);
395+
failedLookupLocationToDirPath.delete(failedLookupDirectory);
378396
}
379397
}
380398
else {
@@ -455,19 +473,22 @@ namespace ts {
455473

456474
function onFileAddOrRemoveInDirectoryOfFailedLookup(dirPath: Path, fileOrFolder: Path) {
457475
const watches = directoryWatchesOfFailedLookups.get(dirPath);
458-
const isFailedLookupFile = watches.mapLocations.has(fileOrFolder);
459-
if (isFailedLookupFile) {
476+
if (watches.mapLocations.has(fileOrFolder)) {
477+
const invalidatedFiles = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size;
460478
const isFileOrFolder: (location: string) => boolean = location => resolutionHost.toPath(location) === fileOrFolder;
461479
invalidateResolutionCacheOfChangedFailedLookupLocation(resolvedModuleNames, isFileOrFolder);
462480
invalidateResolutionCacheOfChangedFailedLookupLocation(resolvedTypeReferenceDirectives, isFileOrFolder);
481+
return filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size !== invalidatedFiles;
463482
}
464-
return isFailedLookupFile;
483+
return false;
465484
}
466485

467486
function onAddOrRemoveDirectoryOfFailedLookup(dirPath: Path) {
487+
const invalidatedFiles = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size;
468488
const isInDirPath: (location: string) => boolean = location => isInDirectoryPath(dirPath, resolutionHost.toPath(location));
469489
invalidateResolutionCacheOfChangedFailedLookupLocation(resolvedModuleNames, isInDirPath);
470490
invalidateResolutionCacheOfChangedFailedLookupLocation(resolvedTypeReferenceDirectives, isInDirPath);
491+
filesWithInvalidatedResolutions && filesWithInvalidatedResolutions.size !== invalidatedFiles;
471492
}
472493

473494
function closeTypeRootsWatch() {

0 commit comments

Comments
 (0)