Skip to content

Commit a27b29f

Browse files
committed
Remove lib file errors when all files are to be emitted.
Fixes #26389
1 parent 9320699 commit a27b29f

File tree

2 files changed

+144
-1
lines changed

2 files changed

+144
-1
lines changed

src/compiler/builder.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ namespace ts {
3838
* Already seen affected files
3939
*/
4040
seenAffectedFiles: Map<true> | undefined;
41+
/**
42+
* program corresponding to this state
43+
*/
44+
cleanedDiagnosticsOfLibFiles?: boolean;
4145
/**
4246
* True if the semantic diagnostics were copied from the old state
4347
*/
@@ -83,6 +87,8 @@ namespace ts {
8387
// Update changed files and copy semantic diagnostics if we can
8488
const referencedMap = state.referencedMap;
8589
const oldReferencedMap = useOldState ? oldState!.referencedMap : undefined;
90+
const copyDeclarationFileDiagnostics = canCopySemanticDiagnostics && !compilerOptions.skipLibCheck === !oldState!.program.getCompilerOptions().skipLibCheck;
91+
const copyLibFileDiagnostics = copyDeclarationFileDiagnostics && !compilerOptions.skipDefaultLibCheck === !oldState!.program.getCompilerOptions().skipDefaultLibCheck;
8692
state.fileInfos.forEach((info, sourceFilePath) => {
8793
let oldInfo: Readonly<BuilderState.FileInfo> | undefined;
8894
let newReferences: BuilderState.ReferencedSet | undefined;
@@ -101,6 +107,11 @@ namespace ts {
101107
state.changedFilesSet.set(sourceFilePath, true);
102108
}
103109
else if (canCopySemanticDiagnostics) {
110+
const sourceFile = state.program.getSourceFileByPath(sourceFilePath as Path)!;
111+
112+
if (sourceFile.isDeclarationFile && !copyDeclarationFileDiagnostics) { return; }
113+
if (sourceFile.hasNoDefaultLib && !copyLibFileDiagnostics) { return; }
114+
104115
// Unchanged file copy diagnostics
105116
const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath);
106117
if (diagnostics) {
@@ -193,6 +204,19 @@ namespace ts {
193204
return;
194205
}
195206

207+
// Clean lib file diagnostics if its all files excluding default files to emit
208+
if (state.allFilesExcludingDefaultLibraryFile === state.affectedFiles && !state.cleanedDiagnosticsOfLibFiles) {
209+
state.cleanedDiagnosticsOfLibFiles = true;
210+
const options = state.program.getCompilerOptions();
211+
if (forEach(state.program.getSourceFiles(), f =>
212+
!contains(state.allFilesExcludingDefaultLibraryFile, f) &&
213+
!skipTypeChecking(f, options) &&
214+
removeSemanticDiagnosticsOf(state, f.path)
215+
)) {
216+
return;
217+
}
218+
}
219+
196220
// If there was change in signature for the changed file,
197221
// then delete the semantic diagnostics for files that are affected by using exports of this module
198222

@@ -268,7 +292,7 @@ namespace ts {
268292
*/
269293
function removeSemanticDiagnosticsOf(state: BuilderProgramState, path: Path) {
270294
if (!state.semanticDiagnosticsFromOldState) {
271-
return false;
295+
return true;
272296
}
273297
state.semanticDiagnosticsFromOldState.delete(path);
274298
state.semanticDiagnosticsPerFile!.delete(path);

src/testRunner/unittests/tscWatchMode.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,125 @@ export class Data2 {
15641564
verifyTransitiveExports([libFile, app, lib2Public, lib2Data, lib2Data2, lib1Public, lib1ToolsPublic, lib1ToolsInterface]);
15651565
});
15661566
});
1567+
1568+
describe("updates errors in lib file when non module file changes", () => {
1569+
const currentDirectory = "/user/username/projects/myproject";
1570+
const field = "fullscreen";
1571+
const aFile: File = {
1572+
path: `${currentDirectory}/a.ts`,
1573+
content: `interface Document {
1574+
${field}: boolean;
1575+
}`
1576+
};
1577+
const libFileWithDocument: File = {
1578+
path: libFile.path,
1579+
content: `${libFile.content}
1580+
interface Document {
1581+
readonly ${field}: boolean;
1582+
}`
1583+
};
1584+
1585+
function getDiagnostic(program: Program, file: File) {
1586+
return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(field), field.length, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, field);
1587+
}
1588+
1589+
const files = [aFile, libFileWithDocument];
1590+
1591+
function verifyLibErrors(options: CompilerOptions) {
1592+
const host = createWatchedSystem(files, { currentDirectory });
1593+
const watch = createWatchOfFilesAndCompilerOptions([aFile.path], host, options);
1594+
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
1595+
checkOutputErrorsInitial(host, getErrors());
1596+
1597+
host.writeFile(aFile.path, "var x = 10;");
1598+
host.runQueuedTimeoutCallbacks();
1599+
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
1600+
checkOutputErrorsIncremental(host, emptyArray);
1601+
1602+
host.writeFile(aFile.path, aFile.content);
1603+
host.runQueuedTimeoutCallbacks();
1604+
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
1605+
checkOutputErrorsIncremental(host, getErrors());
1606+
1607+
function getErrors() {
1608+
return [
1609+
...(options.skipLibCheck || options.skipDefaultLibCheck ? [] : [getDiagnostic(watch(), libFileWithDocument)]),
1610+
getDiagnostic(watch(), aFile)
1611+
];
1612+
}
1613+
}
1614+
1615+
it("with default options", () => {
1616+
verifyLibErrors({});
1617+
});
1618+
it("with skipLibCheck", () => {
1619+
verifyLibErrors({ skipLibCheck: true });
1620+
});
1621+
it("with skipDefaultLibCheck", () => {
1622+
verifyLibErrors({ skipDefaultLibCheck: true });
1623+
});
1624+
});
1625+
1626+
it("when skipLibCheck and skipDefaultLibCheck changes", () => {
1627+
const currentDirectory = "/user/username/projects/myproject";
1628+
const field = "fullscreen";
1629+
const aFile: File = {
1630+
path: `${currentDirectory}/a.ts`,
1631+
content: `interface Document {
1632+
${field}: boolean;
1633+
}`
1634+
};
1635+
const bFile: File = {
1636+
path: `${currentDirectory}/b.d.ts`,
1637+
content: `interface Document {
1638+
${field}: boolean;
1639+
}`
1640+
};
1641+
const libFileWithDocument: File = {
1642+
path: libFile.path,
1643+
content: `${libFile.content}
1644+
interface Document {
1645+
readonly ${field}: boolean;
1646+
}`
1647+
};
1648+
const configFile: File = {
1649+
path: `${currentDirectory}/tsconfig.json`,
1650+
content: "{}"
1651+
};
1652+
1653+
const files = [aFile, bFile, configFile, libFileWithDocument];
1654+
1655+
const host = createWatchedSystem(files, { currentDirectory });
1656+
const watch = createWatchOfConfigFile("tsconfig.json", host);
1657+
verifyProgramFiles();
1658+
checkOutputErrorsInitial(host, [
1659+
getDiagnostic(libFileWithDocument),
1660+
getDiagnostic(aFile),
1661+
getDiagnostic(bFile)
1662+
]);
1663+
1664+
verifyConfigChange({ skipLibCheck: true }, [aFile]);
1665+
verifyConfigChange({ skipDefaultLibCheck: true }, [aFile, bFile]);
1666+
verifyConfigChange({}, [libFileWithDocument, aFile, bFile]);
1667+
verifyConfigChange({ skipDefaultLibCheck: true }, [aFile, bFile]);
1668+
verifyConfigChange({ skipLibCheck: true }, [aFile]);
1669+
verifyConfigChange({}, [libFileWithDocument, aFile, bFile]);
1670+
1671+
function verifyConfigChange(compilerOptions: CompilerOptions, errorInFiles: ReadonlyArray<File>) {
1672+
host.writeFile(configFile.path, JSON.stringify({ compilerOptions }));
1673+
host.runQueuedTimeoutCallbacks();
1674+
verifyProgramFiles();
1675+
checkOutputErrorsIncremental(host, errorInFiles.map(getDiagnostic));
1676+
}
1677+
1678+
function getDiagnostic(file: File) {
1679+
return getDiagnosticOfFileFromProgram(watch(), file.path, file.content.indexOf(field), field.length, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, field);
1680+
}
1681+
1682+
function verifyProgramFiles() {
1683+
checkProgramActualFiles(watch(), [aFile.path, bFile.path, libFile.path]);
1684+
}
1685+
});
15671686
});
15681687

15691688
describe("tsc-watch emit with outFile or out setting", () => {

0 commit comments

Comments
 (0)