Skip to content

Commit d760cbb

Browse files
committed
Make any paths in buildInfoFile to be relative to it.
1 parent 7ed3896 commit d760cbb

File tree

20 files changed

+419
-414
lines changed

20 files changed

+419
-414
lines changed

src/compiler/builder.ts

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,13 @@ namespace ts {
1010
export interface ReusableDiagnosticRelatedInformation {
1111
category: DiagnosticCategory;
1212
code: number;
13-
file: Path | undefined;
13+
file: string | undefined;
1414
start: number | undefined;
1515
length: number | undefined;
1616
messageText: string | ReusableDiagnosticMessageChain;
1717
}
1818

19-
export interface ReusableDiagnosticMessageChain {
20-
messageText: string;
21-
category: DiagnosticCategory;
22-
code: number;
23-
next?: ReusableDiagnosticMessageChain;
24-
}
19+
export type ReusableDiagnosticMessageChain = DiagnosticMessageChain;
2520

2621
export interface ReusableBuilderProgramState extends ReusableBuilderState {
2722
/**
@@ -227,7 +222,7 @@ namespace ts {
227222
// Unchanged file copy diagnostics
228223
const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath);
229224
if (diagnostics) {
230-
state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as ReadonlyArray<ReusableDiagnostic>, newProgram) : diagnostics as ReadonlyArray<Diagnostic>);
225+
state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as ReadonlyArray<ReusableDiagnostic>, newProgram, getCanonicalFileName) : diagnostics as ReadonlyArray<Diagnostic>);
231226
if (!state.semanticDiagnosticsFromOldState) {
232227
state.semanticDiagnosticsFromOldState = createMap<true>();
233228
}
@@ -246,37 +241,32 @@ namespace ts {
246241
return state;
247242
}
248243

249-
function convertToDiagnostics(diagnostics: ReadonlyArray<ReusableDiagnostic>, newProgram: Program): ReadonlyArray<Diagnostic> {
244+
function convertToDiagnostics(diagnostics: ReadonlyArray<ReusableDiagnostic>, newProgram: Program, getCanonicalFileName: GetCanonicalFileName): ReadonlyArray<Diagnostic> {
250245
if (!diagnostics.length) return emptyArray;
246+
const buildInfoDirectory = getDirectoryPath(getOutputPathForBuildInfo(newProgram.getCompilerOptions())!);
251247
return diagnostics.map(diagnostic => {
252-
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram);
248+
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram, toPath);
253249
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
254250
result.source = diagnostic.source;
255251
const { relatedInformation } = diagnostic;
256252
result.relatedInformation = relatedInformation ?
257253
relatedInformation.length ?
258-
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram)) :
254+
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram, toPath)) :
259255
emptyArray :
260256
undefined;
261257
return result;
262258
});
263-
}
264259

265-
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program): DiagnosticRelatedInformation {
266-
const { file, messageText } = diagnostic;
267-
return {
268-
...diagnostic,
269-
file: file && newProgram.getSourceFileByPath(file),
270-
messageText: messageText === undefined || isString(messageText) ?
271-
messageText :
272-
convertToDiagnosticMessageChain(messageText, newProgram)
273-
};
260+
function toPath(path: string) {
261+
return ts.toPath(path, buildInfoDirectory, getCanonicalFileName);
262+
}
274263
}
275264

276-
function convertToDiagnosticMessageChain(diagnostic: ReusableDiagnosticMessageChain, newProgram: Program): DiagnosticMessageChain {
265+
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
266+
const { file } = diagnostic;
277267
return {
278268
...diagnostic,
279-
next: diagnostic.next && convertToDiagnosticMessageChain(diagnostic.next, newProgram)
269+
file: file ? newProgram.getSourceFileByPath(toPath(file)) : undefined
280270
};
281271
}
282272

@@ -620,19 +610,20 @@ namespace ts {
620610
/**
621611
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
622612
*/
623-
function getProgramBuildInfo(state: Readonly<ReusableBuilderProgramState>): ProgramBuildInfo | undefined {
613+
function getProgramBuildInfo(state: Readonly<ReusableBuilderProgramState>, getCanonicalFileName: GetCanonicalFileName): ProgramBuildInfo | undefined {
624614
if (state.compilerOptions.outFile || state.compilerOptions.out) return undefined;
615+
const buildInfoDirectory = getDirectoryPath(getOutputPathForBuildInfo(state.compilerOptions)!);
625616
const fileInfos: MapLike<BuilderState.FileInfo> = {};
626617
state.fileInfos.forEach((value, key) => {
627618
const signature = state.currentAffectedFilesSignatures && state.currentAffectedFilesSignatures.get(key);
628-
fileInfos[key] = signature === undefined ? value : { version: value.version, signature };
619+
fileInfos[relativeToBuildInfo(key)] = signature === undefined ? value : { version: value.version, signature };
629620
});
630621

631622
const result: ProgramBuildInfo = { fileInfos, options: state.compilerOptions };
632623
if (state.referencedMap) {
633624
const referencedMap: MapLike<string[]> = {};
634625
state.referencedMap.forEach((value, key) => {
635-
referencedMap[key] = arrayFrom(value.keys());
626+
referencedMap[relativeToBuildInfo(key)] = arrayFrom(value.keys(), relativeToBuildInfo);
636627
});
637628
result.referencedMap = referencedMap;
638629
}
@@ -642,9 +633,9 @@ namespace ts {
642633
state.exportedModulesMap.forEach((value, key) => {
643634
const newValue = state.currentAffectedFilesExportedModulesMap && state.currentAffectedFilesExportedModulesMap.get(key);
644635
// Not in temporary cache, use existing value
645-
if (newValue === undefined) exportedModulesMap[key] = arrayFrom(value.keys());
636+
if (newValue === undefined) exportedModulesMap[relativeToBuildInfo(key)] = arrayFrom(value.keys(), relativeToBuildInfo);
646637
// Value in cache and has updated value map, use that
647-
else if (newValue) exportedModulesMap[key] = arrayFrom(newValue.keys());
638+
else if (newValue) exportedModulesMap[relativeToBuildInfo(key)] = arrayFrom(newValue.keys(), relativeToBuildInfo);
648639
});
649640
result.exportedModulesMap = exportedModulesMap;
650641
}
@@ -655,50 +646,44 @@ namespace ts {
655646
state.semanticDiagnosticsPerFile.forEach((value, key) => semanticDiagnosticsPerFile.push(
656647
value.length ?
657648
[
658-
key,
649+
relativeToBuildInfo(key),
659650
state.hasReusableDiagnostic ?
660651
value as ReadonlyArray<ReusableDiagnostic> :
661-
convertToReusableDiagnostics(value as ReadonlyArray<Diagnostic>)
652+
convertToReusableDiagnostics(value as ReadonlyArray<Diagnostic>, relativeToBuildInfo)
662653
] :
663-
key
654+
relativeToBuildInfo(key)
664655
));
665656
result.semanticDiagnosticsPerFile = semanticDiagnosticsPerFile;
666657
}
667658

668659
return result;
660+
661+
function relativeToBuildInfo(path: string) {
662+
return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName));
663+
}
669664
}
670665

671-
function convertToReusableDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): ReadonlyArray<ReusableDiagnostic> {
666+
function convertToReusableDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, relativeToBuildInfo: (path: string) => string): ReadonlyArray<ReusableDiagnostic> {
672667
Debug.assert(!!diagnostics.length);
673668
return diagnostics.map(diagnostic => {
674-
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic);
669+
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic, relativeToBuildInfo);
675670
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
676671
result.source = diagnostic.source;
677672
const { relatedInformation } = diagnostic;
678673
result.relatedInformation = relatedInformation ?
679674
relatedInformation.length ?
680-
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r)) :
675+
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, relativeToBuildInfo)) :
681676
emptyArray :
682677
undefined;
683678
return result;
684679
});
685680
}
686681

687-
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation): ReusableDiagnosticRelatedInformation {
688-
const { file, messageText } = diagnostic;
682+
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation, relativeToBuildInfo: (path: string) => string): ReusableDiagnosticRelatedInformation {
683+
const { file } = diagnostic;
689684
return {
690685
...diagnostic,
691-
file: file && file.path,
692-
messageText: messageText === undefined || isString(messageText) ?
693-
messageText :
694-
convertToReusableDiagnosticMessageChain(messageText)
695-
};
696-
}
697-
698-
function convertToReusableDiagnosticMessageChain(diagnostic: DiagnosticMessageChain): ReusableDiagnosticMessageChain {
699-
return {
700-
...diagnostic,
701-
next: diagnostic.next && convertToReusableDiagnosticMessageChain(diagnostic.next)
686+
file: file ? relativeToBuildInfo(file.path) : undefined
702687
};
703688
}
704689

@@ -767,7 +752,7 @@ namespace ts {
767752
const computeHash = host.createHash || generateDjb2Hash;
768753
let state = createBuilderProgramState(newProgram, getCanonicalFileName, oldState);
769754
let backupState: BuilderProgramState | undefined;
770-
newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state);
755+
newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state, getCanonicalFileName);
771756

772757
// To ensure that we arent storing any references to old program or new program without state
773758
newProgram = undefined!; // TODO: GH#18217
@@ -980,26 +965,35 @@ namespace ts {
980965
}
981966
}
982967

983-
function getMapOfReferencedSet(mapLike: MapLike<ReadonlyArray<string>> | undefined): ReadonlyMap<BuilderState.ReferencedSet> | undefined {
968+
function getMapOfReferencedSet(mapLike: MapLike<ReadonlyArray<string>> | undefined, toPath: (path: string) => Path): ReadonlyMap<BuilderState.ReferencedSet> | undefined {
984969
if (!mapLike) return undefined;
985970
const map = createMap<BuilderState.ReferencedSet>();
986971
// Copies keys/values from template. Note that for..in will not throw if
987972
// template is undefined, and instead will just exit the loop.
988973
for (const key in mapLike) {
989974
if (hasProperty(mapLike, key)) {
990-
map.set(key, arrayToSet(mapLike[key]));
975+
map.set(toPath(key), arrayToSet(mapLike[key], toPath));
991976
}
992977
}
993978
return map;
994979
}
995980

996-
export function createBuildProgramUsingProgramBuildInfo(program: ProgramBuildInfo): EmitAndSemanticDiagnosticsBuilderProgram {
997-
const fileInfos = createMapFromTemplate(program.fileInfos);
981+
export function createBuildProgramUsingProgramBuildInfo(program: ProgramBuildInfo, buildInfoPath: string, useCaseSensitiveFileNames: boolean): EmitAndSemanticDiagnosticsBuilderProgram {
982+
const buildInfoDirectory = getDirectoryPath(buildInfoPath);
983+
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
984+
985+
const fileInfos = createMap<BuilderState.FileInfo>();
986+
for (const key in program.fileInfos) {
987+
if (hasProperty(program.fileInfos, key)) {
988+
fileInfos.set(toPath(key), program.fileInfos[key]);
989+
}
990+
}
991+
998992
const state: ReusableBuilderProgramState = {
999993
fileInfos,
1000994
compilerOptions: program.options,
1001-
referencedMap: getMapOfReferencedSet(program.referencedMap),
1002-
exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap),
995+
referencedMap: getMapOfReferencedSet(program.referencedMap, toPath),
996+
exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap, toPath),
1003997
semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => isString(value) ? value : value[0], value => isString(value) ? emptyArray : value[1]),
1004998
hasReusableDiagnostic: true
1005999
};
@@ -1025,6 +1019,10 @@ namespace ts {
10251019
emitNextAffectedFile: notImplemented,
10261020
getSemanticDiagnosticsOfNextAffectedFile: notImplemented,
10271021
};
1022+
1023+
function toPath(path: string) {
1024+
return ts.toPath(path, buildInfoDirectory, getCanonicalFileName);
1025+
}
10281026
}
10291027

10301028
export function createRedirectedBuilderProgram(state: { program: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: ReadonlyArray<Diagnostic>): BuilderProgram {

src/compiler/tsbuild.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,11 +1298,11 @@ namespace ts {
12981298
}
12991299
}
13001300

1301-
function getOldProgram<T extends BuilderProgram>({ options, builderPrograms, readFileWithCache }: SolutionBuilderState<T>, proj: ResolvedConfigFilePath, parsed: ParsedCommandLine) {
1301+
function getOldProgram<T extends BuilderProgram>({ options, builderPrograms, readFileWithCache, host }: SolutionBuilderState<T>, proj: ResolvedConfigFilePath, parsed: ParsedCommandLine) {
13021302
if (options.force) return undefined;
13031303
const value = builderPrograms.get(proj);
13041304
if (value) return value;
1305-
return readBuilderProgram(parsed.options, readFileWithCache) as any as T;
1305+
return readBuilderProgram(parsed.options, readFileWithCache, host.useCaseSensitiveFileNames()) as any as T;
13061306
}
13071307

13081308
function afterProgramCreate<T extends BuilderProgram>({ host, watch, builderPrograms }: SolutionBuilderState<T>, proj: ResolvedConfigFilePath, program: T) {

src/compiler/watch.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ namespace ts {
437437
}
438438

439439
namespace ts {
440-
export function readBuilderProgram(compilerOptions: CompilerOptions, readFile: (path: string) => string | undefined) {
440+
export function readBuilderProgram(compilerOptions: CompilerOptions, readFile: (path: string) => string | undefined, useCaseSensitiveFileNames: boolean) {
441441
if (compilerOptions.out || compilerOptions.outFile) return undefined;
442442
const buildInfoPath = getOutputPathForBuildInfo(compilerOptions);
443443
if (!buildInfoPath) return undefined;
@@ -446,7 +446,7 @@ namespace ts {
446446
const buildInfo = getBuildInfo(content);
447447
if (buildInfo.version !== version) return undefined;
448448
if (!buildInfo.program) return undefined;
449-
return createBuildProgramUsingProgramBuildInfo(buildInfo.program);
449+
return createBuildProgramUsingProgramBuildInfo(buildInfo.program, buildInfoPath, useCaseSensitiveFileNames);
450450
}
451451

452452
export function createIncrementalCompilerHost(options: CompilerOptions, system = sys): CompilerHost {
@@ -471,7 +471,7 @@ namespace ts {
471471
}: IncrementalProgramOptions<T>): T {
472472
host = host || createIncrementalCompilerHost(options);
473473
createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram<T>;
474-
const oldProgram = readBuilderProgram(options, path => host!.readFile(path)) as any as T;
474+
const oldProgram = readBuilderProgram(options, path => host!.readFile(path), host.useCaseSensitiveFileNames()) as any as T;
475475
return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
476476
}
477477

@@ -747,7 +747,7 @@ namespace ts {
747747
((typeDirectiveNames, containingFile, redirectedReference) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference));
748748
const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives;
749749

750-
builderProgram = readBuilderProgram(compilerOptions, path => compilerHost.readFile(path)) as any as T;
750+
builderProgram = readBuilderProgram(compilerOptions, path => compilerHost.readFile(path), compilerHost.useCaseSensitiveFileNames()) as any as T;
751751
synchronizeProgram();
752752

753753
// Update the wild card directory watch

0 commit comments

Comments
 (0)