Skip to content

Commit 0adab89

Browse files
committed
Use source files instead of .d.ts files from project references
1 parent d0282b7 commit 0adab89

File tree

7 files changed

+119
-18
lines changed

7 files changed

+119
-18
lines changed

src/compiler/program.ts

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,8 @@ namespace ts {
813813
let resolvedProjectReferences: ReadonlyArray<ResolvedProjectReference | undefined> | undefined;
814814
let projectReferenceRedirects: Map<ResolvedProjectReference | false> | undefined;
815815
let mapFromFileToProjectReferenceRedirects: Map<Path> | undefined;
816+
let mapFromToProjectReferenceRedirectSource: Map<SourceOfProjectReferenceRedirect> | undefined;
817+
const useSourceOfReference = host.useSourceInsteadOfReferenceRedirect && host.useSourceInsteadOfReferenceRedirect();
816818

817819
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
818820
const structuralIsReused = tryReuseStructureFromOldProgram();
@@ -824,17 +826,29 @@ namespace ts {
824826
if (!resolvedProjectReferences) {
825827
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
826828
}
829+
if (host.setGetSourceOfProjectReferenceRedirect) {
830+
host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect);
831+
}
827832
if (rootNames.length) {
828833
for (const parsedRef of resolvedProjectReferences) {
829834
if (!parsedRef) continue;
830835
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
831-
if (out) {
832-
processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
836+
if (useSourceOfReference) {
837+
if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
838+
for (const fileName of parsedRef.commandLine.fileNames) {
839+
processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
840+
}
841+
}
833842
}
834-
else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
835-
for (const fileName of parsedRef.commandLine.fileNames) {
836-
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
837-
processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
843+
else {
844+
if (out) {
845+
processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
846+
}
847+
else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
848+
for (const fileName of parsedRef.commandLine.fileNames) {
849+
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
850+
processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
851+
}
838852
}
839853
}
840854
}
@@ -1212,6 +1226,9 @@ namespace ts {
12121226
}
12131227
if (projectReferences) {
12141228
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1229+
if (host.setGetSourceOfProjectReferenceRedirect) {
1230+
host.setGetSourceOfProjectReferenceRedirect(getSourceOfProjectReferenceRedirect);
1231+
}
12151232
}
12161233

12171234
// check if program source files has changed in the way that can affect structure of the program
@@ -2220,6 +2237,14 @@ namespace ts {
22202237

22212238
// Get source file from normalized fileName
22222239
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
2240+
if (useSourceOfReference) {
2241+
const source = getSourceOfProjectReferenceRedirect(fileName);
2242+
if (source) {
2243+
return isString(source) ?
2244+
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, refPos, refEnd, packageId) :
2245+
undefined;
2246+
}
2247+
}
22232248
const originalFileName = fileName;
22242249
if (filesByName.has(path)) {
22252250
const file = filesByName.get(path);
@@ -2267,7 +2292,7 @@ namespace ts {
22672292
}
22682293

22692294
let redirectedPath: Path | undefined;
2270-
if (refFile) {
2295+
if (refFile && !useSourceOfReference) {
22712296
const redirectProject = getProjectReferenceRedirectProject(fileName);
22722297
if (redirectProject) {
22732298
if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) {
@@ -2286,15 +2311,20 @@ namespace ts {
22862311
}
22872312

22882313
// We haven't looked for this file, do so now and cache result
2289-
const file = host.getSourceFile(fileName, options.target!, hostErrorMessage => { // TODO: GH#18217
2290-
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
2291-
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
2292-
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
2293-
}
2294-
else {
2295-
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
2296-
}
2297-
}, shouldCreateNewSourceFile);
2314+
const file = host.getSourceFile(
2315+
fileName,
2316+
options.target!,
2317+
hostErrorMessage => { // TODO: GH#18217
2318+
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
2319+
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
2320+
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
2321+
}
2322+
else {
2323+
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
2324+
}
2325+
},
2326+
shouldCreateNewSourceFile
2327+
);
22982328

22992329
if (packageId) {
23002330
const packageIdKey = packageIdToString(packageId);
@@ -2424,6 +2454,30 @@ namespace ts {
24242454
});
24252455
}
24262456

2457+
function getSourceOfProjectReferenceRedirect(file: string) {
2458+
if (!isDeclarationFileName(file)) return undefined;
2459+
if (mapFromToProjectReferenceRedirectSource === undefined) {
2460+
mapFromToProjectReferenceRedirectSource = createMap();
2461+
forEachResolvedProjectReference(resolvedRef => {
2462+
if (resolvedRef) {
2463+
const out = resolvedRef.commandLine.options.outFile || resolvedRef.commandLine.options.out;
2464+
if (out) {
2465+
// Dont know which source file it means so return true?
2466+
const outputDts = changeExtension(out, Extension.Dts);
2467+
mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true);
2468+
}
2469+
else {
2470+
forEach(resolvedRef.commandLine.fileNames, fileName => {
2471+
const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, host.useCaseSensitiveFileNames());
2472+
mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName);
2473+
});
2474+
}
2475+
}
2476+
});
2477+
}
2478+
return mapFromToProjectReferenceRedirectSource.get(toPath(file));
2479+
}
2480+
24272481
function forEachProjectReference<T>(
24282482
projectReferences: ReadonlyArray<ProjectReference> | undefined,
24292483
resolvedProjectReferences: ReadonlyArray<ResolvedProjectReference | undefined> | undefined,

src/compiler/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5166,11 +5166,20 @@ namespace ts {
51665166
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
51675167
createHash?(data: string): string;
51685168
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
5169+
/* @internal */ setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void;
5170+
/* @internal */ useSourceInsteadOfReferenceRedirect?(): boolean;
51695171

51705172
// TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base
51715173
/*@internal*/createDirectory?(directory: string): void;
51725174
}
51735175

5176+
/** true if --out otherwise source file name */
5177+
/*@internal*/
5178+
export type SourceOfProjectReferenceRedirect = string | true ;
5179+
5180+
/*@internal*/
5181+
export type GetSourceOfProjectReferenceRedirect = (fileName: string) => SourceOfProjectReferenceRedirect | undefined;
5182+
51745183
/* @internal */
51755184
export const enum TransformFlags {
51765185
None = 0,

src/server/editorServices.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,7 +1798,7 @@ namespace ts.server {
17981798
let scriptInfo: ScriptInfo | NormalizedPath;
17991799
let path: Path;
18001800
// Use the project's fileExists so that it can use caching instead of reaching to disk for the query
1801-
if (!isDynamic && !project.fileExists(newRootFile)) {
1801+
if (!isDynamic && !project.fileExistsWithCache(newRootFile)) {
18021802
path = normalizedPathToPath(normalizedPath, this.currentDirectory, this.toCanonicalFileName);
18031803
const existingValue = projectRootFilesMap.get(path)!;
18041804
if (isScriptInfo(existingValue)) {
@@ -1831,7 +1831,7 @@ namespace ts.server {
18311831
projectRootFilesMap.forEach((value, path) => {
18321832
if (!newRootScriptInfoMap.has(path)) {
18331833
if (isScriptInfo(value)) {
1834-
project.removeFile(value, project.fileExists(path), /*detachFromProject*/ true);
1834+
project.removeFile(value, project.fileExistsWithCache(path), /*detachFromProject*/ true);
18351835
}
18361836
else {
18371837
projectRootFilesMap.delete(path);

src/server/project.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ namespace ts.server {
381381
}
382382

383383
fileExists(file: string): boolean {
384+
return this.fileExistsWithCache(file);
385+
}
386+
387+
/* @internal */
388+
fileExistsWithCache(file: string): boolean {
384389
// As an optimization, don't hit the disks for files we already know don't exist
385390
// (because we're watching for their creation).
386391
const path = this.toPath(file);
@@ -1369,6 +1374,7 @@ namespace ts.server {
13691374
configFileWatcher: FileWatcher | undefined;
13701375
private directoriesWatchedForWildcards: Map<WildcardDirectoryWatcher> | undefined;
13711376
readonly canonicalConfigFilePath: NormalizedPath;
1377+
private getSourceOfProjectReferenceRedirect: GetSourceOfProjectReferenceRedirect | undefined;
13721378

13731379
/* @internal */
13741380
pendingReload: ConfigFileProgramReloadLevel | undefined;
@@ -1414,6 +1420,25 @@ namespace ts.server {
14141420
this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName));
14151421
}
14161422

1423+
/* @internal */
1424+
setGetSourceOfProjectReferenceRedirect(getSource: GetSourceOfProjectReferenceRedirect) {
1425+
this.getSourceOfProjectReferenceRedirect = getSource;
1426+
}
1427+
1428+
/* @internal */
1429+
useSourceInsteadOfReferenceRedirect() {
1430+
return true;
1431+
}
1432+
1433+
fileExists(file: string): boolean {
1434+
// Project references go to source file instead of .d.ts file
1435+
if (this.getSourceOfProjectReferenceRedirect) {
1436+
const source = this.getSourceOfProjectReferenceRedirect(file);
1437+
if (source) return isString(source) ? super.fileExists(source) : true;
1438+
}
1439+
return super.fileExists(file);
1440+
}
1441+
14171442
/**
14181443
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
14191444
* @returns: true if set of files in the project stays the same and false - otherwise.
@@ -1436,6 +1461,7 @@ namespace ts.server {
14361461
default:
14371462
result = super.updateGraph();
14381463
}
1464+
this.getSourceOfProjectReferenceRedirect = undefined;
14391465
this.projectService.sendProjectLoadingFinishEvent(this);
14401466
this.projectService.sendProjectTelemetry(this);
14411467
return result;

src/services/services.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,12 @@ namespace ts {
12451245
return host.resolveTypeReferenceDirectives!(typeReferenceDirectiveNames, containingFile, redirectedReference);
12461246
};
12471247
}
1248+
if (host.setGetSourceOfProjectReferenceRedirect) {
1249+
compilerHost.setGetSourceOfProjectReferenceRedirect = getSource => host.setGetSourceOfProjectReferenceRedirect!(getSource);
1250+
}
1251+
if (host.useSourceInsteadOfReferenceRedirect) {
1252+
compilerHost.useSourceInsteadOfReferenceRedirect = () => host.useSourceInsteadOfReferenceRedirect!();
1253+
}
12481254

12491255
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
12501256
const options: CreateProgramOptions = {

src/services/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ namespace ts {
236236
getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined;
237237
/* @internal */
238238
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
239+
/* @internal */
240+
setGetSourceOfProjectReferenceRedirect?(getSource: GetSourceOfProjectReferenceRedirect): void;
241+
/* @internal */
242+
useSourceInsteadOfReferenceRedirect?(): boolean;
239243
}
240244

241245
/* @internal */

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8546,11 +8546,13 @@ declare namespace ts.server {
85468546
private typeAcquisition;
85478547
private directoriesWatchedForWildcards;
85488548
readonly canonicalConfigFilePath: NormalizedPath;
8549+
private getSourceOfProjectReferenceRedirect;
85498550
/** Ref count to the project when opened from external project */
85508551
private externalProjectRefCount;
85518552
private projectErrors;
85528553
private projectReferences;
85538554
protected isInitialLoadPending: () => boolean;
8555+
fileExists(file: string): boolean;
85548556
/**
85558557
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
85568558
* @returns: true if set of files in the project stays the same and false - otherwise.

0 commit comments

Comments
 (0)