Set hasAddedOrRemovedSymlinks when discovering an existing file by its link (#46569)

* Set hasAddedOrRemovedSymlinks when discovering an existing file by its link

* Make it optional
This commit is contained in:
Andrew Branch 2021-10-29 15:47:48 -07:00 committed by GitHub
parent eeaa595196
commit 7742cf2180
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 2 deletions

View file

@ -1674,8 +1674,8 @@ namespace ts {
const typesReferenceDirectives = map(newSourceFile.typeReferenceDirectives, ref => toFileNameLowerCase(ref.fileName));
const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFile);
// ensure that types resolutions are still correct
const typeReferenceEesolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, oldSourceFile, typeDirectiveIsEqualTo);
if (typeReferenceEesolutionsChanged) {
const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, oldSourceFile, typeDirectiveIsEqualTo);
if (typeReferenceResolutionsChanged) {
structureIsReused = StructureIsReused.SafeModules;
newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache(newSourceFile, typesReferenceDirectives, typeReferenceResolutions);
}

View file

@ -66,6 +66,7 @@ namespace ts {
getCurrentProgram(): Program | undefined;
fileIsOpen(filePath: Path): boolean;
getCompilerHost?(): CompilerHost | undefined;
onDiscoveredSymlink?(): void;
}
interface DirectoryWatchesOfFailedLookup {
@ -431,6 +432,9 @@ namespace ts {
else {
resolution = loader(name, containingFile, compilerOptions, resolutionHost.getCompilerHost?.() || resolutionHost, redirectedReference, containingSourceFile);
perDirectoryResolution.set(name, mode, resolution);
if (resolutionHost.onDiscoveredSymlink && resolutionIsSymlink(resolution)) {
resolutionHost.onDiscoveredSymlink();
}
}
resolutionsInFile.set(name, mode, resolution);
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName);
@ -965,4 +969,11 @@ namespace ts {
return dirPath === rootPath || canWatchDirectory(dirPath);
}
}
function resolutionIsSymlink(resolution: ResolutionWithFailedLookupLocations) {
return !!(
(resolution as ResolvedModuleWithFailedLookupLocations).resolvedModule?.originalPath ||
(resolution as ResolvedTypeReferenceDirectiveWithFailedLookupLocations).resolvedTypeReferenceDirective?.originalPath
);
}
}

View file

@ -1031,6 +1031,11 @@ namespace ts.server {
}
}
/* @internal */
onDiscoveredSymlink() {
this.hasAddedOrRemovedSymlinks = true;
}
/**
* Updates set of files that contribute to this project
* @returns: true if set of files in the project stays the same and false - otherwise.

View file

@ -0,0 +1,87 @@
/// <reference path="../fourslash.ts" />
// Notable lack of package.json referencing `mylib` as dependency here.
// This is not accurate to the original repro, but I think that's a separate
// bug, which, if fixed, would prevent the later crash.
// @Filename: /tsconfig.json
//// { "compilerOptions": { "module": "commonjs" } }
// @Filename: /packages/mylib/package.json
//// { "name": "mylib", "version": "1.0.0", "main": "index.js" }
// @Filename: /packages/mylib/index.ts
//// export * from "./mySubDir";
// @Filename: /packages/mylib/mySubDir/index.ts
//// export * from "./myClass";
//// export * from "./myClass2";
// @Filename: /packages/mylib/mySubDir/myClass.ts
//// export class MyClass {}
// @Filename: /packages/mylib/mySubDir/myClass2.ts
//// export class MyClass2 {}
// @link: /packages/mylib -> /node_modules/mylib
// @Filename: /src/index.ts
////
//// const a = new MyClass/*1*/();
//// const b = new MyClass2/*2*/();
goTo.marker("1");
format.setOption("newLineCharacter", "\n");
verify.completions({
marker: "1",
includes: [{
name: "MyClass",
source: "../packages/mylib",
sourceDisplay: "../packages/mylib",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions,
}],
preferences: {
includeCompletionsForModuleExports: true,
includeInsertTextCompletions: true,
allowIncompleteCompletions: true,
}
});
verify.applyCodeActionFromCompletion("1", {
name: "MyClass",
source: "../packages/mylib",
description: `Import 'MyClass' from module "../packages/mylib"`,
data: {
exportName: "MyClass",
fileName: "/packages/mylib/index.ts",
},
preferences: {
includeCompletionsForModuleExports: true,
includeCompletionsWithInsertText: true,
allowIncompleteCompletions: true,
},
newFileContent: `import { MyClass } from "../packages/mylib";
const a = new MyClass();
const b = new MyClass2();`,
});
edit.replaceLine(0, `import { MyClass } from "mylib";`);
verify.completions({
marker: "2",
includes: [{
name: "MyClass2",
source: "mylib",
sourceDisplay: "mylib",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions,
}],
preferences: {
includeCompletionsForModuleExports: true,
includeInsertTextCompletions: true,
allowIncompleteCompletions: true,
}
});