From 941d97c45a37d0ac6a2b6ba8a6806933b14df856 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 9 Nov 2018 16:41:18 -0800 Subject: [PATCH] Handle global augmentation in the module --- src/compiler/builderState.ts | 20 +++++- src/testRunner/unittests/tscWatchMode.ts | 85 +++++++++++++++--------- 2 files changed, 71 insertions(+), 34 deletions(-) diff --git a/src/compiler/builderState.ts b/src/compiler/builderState.ts index 7cd67d99f72..7c7bebde9f9 100644 --- a/src/compiler/builderState.ts +++ b/src/compiler/builderState.ts @@ -368,7 +368,7 @@ namespace ts.BuilderState { } // If this is non module emit, or its a global file, it depends on all the source files - if (!state.referencedMap || (!isExternalModule(sourceFile) && !containsOnlyAmbientModules(sourceFile))) { + if (!state.referencedMap || isFileAffectingGlobalScope(sourceFile)) { return getAllFileNames(state, programOfThisState); } @@ -430,6 +430,22 @@ namespace ts.BuilderState { return true; } + /** + * Return true if file contains anything that augments to global scope we need to build them as if + * they are global files as well as module + */ + function containsGlobalScopeAugmentation(sourceFile: SourceFile) { + return some(sourceFile.moduleAugmentations, augmentation => isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)); + } + + /** + * Return true if the file will invalidate all files because it affectes global scope + */ + function isFileAffectingGlobalScope(sourceFile: SourceFile) { + return containsGlobalScopeAugmentation(sourceFile) || + !isExternalModule(sourceFile) && !containsOnlyAmbientModules(sourceFile); + } + /** * Gets all files of the program excluding the default library file */ @@ -473,7 +489,7 @@ namespace ts.BuilderState { * When program emits modular code, gets the files affected by the sourceFile whose shape has changed */ function getFilesAffectedByUpdatedShapeWhenModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile, cacheToUpdateSignature: Map, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash | undefined, exportedModulesMapCache: ComputingExportedModulesMap | undefined) { - if (!isExternalModule(sourceFileWithUpdatedShape) && !containsOnlyAmbientModules(sourceFileWithUpdatedShape)) { + if (isFileAffectingGlobalScope(sourceFileWithUpdatedShape)) { return getAllFilesExcludingDefaultLibraryFile(state, programOfThisState, sourceFileWithUpdatedShape); } diff --git a/src/testRunner/unittests/tscWatchMode.ts b/src/testRunner/unittests/tscWatchMode.ts index 1e65e7b9e99..65f64b9da78 100644 --- a/src/testRunner/unittests/tscWatchMode.ts +++ b/src/testRunner/unittests/tscWatchMode.ts @@ -1565,15 +1565,13 @@ export class Data2 { }); }); - describe("updates errors in lib file when non module file changes", () => { + describe("updates errors in lib file", () => { const currentDirectory = "/user/username/projects/myproject"; const field = "fullscreen"; - const aFile: File = { - path: `${currentDirectory}/a.ts`, - content: `interface Document { + const fieldWithoutReadonly = `interface Document { ${field}: boolean; -}` - }; +}`; + const libFileWithDocument: File = { path: libFile.path, content: `${libFile.content} @@ -1586,40 +1584,63 @@ interface Document { return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(field), field.length, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, field); } - const files = [aFile, libFileWithDocument]; + function verifyLibFileErrorsWith(aFile: File) { + const files = [aFile, libFileWithDocument]; - function verifyLibErrors(options: CompilerOptions) { - const host = createWatchedSystem(files, { currentDirectory }); - const watch = createWatchOfFilesAndCompilerOptions([aFile.path], host, options); - checkProgramActualFiles(watch(), [aFile.path, libFile.path]); - checkOutputErrorsInitial(host, getErrors()); + function verifyLibErrors(options: CompilerOptions) { + const host = createWatchedSystem(files, { currentDirectory }); + const watch = createWatchOfFilesAndCompilerOptions([aFile.path], host, options); + checkProgramActualFiles(watch(), [aFile.path, libFile.path]); + checkOutputErrorsInitial(host, getErrors()); - host.writeFile(aFile.path, "var x = 10;"); - host.runQueuedTimeoutCallbacks(); - checkProgramActualFiles(watch(), [aFile.path, libFile.path]); - checkOutputErrorsIncremental(host, emptyArray); + host.writeFile(aFile.path, aFile.content.replace(fieldWithoutReadonly, "var x: string;")); + host.runQueuedTimeoutCallbacks(); + checkProgramActualFiles(watch(), [aFile.path, libFile.path]); + checkOutputErrorsIncremental(host, emptyArray); - host.writeFile(aFile.path, aFile.content); - host.runQueuedTimeoutCallbacks(); - checkProgramActualFiles(watch(), [aFile.path, libFile.path]); - checkOutputErrorsIncremental(host, getErrors()); + host.writeFile(aFile.path, aFile.content); + host.runQueuedTimeoutCallbacks(); + checkProgramActualFiles(watch(), [aFile.path, libFile.path]); + checkOutputErrorsIncremental(host, getErrors()); - function getErrors() { - return [ - ...(options.skipLibCheck || options.skipDefaultLibCheck ? [] : [getDiagnostic(watch(), libFileWithDocument)]), - getDiagnostic(watch(), aFile) - ]; + function getErrors() { + return [ + ...(options.skipLibCheck || options.skipDefaultLibCheck ? [] : [getDiagnostic(watch(), libFileWithDocument)]), + getDiagnostic(watch(), aFile) + ]; + } } + + it("with default options", () => { + verifyLibErrors({}); + }); + it("with skipLibCheck", () => { + verifyLibErrors({ skipLibCheck: true }); + }); + it("with skipDefaultLibCheck", () => { + verifyLibErrors({ skipDefaultLibCheck: true }); + }); } - it("with default options", () => { - verifyLibErrors({}); + describe("when non module file changes", () => { + const aFile: File = { + path: `${currentDirectory}/a.ts`, + content: `${fieldWithoutReadonly} +var y: number;` + }; + verifyLibFileErrorsWith(aFile); }); - it("with skipLibCheck", () => { - verifyLibErrors({ skipLibCheck: true }); - }); - it("with skipDefaultLibCheck", () => { - verifyLibErrors({ skipDefaultLibCheck: true }); + + describe("when module file with global definitions changes", () => { + const aFile: File = { + path: `${currentDirectory}/a.ts`, + content: `export {} +declare global { +${fieldWithoutReadonly} +var y: number; +}` + }; + verifyLibFileErrorsWith(aFile); }); });