diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index a0ab1339bca19..1deeaf45ba275 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -313,7 +313,13 @@ function createBuilderProgramState(newProgram: Program, getCanonicalFileName: Ge }); // If the global file is removed, add all files as changed - if (useOldState && forEachEntry(oldState!.fileInfos, (info, sourceFilePath) => (outFilePath || info.affectsGlobalScope) && !state.fileInfos.has(sourceFilePath))) { + if (useOldState && forEachEntry(oldState!.fileInfos, (info, sourceFilePath) => { + if (state.fileInfos.has(sourceFilePath)) return false; + if (outFilePath || info.affectsGlobalScope) return true; + // if file is deleted we need to write buildInfo again + state.buildInfoEmitPending = true; + return false; + })) { BuilderState.getAllFilesExcludingDefaultLibraryFile(state, newProgram, /*firstSourceFile*/ undefined) .forEach(file => addFileToChangeSet(state, file.resolvedPath)); } diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts index 9bd13a37fb64c..5bfe1a27c53e1 100644 --- a/src/testRunner/unittests/tsc/incremental.ts +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -819,4 +819,26 @@ console.log(a);`, baselinePrograms: true, }); }); + + verifyTscWithEdits({ + scenario: "incremental", + subScenario: "when file is deleted", + commandLineArgs: ["-p", `/src/project`], + fs: () => loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + composite: true, + outDir: "outDir", + }, + }), + "/src/project/file1.ts": `export class C { }`, + "/src/project/file2.ts": `export class D { }`, + }), + edits: [ + { + subScenario: "delete file with imports", + modifyFs: fs => fs.unlinkSync("/src/project/file2.ts"), + }, + ] + }); }); diff --git a/tests/baselines/reference/tsc/incremental/when-file-is-deleted.js b/tests/baselines/reference/tsc/incremental/when-file-is-deleted.js new file mode 100644 index 0000000000000..9ee08e92a5412 --- /dev/null +++ b/tests/baselines/reference/tsc/incremental/when-file-is-deleted.js @@ -0,0 +1,178 @@ +Input:: +//// [/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } +interface ReadonlyArray {} +declare const console: { log(msg: any): void; }; + +//// [/src/project/file1.ts] +export class C { } + +//// [/src/project/file2.ts] +export class D { } + +//// [/src/project/tsconfig.json] +{"compilerOptions":{"composite":true,"outDir":"outDir"}} + + + +Output:: +/lib/tsc -p /src/project +exitCode:: ExitStatus.Success + + +//// [/src/project/outDir/file1.d.ts] +export declare class C { +} + + +//// [/src/project/outDir/file1.js] +"use strict"; +exports.__esModule = true; +exports.C = void 0; +var C = /** @class */ (function () { + function C() { + } + return C; +}()); +exports.C = C; + + +//// [/src/project/outDir/file2.d.ts] +export declare class D { +} + + +//// [/src/project/outDir/file2.js] +"use strict"; +exports.__esModule = true; +exports.D = void 0; +var D = /** @class */ (function () { + function D() { + } + return D; +}()); +exports.D = D; + + +//// [/src/project/outDir/tsconfig.tsbuildinfo] +{"program":{"fileNames":["../../../lib/lib.d.ts","../file1.ts","../file2.ts"],"fileInfos":[{"version":"3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-9819564552-export class C { }","signature":"-10192454122-export declare class C {\r\n}\r\n"},{"version":"-7804761415-export class D { }","signature":"-10523684105-export declare class D {\r\n}\r\n"}],"options":{"composite":true,"outDir":"./"},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2,3],"latestChangedDtsFile":"./file2.d.ts"},"version":"FakeTSVersion"} + +//// [/src/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt] +{ + "program": { + "fileNames": [ + "../../../lib/lib.d.ts", + "../file1.ts", + "../file2.ts" + ], + "fileInfos": { + "../../../lib/lib.d.ts": { + "original": { + "version": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "affectsGlobalScope": true + }, + "version": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "signature": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "affectsGlobalScope": true + }, + "../file1.ts": { + "original": { + "version": "-9819564552-export class C { }", + "signature": "-10192454122-export declare class C {\r\n}\r\n" + }, + "version": "-9819564552-export class C { }", + "signature": "-10192454122-export declare class C {\r\n}\r\n" + }, + "../file2.ts": { + "original": { + "version": "-7804761415-export class D { }", + "signature": "-10523684105-export declare class D {\r\n}\r\n" + }, + "version": "-7804761415-export class D { }", + "signature": "-10523684105-export declare class D {\r\n}\r\n" + } + }, + "options": { + "composite": true, + "outDir": "./" + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "../../../lib/lib.d.ts", + "../file1.ts", + "../file2.ts" + ], + "latestChangedDtsFile": "./file2.d.ts" + }, + "version": "FakeTSVersion", + "size": 972 +} + + + +Change:: delete file with imports +Input:: +//// [/src/project/file2.ts] unlink + + +Output:: +/lib/tsc -p /src/project +exitCode:: ExitStatus.Success + + +//// [/src/project/outDir/tsconfig.tsbuildinfo] +{"program":{"fileNames":["../../../lib/lib.d.ts","../file1.ts"],"fileInfos":[{"version":"3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-9819564552-export class C { }","signature":"-10192454122-export declare class C {\r\n}\r\n"}],"options":{"composite":true,"outDir":"./"},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"latestChangedDtsFile":"./file2.d.ts"},"version":"FakeTSVersion"} + +//// [/src/project/outDir/tsconfig.tsbuildinfo.readable.baseline.txt] +{ + "program": { + "fileNames": [ + "../../../lib/lib.d.ts", + "../file1.ts" + ], + "fileInfos": { + "../../../lib/lib.d.ts": { + "original": { + "version": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "affectsGlobalScope": true + }, + "version": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "signature": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "affectsGlobalScope": true + }, + "../file1.ts": { + "original": { + "version": "-9819564552-export class C { }", + "signature": "-10192454122-export declare class C {\r\n}\r\n" + }, + "version": "-9819564552-export class C { }", + "signature": "-10192454122-export declare class C {\r\n}\r\n" + } + }, + "options": { + "composite": true, + "outDir": "./" + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "../../../lib/lib.d.ts", + "../file1.ts" + ], + "latestChangedDtsFile": "./file2.d.ts" + }, + "version": "FakeTSVersion", + "size": 850 +} +