Skip to content

Commit fb20c38

Browse files
committed
If we are writing dts file and have used file text as version, we can update the signature when doing actual emit
1 parent a92aaed commit fb20c38

File tree

182 files changed

+2284
-2765
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

182 files changed

+2284
-2765
lines changed

src/compiler/builder.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ namespace ts {
161161
* true if program has been emitted
162162
*/
163163
programEmitComplete?: true;
164+
/** Stores list of files that change signature during emit - test only */
165+
filesChangingSignature?: Set<Path>;
164166
}
165167

166168
function hasSameKeys(map1: ReadonlyCollection<string> | undefined, map2: ReadonlyCollection<string> | undefined): boolean {
@@ -1083,7 +1085,9 @@ namespace ts {
10831085
// Otherwise just affected file
10841086
Debug.checkDefined(state.program).emit(
10851087
affected === state.program ? undefined : affected as SourceFile,
1086-
writeFile || maybeBind(host, host.writeFile),
1088+
affected !== state.program && getEmitDeclarations(state.compilerOptions) && !customTransformers ?
1089+
writeFileUpdatingSignature :
1090+
writeFile || maybeBind(host, host.writeFile),
10871091
cancellationToken,
10881092
emitOnlyDtsFiles || emitKind === BuilderFileEmit.DtsOnly,
10891093
customTransformers
@@ -1092,6 +1096,39 @@ namespace ts {
10921096
emitKind,
10931097
isPendingEmitFile,
10941098
);
1099+
1100+
function writeFileUpdatingSignature(
1101+
fileName: string,
1102+
data: string,
1103+
writeByteOrderMark: boolean,
1104+
onError?: (message: string) => void,
1105+
sourceFiles?: readonly SourceFile[],
1106+
sourceMapUrlPos?: number
1107+
) {
1108+
Debug.assert(sourceFiles?.length === 1);
1109+
if (isDeclarationFileName(fileName)) {
1110+
const file = sourceFiles[0];
1111+
const info = state.fileInfos.get(file.resolvedPath)!;
1112+
const signature = state.currentAffectedFilesSignatures?.get(file.resolvedPath) || info.signature;
1113+
if (signature === file.version) {
1114+
const newSignature = (computeHash || generateDjb2Hash)(sourceMapUrlPos !== undefined ? data.substring(0, sourceMapUrlPos) : data);
1115+
if (newSignature !== file.version) { // Update it
1116+
if (host.storeFilesChangingSignatureDuringEmit) (state.filesChangingSignature ||= new Set()).add(file.resolvedPath);
1117+
if (state.exportedModulesMap) BuilderState.updateExportedModules(file, file.exportedModulesFromDeclarationEmit, state.currentAffectedFilesExportedModulesMap ||= BuilderState.createManyToManyPathMap());
1118+
if (state.affectedFiles && state.affectedFilesIndex! < state.affectedFiles.length) {
1119+
state.currentAffectedFilesSignatures!.set(file.resolvedPath, newSignature);
1120+
}
1121+
else {
1122+
info.signature = newSignature;
1123+
if (state.exportedModulesMap) BuilderState.updateExportedFilesMapFromCache(state, state.currentAffectedFilesExportedModulesMap);
1124+
}
1125+
}
1126+
}
1127+
}
1128+
if (writeFile) writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles, sourceMapUrlPos);
1129+
else if (host.writeFile) host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles, sourceMapUrlPos);
1130+
else state.program!.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles, sourceMapUrlPos);
1131+
}
10951132
}
10961133

10971134
/**

src/compiler/builderPublic.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ namespace ts {
2020
*/
2121
/*@internal*/
2222
disableUseFileVersionAsSignature?: boolean;
23+
/**
24+
* Store the list of files that update signature during the emit
25+
*/
26+
/*@internal*/
27+
storeFilesChangingSignatureDuringEmit?: boolean;
2328
}
2429

2530
/**

src/compiler/builderState.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ namespace ts {
434434
);
435435
const firstDts = firstOrUndefined(emitOutput.outputFiles);
436436
if (firstDts) {
437-
Debug.assert(fileExtensionIsOneOf(firstDts.name, [Extension.Dts, Extension.Dmts, Extension.Dcts]), "File extension for signature expected to be dts", () => `Found: ${getAnyExtensionFromPath(firstDts.name)} for ${firstDts.name}:: All output files: ${JSON.stringify(emitOutput.outputFiles.map(f => f.name))}`);
437+
Debug.assert(isDeclarationFileName(firstDts.name), "File extension for signature expected to be dts", () => `Found: ${getAnyExtensionFromPath(firstDts.name)} for ${firstDts.name}:: All output files: ${JSON.stringify(emitOutput.outputFiles.map(f => f.name))}`);
438438
latestSignature = (computeHash || generateDjb2Hash)(firstDts.text);
439439
if (exportedModulesMapCache && latestSignature !== prevSignature) {
440440
updateExportedModules(sourceFile, emitOutput.exportedModulesFromDeclarationEmit, exportedModulesMapCache);
@@ -462,7 +462,7 @@ namespace ts {
462462
/**
463463
* Coverts the declaration emit result into exported modules map
464464
*/
465-
function updateExportedModules(sourceFile: SourceFile, exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined, exportedModulesMapCache: ManyToManyPathMap) {
465+
export function updateExportedModules(sourceFile: SourceFile, exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined, exportedModulesMapCache: ManyToManyPathMap) {
466466
if (!exportedModulesFromDeclarationEmit) {
467467
exportedModulesMapCache.deleteKey(sourceFile.resolvedPath);
468468
return;

src/compiler/emitter.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ namespace ts {
531531
printer.writeFile(sourceFile!, writer, sourceMapGenerator);
532532
}
533533

534+
let sourceMapUrlPos;
534535
if (sourceMapGenerator) {
535536
if (sourceMapDataList) {
536537
sourceMapDataList.push({
@@ -548,6 +549,7 @@ namespace ts {
548549

549550
if (sourceMappingURL) {
550551
if (!writer.isAtStartOfLine()) writer.rawWrite(newLine);
552+
sourceMapUrlPos = writer.getTextPos();
551553
writer.writeComment(`//# ${"sourceMappingURL"}=${sourceMappingURL}`); // Tools can sometimes see this line as a source mapping url comment
552554
}
553555

@@ -562,7 +564,7 @@ namespace ts {
562564
}
563565

564566
// Write the output file
565-
writeFile(host, emitterDiagnostics, jsFilePath, writer.getText(), !!compilerOptions.emitBOM, sourceFiles);
567+
writeFile(host, emitterDiagnostics, jsFilePath, writer.getText(), !!compilerOptions.emitBOM, sourceFiles, sourceMapUrlPos);
566568

567569
// Reset state
568570
writer.clear();

src/compiler/moduleNameResolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ namespace ts {
14981498
}
14991499

15001500
function loadJSOrExactTSFileName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
1501-
if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && fileExtensionIsOneOf(candidate, [Extension.Dts, Extension.Dcts, Extension.Dmts])) {
1501+
if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && isDeclarationFileName(candidate)) {
15021502
const result = tryFile(candidate, onlyRecordFailures, state);
15031503
return result !== undefined ? { path: candidate, ext: forEach([Extension.Dts, Extension.Dcts, Extension.Dmts], e => fileExtensionIs(candidate, e) ? e : undefined)! } : undefined;
15041504
}

src/compiler/parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9411,9 +9411,10 @@ namespace ts {
94119411
}
94129412
}
94139413

9414+
const dtsExtensions = [Extension.Dts, Extension.Dmts, Extension.Dcts];
94149415
/** @internal */
94159416
export function isDeclarationFileName(fileName: string): boolean {
9416-
return fileExtensionIsOneOf(fileName, [Extension.Dts, Extension.Dmts, Extension.Dcts]);
9417+
return fileExtensionIsOneOf(fileName, dtsExtensions);
94179418
}
94189419

94199420
/*@internal*/

src/compiler/program.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ namespace ts {
262262
return newValue;
263263
};
264264
if (originalWriteFile) {
265-
host.writeFile = (fileName, data, writeByteOrderMark, onError, sourceFiles) => {
265+
host.writeFile = (fileName, data, ...rest) => {
266266
const key = toPath(fileName);
267267
fileExistsCache.delete(key);
268268

@@ -277,7 +277,7 @@ namespace ts {
277277
sourceFileCache.delete(key);
278278
}
279279
}
280-
originalWriteFile.call(host, fileName, data, writeByteOrderMark, onError, sourceFiles);
280+
originalWriteFile.call(host, fileName, data, ...rest);
281281
};
282282
}
283283

@@ -1340,6 +1340,7 @@ namespace ts {
13401340
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
13411341
getFileIncludeReasons: () => fileReasons,
13421342
structureIsReused,
1343+
writeFile,
13431344
};
13441345

13451346
onProgramCreateComplete();
@@ -1393,7 +1394,7 @@ namespace ts {
13931394

13941395
function getRedirectReferenceForResolution(file: SourceFile) {
13951396
const redirect = getResolvedProjectReferenceToRedirect(file.originalFileName);
1396-
if (redirect || !fileExtensionIsOneOf(file.originalFileName, [Extension.Dts, Extension.Dcts, Extension.Dmts])) return redirect;
1397+
if (redirect || !isDeclarationFileName(file.originalFileName)) return redirect;
13971398

13981399
// The originalFileName could not be actual source file name if file found was d.ts from referecned project
13991400
// So in this case try to look up if this is output from referenced project, if it is use the redirected project in that case
@@ -1894,8 +1895,7 @@ namespace ts {
18941895
getProjectReferenceRedirect,
18951896
isSourceOfProjectReferenceRedirect,
18961897
getSymlinkCache,
1897-
writeFile: writeFileCallback || (
1898-
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
1898+
writeFile: writeFileCallback || writeFile,
18991899
isEmitBlocked,
19001900
readFile: f => host.readFile(f),
19011901
fileExists: f => {
@@ -1914,6 +1914,17 @@ namespace ts {
19141914
};
19151915
}
19161916

1917+
function writeFile(
1918+
fileName: string,
1919+
data: string,
1920+
writeByteOrderMark: boolean,
1921+
onError?: (message: string) => void,
1922+
sourceFiles?: readonly SourceFile[],
1923+
sourceMapUrlPos?: number,
1924+
) {
1925+
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles, sourceMapUrlPos);
1926+
}
1927+
19171928
function emitBuildInfo(writeFileCallback?: WriteFileCallback): EmitResult {
19181929
Debug.assert(!outFile(options));
19191930
tracing?.push(tracing.Phase.Emit, "emitBuildInfo", {}, /*separateBeginAndEnd*/ true);

src/compiler/sys.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,11 +1210,13 @@ namespace ts {
12101210
base64decode?(input: string): string;
12111211
base64encode?(input: string): string;
12121212
/*@internal*/ bufferFrom?(input: string, encoding?: string): Buffer;
1213+
/*@internal*/ require?(baseDir: string, moduleName: string): RequireResult;
1214+
/*@internal*/ defaultWatchFileKind?(): WatchFileKind | undefined;
1215+
12131216
// For testing
12141217
/*@internal*/ now?(): Date;
12151218
/*@internal*/ disableUseFileVersionAsSignature?: boolean;
1216-
/*@internal*/ require?(baseDir: string, moduleName: string): RequireResult;
1217-
/*@internal*/ defaultWatchFileKind?(): WatchFileKind | undefined;
1219+
/*@internal*/ storeFilesChangingSignatureDuringEmit?: boolean;
12181220
}
12191221

12201222
export interface FileWatcher {

src/compiler/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3862,6 +3862,7 @@ namespace ts {
38623862
writeByteOrderMark: boolean,
38633863
onError?: (message: string) => void,
38643864
sourceFiles?: readonly SourceFile[],
3865+
sourceMapUrlPos?: number,
38653866
) => void;
38663867

38673868
export class OperationCanceledException { }
@@ -4067,6 +4068,8 @@ namespace ts {
40674068
* This implementation handles file exists to be true if file is source of project reference redirect when program is created using useSourceOfProjectReferenceRedirect
40684069
*/
40694070
/*@internal*/ fileExists(fileName: string): boolean;
4071+
/** Call compilerHost.writeFile on host program was created with */
4072+
/*@internal*/ writeFile: WriteFileCallback;
40704073
}
40714074

40724075
/*@internal*/
@@ -6779,6 +6782,7 @@ namespace ts {
67796782

67806783
// For testing:
67816784
/*@internal*/ disableUseFileVersionAsSignature?: boolean;
6785+
/*@internal*/ storeFilesChangingSignatureDuringEmit?: boolean;
67826786
}
67836787

67846788
/** true if --out otherwise source file name */

src/compiler/utilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4446,10 +4446,10 @@ namespace ts {
44464446
return combinePaths(newDirPath, sourceFilePath);
44474447
}
44484448

4449-
export function writeFile(host: { writeFile: WriteFileCallback; }, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean, sourceFiles?: readonly SourceFile[]) {
4449+
export function writeFile(host: { writeFile: WriteFileCallback; }, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean, sourceFiles?: readonly SourceFile[], sourceMapUrlPos?: number) {
44504450
host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => {
44514451
diagnostics.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
4452-
}, sourceFiles);
4452+
}, sourceFiles, sourceMapUrlPos);
44534453
}
44544454

44554455
function ensureDirectoriesExist(

0 commit comments

Comments
 (0)