Skip to content

Commit f72af3b

Browse files
committed
Verify the scenarios when d.ts directory of dependency doesnt exist
1 parent 96a8c86 commit f72af3b

File tree

6 files changed

+88
-16
lines changed

6 files changed

+88
-16
lines changed

src/compiler/program.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,11 @@ namespace ts {
826826
if (!resolvedProjectReferences) {
827827
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
828828
}
829-
if (host.setGetSourceOfProjectReferenceRedirect) {
830-
host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect);
829+
if (host.setResolvedProjectReferenceCallbacks) {
830+
host.setResolvedProjectReferenceCallbacks({
831+
getSourceOfProjectReferenceRedirect,
832+
forEachResolvedProjectReference
833+
});
831834
}
832835
if (rootNames.length) {
833836
for (const parsedRef of resolvedProjectReferences) {
@@ -1226,8 +1229,11 @@ namespace ts {
12261229
}
12271230
if (projectReferences) {
12281231
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1229-
if (host.setGetSourceOfProjectReferenceRedirect) {
1230-
host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect);
1232+
if (host.setResolvedProjectReferenceCallbacks) {
1233+
host.setResolvedProjectReferenceCallbacks({
1234+
getSourceOfProjectReferenceRedirect,
1235+
forEachResolvedProjectReference
1236+
});
12311237
}
12321238
}
12331239

src/compiler/types.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5166,7 +5166,7 @@ namespace ts {
51665166
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
51675167
createHash?(data: string): string;
51685168
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
5169-
/* @internal */ setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void;
5169+
/* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void;
51705170
/* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean;
51715171

51725172
// TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base
@@ -5175,10 +5175,13 @@ namespace ts {
51755175

51765176
/** true if --out otherwise source file name */
51775177
/*@internal*/
5178-
export type SourceOfProjectReferenceRedirect = string | true ;
5178+
export type SourceOfProjectReferenceRedirect = string | true;
51795179

51805180
/*@internal*/
5181-
export type GetSourceOfProjectReferenceRedirect = (fileName: string) => SourceOfProjectReferenceRedirect | undefined;
5181+
interface ResolvedProjectReferenceCallbacks {
5182+
getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined;
5183+
forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined;
5184+
}
51825185

51835186
/* @internal */
51845187
export const enum TransformFlags {

src/server/project.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,8 @@ namespace ts.server {
14821482
configFileWatcher: FileWatcher | undefined;
14831483
private directoriesWatchedForWildcards: Map<WildcardDirectoryWatcher> | undefined;
14841484
readonly canonicalConfigFilePath: NormalizedPath;
1485-
private getSourceOfProjectReferenceRedirect: GetSourceOfProjectReferenceRedirect | undefined;
1485+
private projectReferenceCallbacks: ResolvedProjectReferenceCallbacks | undefined;
1486+
private mapOfDeclarationDirectories: Map<true> | undefined;
14861487

14871488
/* @internal */
14881489
pendingReload: ConfigFileProgramReloadLevel | undefined;
@@ -1529,22 +1530,51 @@ namespace ts.server {
15291530
}
15301531

15311532
/* @internal */
1532-
setGetSourceOfProjectReferenceRedirect(getSource: GetSourceOfProjectReferenceRedirect) {
1533-
this.getSourceOfProjectReferenceRedirect = getSource;
1533+
setResolvedProjectReferenceCallbacks(projectReferenceCallbacks: ResolvedProjectReferenceCallbacks) {
1534+
this.projectReferenceCallbacks = projectReferenceCallbacks;
15341535
}
15351536

15361537
/* @internal */
15371538
useSourceInsteadOfReferenceRedirect = () => !!this.languageServiceEnabled;
15381539

15391540
fileExists(file: string): boolean {
15401541
// Project references go to source file instead of .d.ts file
1541-
if (this.languageServiceEnabled && this.getSourceOfProjectReferenceRedirect) {
1542-
const source = this.getSourceOfProjectReferenceRedirect(file);
1542+
if (this.useSourceInsteadOfReferenceRedirect() && this.projectReferenceCallbacks) {
1543+
const source = this.projectReferenceCallbacks.getSourceOfProjectReferenceRedirect(file);
15431544
if (source) return isString(source) ? super.fileExists(source) : true;
15441545
}
15451546
return super.fileExists(file);
15461547
}
15471548

1549+
directoryExists(path: string): boolean {
1550+
if (super.directoryExists(path)) return true;
1551+
if (!this.useSourceInsteadOfReferenceRedirect() || !this.projectReferenceCallbacks) return false;
1552+
1553+
if (!this.mapOfDeclarationDirectories) {
1554+
this.mapOfDeclarationDirectories = createMap();
1555+
this.projectReferenceCallbacks.forEachResolvedProjectReference(ref => {
1556+
if (!ref) return;
1557+
const out = ref.commandLine.options.outFile || ref.commandLine.options.outDir;
1558+
if (out) {
1559+
this.mapOfDeclarationDirectories!.set(getDirectoryPath(this.toPath(out)), true);
1560+
}
1561+
else {
1562+
// Set declaration's in different locations only, if they are next to source the directory present doesnt change
1563+
const declarationDir = ref.commandLine.options.declarationDir || ref.commandLine.options.outDir;
1564+
if (declarationDir) {
1565+
this.mapOfDeclarationDirectories!.set(this.toPath(declarationDir), true);
1566+
}
1567+
}
1568+
});
1569+
}
1570+
const dirPath = this.toPath(path);
1571+
const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
1572+
return !!forEachKey(
1573+
this.mapOfDeclarationDirectories,
1574+
declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator)
1575+
);
1576+
}
1577+
15481578
/**
15491579
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
15501580
* @returns: true if set of files in the project stays the same and false - otherwise.
@@ -1553,6 +1583,8 @@ namespace ts.server {
15531583
this.isInitialLoadPending = returnFalse;
15541584
const reloadLevel = this.pendingReload;
15551585
this.pendingReload = ConfigFileProgramReloadLevel.None;
1586+
this.projectReferenceCallbacks = undefined;
1587+
this.mapOfDeclarationDirectories = undefined;
15561588
let result: boolean;
15571589
switch (reloadLevel) {
15581590
case ConfigFileProgramReloadLevel.Partial:
@@ -1567,7 +1599,6 @@ namespace ts.server {
15671599
default:
15681600
result = super.updateGraph();
15691601
}
1570-
this.getSourceOfProjectReferenceRedirect = undefined;
15711602
this.projectService.sendProjectLoadingFinishEvent(this);
15721603
this.projectService.sendProjectTelemetry(this);
15731604
return result;
@@ -1684,6 +1715,8 @@ namespace ts.server {
16841715
this.stopWatchingWildCards();
16851716
this.projectErrors = undefined;
16861717
this.configFileSpecs = undefined;
1718+
this.projectReferenceCallbacks = undefined;
1719+
this.mapOfDeclarationDirectories = undefined;
16871720
super.close();
16881721
}
16891722

src/services/services.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,8 +1246,8 @@ namespace ts {
12461246
return host.resolveTypeReferenceDirectives!(typeReferenceDirectiveNames, containingFile, redirectedReference);
12471247
};
12481248
}
1249-
if (host.setGetSourceOfProjectReferenceRedirect) {
1250-
compilerHost.setGetSourceOfProjectReferenceRedirect = getSource => host.setGetSourceOfProjectReferenceRedirect!(getSource);
1249+
if (host.setResolvedProjectReferenceCallbacks) {
1250+
compilerHost.setResolvedProjectReferenceCallbacks = callbacks => host.setResolvedProjectReferenceCallbacks!(callbacks);
12511251
}
12521252
if (host.useSourceInsteadOfReferenceRedirect) {
12531253
compilerHost.useSourceInsteadOfReferenceRedirect = () => host.useSourceInsteadOfReferenceRedirect!();

src/services/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ namespace ts {
237237
/* @internal */
238238
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
239239
/* @internal */
240-
setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void;
240+
setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void;
241241
/* @internal */
242242
useSourceInsteadOfReferenceRedirect?(): boolean;
243243
}

src/testRunner/unittests/tsserver/projectReferences.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,36 @@ ${dependencyTs.content}`);
727727
/*afterActionDocumentPositionMapperNotEquals*/ undefined,
728728
/*useDepedencyChange*/ true
729729
);
730+
731+
it("when d.ts file is not generated", () => {
732+
const host = createServerHost(files);
733+
const session = createSession(host);
734+
openFilesForSession([...openFiles, randomFile], session);
735+
736+
const expectedClosedInfos = closedInfos.filter(f => f.toLowerCase() !== dtsPath && f.toLowerCase() !== dtsMapPath);
737+
// If closed infos includes dts and dtsMap, watch dts since its not present
738+
const expectedWatchedFiles = closedInfos.length === expectedClosedInfos.length ?
739+
otherWatchedFiles :
740+
otherWatchedFiles.concat(dtsPath);
741+
// Main scenario action
742+
verifyAllFnActionWorker(session, ({ reqName, response, expectedResponse }) => {
743+
assert.deepEqual(response, expectedResponse, `Failed on ${reqName}`);
744+
verifyInfosWithRandom(session, host, openInfos, expectedClosedInfos, expectedWatchedFiles);
745+
verifyDocumentPositionMapper(session, /*dependencyMap*/ undefined, /*documentPositionMapper*/ undefined);
746+
}, /*dtsAbsent*/ true);
747+
checkProject(session);
748+
749+
// Collecting at this point retains dependency.d.ts and map
750+
closeFilesForSession([randomFile], session);
751+
openFilesForSession([randomFile], session);
752+
verifyInfosWithRandom(session, host, openInfos, expectedClosedInfos, expectedWatchedFiles);
753+
verifyDocumentPositionMapper(session, /*dependencyMap*/ undefined, /*documentPositionMapper*/ undefined);
754+
755+
// Closing open file, removes dependencies too
756+
closeFilesForSession([...openFiles, randomFile], session);
757+
openFilesForSession([randomFile], session);
758+
verifyOnlyRandomInfos(session, host);
759+
});
730760
}
731761
}
732762

0 commit comments

Comments
 (0)