From 1acd39ce0d3b9e02abbeb079b4f1708b5724774a Mon Sep 17 00:00:00 2001 From: Michael Molisani Date: Wed, 9 Dec 2020 16:38:50 -0500 Subject: [PATCH] Store projects in extended config file watcher Creates SharedExtendedConfigFileWatcher in both editorServices (tsserver) and tsbuildPublic. The file watcher is responsible for triggering a full project reload for the contained projects. Upon reload, any configs that are no longer related to a project have their watchers updated to match. New test cases to confirm that the file watchers for extended configs are closed when the project is closed. --- src/compiler/tsbuildPublic.ts | 64 +++++ src/compiler/watchPublic.ts | 12 +- src/compiler/watchUtilities.ts | 6 +- src/server/editorServices.ts | 77 +++--- .../unittests/tscWatch/programUpdates.ts | 77 ++++++ .../unittests/tsserver/configuredProjects.ts | 67 +++++- .../demo/updates-with-bad-reference.js | 4 + .../demo/updates-with-circular-reference.js | 4 + ...project-with-extended-config-is-removed.js | 220 ++++++++++++++++++ 9 files changed, 486 insertions(+), 45 deletions(-) create mode 100644 tests/baselines/reference/tsbuild/watchMode/programUpdates/works-correctly-when-project-with-extended-config-is-removed.js diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index f74b016093a1e..82cff02c36481 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -209,6 +209,10 @@ namespace ts { originalGetSourceFile: CompilerHost["getSourceFile"]; } + interface SharedExtendedConfigFileWatcher extends FileWatcher { + projects: Set; + } + interface SolutionBuilderState extends WatchFactory { readonly host: SolutionBuilderHost; readonly hostWithWatch: SolutionBuilderWithWatchHost; @@ -253,6 +257,7 @@ namespace ts { readonly allWatchedWildcardDirectories: ESMap>; readonly allWatchedInputFiles: ESMap>; readonly allWatchedConfigFiles: ESMap; + readonly allWatchedExtendedConfigFiles: ESMap; timerToBuildInvalidatedProject: any; reportFileChangeDetected: boolean; @@ -324,6 +329,7 @@ namespace ts { allWatchedWildcardDirectories: new Map(), allWatchedInputFiles: new Map(), allWatchedConfigFiles: new Map(), + allWatchedExtendedConfigFiles: new Map(), timerToBuildInvalidatedProject: undefined, reportFileChangeDetected: false, @@ -461,6 +467,18 @@ namespace ts { { onDeleteValue: closeFileWatcher } ); + state.allWatchedExtendedConfigFiles.forEach((watcher, extendedConfigFilePath) => { + watcher.projects.forEach((project) => { + if (!currentProjects.has(project)) { + watcher.projects.delete(project); + } + }); + if (watcher.projects.size === 0) { + watcher.close(); + state.allWatchedExtendedConfigFiles.delete(extendedConfigFilePath); + } + }); + mutateMapSkippingNewValues( state.allWatchedWildcardDirectories, currentProjects, @@ -1164,6 +1182,7 @@ namespace ts { if (reloadLevel === ConfigFileProgramReloadLevel.Full) { watchConfigFile(state, project, projectPath, config); + watchExtendedConfigFiles(state, projectPath, config); watchWildCardDirectories(state, project, projectPath, config); watchInputFiles(state, project, projectPath, config); } @@ -1790,6 +1809,49 @@ namespace ts { )); } + function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { + const extendedSourceFiles = parsed?.options.configFile?.extendedSourceFiles || emptyArray; + const extendedConfigs = new Map(extendedSourceFiles.map((extendedSourceFile) => { + const extendedConfigFileName = extendedSourceFile as ResolvedConfigFileName; + const extendedConfigFilePath = toResolvedConfigFilePath(state, extendedConfigFileName); + return [extendedConfigFilePath, extendedConfigFileName] as const; + })); + extendedConfigs.forEach((extendedConfigFileName, extendedConfigFilePath) => { + // start watching previously unseen extended config + if (!state.allWatchedExtendedConfigFiles.has(extendedConfigFilePath)) { + const projects = new Set([resolvedPath]); + const fileWatcher = state.watchFile( + extendedConfigFileName, + () => { + projects.forEach((projectConfigFilePath) => { + invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ConfigFileProgramReloadLevel.Full); + }); + }, + PollingInterval.High, + parsed?.watchOptions, + WatchType.ExtendedConfigFile, + extendedConfigFileName + ); + state.allWatchedExtendedConfigFiles.set(extendedConfigFilePath, { + close: () => fileWatcher.close(), + projects, + }); + } + }); + state.allWatchedExtendedConfigFiles.forEach((watcher, extendedConfigFilePath) => { + if (extendedConfigs.has(extendedConfigFilePath)) { + watcher.projects.add(resolvedPath); + } + else { + watcher.projects.delete(resolvedPath); + if (watcher.projects.size === 0) { + watcher.close(); + state.allWatchedExtendedConfigFiles.delete(extendedConfigFilePath); + } + } + }); + } + function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { if (!state.watch) return; updateWatchingWildcardDirectories( @@ -1848,6 +1910,7 @@ namespace ts { const cfg = parseConfigFile(state, resolved, resolvedPath); // Watch this file watchConfigFile(state, resolved, resolvedPath, cfg); + watchExtendedConfigFiles(state, resolvedPath, cfg); if (cfg) { // Update watchers for wildcard directories watchWildCardDirectories(state, resolved, resolvedPath, cfg); @@ -1860,6 +1923,7 @@ namespace ts { function stopWatching(state: SolutionBuilderState) { clearMap(state.allWatchedConfigFiles, closeFileWatcher); + clearMap(state.allWatchedExtendedConfigFiles, closeFileWatcher); clearMap(state.allWatchedWildcardDirectories, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf)); clearMap(state.allWatchedInputFiles, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcher)); } diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index c5b4ed9492c1f..0b94f4039745b 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -793,13 +793,11 @@ namespace ts { function watchExtendedConfigFiles() { const { configFile } = builderProgram.getCompilerOptions(); - if (configFile) { - updateExtendedConfigFilesMap( - configFile, - extendedConfigFilesMap || (extendedConfigFilesMap = new Map()), - watchExtendedConfigFile - ); - } + updateExtendedConfigFilesMap( + configFile, + extendedConfigFilesMap || (extendedConfigFilesMap = new Map()), + watchExtendedConfigFile + ); } function watchExtendedConfigFile(extendedConfigFile: string) { diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index 1a6a307a808ce..97bfb974316e4 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -261,11 +261,11 @@ namespace ts { * Updates the map of extended config file watches with a new set of extended config files from a base config file */ export function updateExtendedConfigFilesMap( - configFile: TsConfigSourceFile, - extendedConfigFilesMap: ESMap, + configFile: TsConfigSourceFile | undefined, + extendedConfigFilesMap: ESMap, createExtendedConfigFileWatch: (extendedConfigPath: string) => FileWatcher, ) { - const extendedSourceFiles = configFile.extendedSourceFiles || emptyArray; + const extendedSourceFiles = configFile?.extendedSourceFiles ?? emptyArray; // TODO(rbuckton): Should be a `Set` but that requires changing the below code that uses `mutateMap` const newExtendedConfigFilesMap = arrayToMap(extendedSourceFiles, identity, returnTrue); // Update the extended config files watcher diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 3b8de491fc5c8..afbc6349de805 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -641,6 +641,10 @@ namespace ts.server { errors: Diagnostic[] | undefined; } + interface SharedExtendedConfigFileWatcher extends FileWatcher { + projects: Set; + } + export class ProjectService { /*@internal*/ @@ -757,9 +761,7 @@ namespace ts.server { readonly watchFactory: WatchFactory; /*@internal*/ - private sharedExtendedConfigFileMap = createMultiMap(); - /*@internal*/ - private sharedExtendedConfigFileWatchers = new Map(); + private readonly sharedExtendedConfigFileWatchers = new Map(); /*@internal*/ readonly packageJsonCache: PackageJsonCache; @@ -1358,53 +1360,60 @@ namespace ts.server { /*@internal*/ private updateSharedExtendedConfigFileMap(project: ConfiguredProject) { - const extendedSourceFiles = project.getCompilerOptions().configFile?.extendedSourceFiles || emptyArray; - extendedSourceFiles.forEach((extendedSourceFile: string) => { - const extendedConfigPath = this.toPath(extendedSourceFile); - if (!this.sharedExtendedConfigFileMap.has(extendedConfigPath)) { - const watcher = this.watchFactory.watchFile( + const extendedConfigPaths: readonly Path[] = project.getCompilerOptions().configFile?.extendedSourceFiles + ?.map((file) => this.toPath(file)) ?? emptyArray; + for (const extendedConfigPath of extendedConfigPaths) { + // start watching previously unseen extended config + if (!this.sharedExtendedConfigFileWatchers.has(extendedConfigPath)) { + const projects = new Set([project]); + const fileWatcherCallback = () => { + const reason = `Change in extended config file ${extendedConfigPath} detected`; + projects.forEach((project: ConfiguredProject) => { + // Skip refresh if project is not yet loaded + if (project.isInitialLoadPending()) return; + project.pendingReload = ConfigFileProgramReloadLevel.Full; + project.pendingReloadReason = reason; + this.delayUpdateProjectGraph(project); + }); + }; + const fileWatcher = this.watchFactory.watchFile( extendedConfigPath, - () => this.onSharedExtendedConfigChanged(extendedConfigPath), + fileWatcherCallback, PollingInterval.High, this.hostConfiguration.watchOptions, WatchType.ExtendedConfigFile ); - this.sharedExtendedConfigFileWatchers.set(extendedConfigPath, watcher); + this.sharedExtendedConfigFileWatchers.set(extendedConfigPath, { + close: () => fileWatcher.close(), + projects, + }); } - const otherProjects = this.sharedExtendedConfigFileMap.get(extendedConfigPath); - if (!otherProjects || !otherProjects.includes(project)) { - this.sharedExtendedConfigFileMap.add(extendedConfigPath, project); + } + this.sharedExtendedConfigFileWatchers.forEach((watcher, extendedConfigPath) => { + if (extendedConfigPaths.includes(extendedConfigPath)) { + watcher.projects.add(project); + } + else { + watcher.projects.delete(project); + if (watcher.projects.size === 0) { + watcher.close(); + this.sharedExtendedConfigFileWatchers.delete(extendedConfigPath); + } } }); } /*@internal*/ private removeProjectFromSharedExtendedConfigFileMap(project: ConfiguredProject) { - for (const key of arrayFrom(this.sharedExtendedConfigFileMap.keys())) { - this.sharedExtendedConfigFileMap.remove(key, project); - const otherProjects = this.sharedExtendedConfigFileMap.get(key) || emptyArray; - if (otherProjects.length === 0) { - const watcher = this.sharedExtendedConfigFileWatchers.get(key); - if (watcher) { - watcher.close(); - this.sharedExtendedConfigFileWatchers.delete(key); - } + for (const [sharedConfigPath, watcher] of arrayFrom(this.sharedExtendedConfigFileWatchers.entries())) { + watcher.projects.delete(project); + if (watcher.projects.size === 0) { + watcher.close(); + this.sharedExtendedConfigFileWatchers.delete(sharedConfigPath); } } } - /*@internal*/ - private onSharedExtendedConfigChanged(extendedConfigPath: Path) { - const projects = this.sharedExtendedConfigFileMap.get(extendedConfigPath) || emptyArray; - projects.forEach((project: ConfiguredProject) => { - // Skip refresh if project is not yet loaded - if (project.isInitialLoadPending()) return; - project.pendingReload = ConfigFileProgramReloadLevel.Full; - project.pendingReloadReason = `Change in extended config file ${extendedConfigPath} detected`; - this.delayUpdateProjectGraph(project); - }); - } - /** * This is the callback function for the config file add/remove/change at any location * that matters to open script info but doesnt have configured project open diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index b9d6547393d70..54130962c5a8c 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -1766,5 +1766,82 @@ import { x } from "../b";`), } ] }); + + verifyTscWatch({ + scenario, + subScenario: "works correctly when project with extended config is removed", + commandLineArgs: ["-b", "-w", configFilePath], + sys: () => { + const alphaExtendedConfigFile: File = { + path: "/a/b/alpha.tsconfig.json", + content: JSON.stringify({ + strict: true + }) + }; + const project1Config: File = { + path: "/a/b/project1.tsconfig.json", + content: JSON.stringify({ + extends: "./alpha.tsconfig.json", + compilerOptions: { + composite: true, + }, + files: [commonFile1.path, commonFile2.path] + }) + }; + const bravoExtendedConfigFile: File = { + path: "/a/b/bravo.tsconfig.json", + content: JSON.stringify({ + strict: true + }) + }; + const otherFile: File = { + path: "/a/b/other.ts", + content: "let z = 0;", + }; + const project2Config: File = { + path: "/a/b/project2.tsconfig.json", + content: JSON.stringify({ + extends: "./bravo.tsconfig.json", + compilerOptions: { + composite: true, + }, + files: [otherFile.path] + }) + }; + const configFile: File = { + path: configFilePath, + content: JSON.stringify({ + references: [ + { + path: "./project1.tsconfig.json", + }, + { + path: "./project2.tsconfig.json", + }, + ], + files: [], + }) + }; + return createWatchedSystem([ + libFile, configFile, + alphaExtendedConfigFile, project1Config, commonFile1, commonFile2, + bravoExtendedConfigFile, project2Config, otherFile + ]); + }, + changes: [ + { + caption: "Remove project2 from base config", + change: sys => sys.modifyFile(configFilePath, JSON.stringify({ + references: [ + { + path: "./project1.tsconfig.json", + }, + ], + files: [], + })), + timeouts: checkSingleTimeoutQueueLengthAndRun, + } + ] + }); }); } diff --git a/src/testRunner/unittests/tsserver/configuredProjects.ts b/src/testRunner/unittests/tsserver/configuredProjects.ts index 2a27cf9f7ca6c..85437496f6277 100644 --- a/src/testRunner/unittests/tsserver/configuredProjects.ts +++ b/src/testRunner/unittests/tsserver/configuredProjects.ts @@ -1136,7 +1136,7 @@ foo();` projectService.openClientFile(aFile.path); projectService.openClientFile(bFile.path); - checkNumberOfProjects(projectService, { configuredProjects: 2 }); + checkNumberOfConfiguredProjects(projectService, 2); const aProject = configuredProjectAt(projectService, 0); const bProject = configuredProjectAt(projectService, 1); checkProjectActualFiles(aProject, [aFile.path, aConfig.path, alphaExtendedConfig.path]); @@ -1171,6 +1171,71 @@ foo();` assert.isTrue(aOptions3.strict); assert.isFalse(bOptions3.strict); }); + + it("should stop watching the extended configs of closed projects", () => { + const alphaExtendedConfig: File = { + path: `${tscWatch.projectRoot}/extended/alpha.tsconfig.json`, + content: "{}" + }; + const bravoExtendedConfig: File = { + path: `${tscWatch.projectRoot}/extended/bravo.tsconfig.json`, + content: JSON.stringify({ + extends: "./alpha.tsconfig.json" + }) + }; + const aConfig: File = { + path: `${tscWatch.projectRoot}/a/tsconfig.json`, + content: JSON.stringify({ + extends: "../extended/alpha.tsconfig.json", + files: ["a.ts"] + }) + }; + const aFile: File = { + path: `${tscWatch.projectRoot}/a/a.ts`, + content: `let a = 1;` + }; + const bConfig: File = { + path: `${tscWatch.projectRoot}/b/tsconfig.json`, + content: JSON.stringify({ + extends: "../extended/bravo.tsconfig.json", + files: ["b.ts"] + }) + }; + const bFile: File = { + path: `${tscWatch.projectRoot}/b/b.ts`, + content: `let b = 1;` + }; + + const host = createServerHost([ + alphaExtendedConfig, aConfig, aFile, + bravoExtendedConfig, bConfig, bFile + ]); + const projectService = createProjectService(host); + + projectService.openClientFile(aFile.path); + projectService.openClientFile(bFile.path); + checkNumberOfConfiguredProjects(projectService, 2); + const aProject = configuredProjectAt(projectService, 0); + const bProject = configuredProjectAt(projectService, 1); + checkProjectActualFiles(aProject, [aFile.path, aConfig.path, alphaExtendedConfig.path]); + checkProjectActualFiles(bProject, [bFile.path, bConfig.path, alphaExtendedConfig.path, bravoExtendedConfig.path]); + + checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, bravoExtendedConfig.path, alphaExtendedConfig.path]); + + projectService.closeClientFile(bFile.path); + host.deleteFile(bConfig.path); + + assert.isTrue(bProject.isClosed()); + checkNumberOfConfiguredProjects(projectService, 1); + checkWatchedFiles(host, [aConfig.path, libFile.path, alphaExtendedConfig.path, bFile.path]); + + projectService.closeClientFile(aFile.path); + host.deleteFile(aConfig.path); + + assert.isTrue(aProject.isClosed()); + checkNumberOfConfiguredProjects(projectService, 0); + checkWatchedFiles(host, [aFile.path, bFile.path]); + }); }); describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories listed in config file input array", () => { diff --git a/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-bad-reference.js b/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-bad-reference.js index c15390100b44e..0d6d5c182241a 100644 --- a/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-bad-reference.js +++ b/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-bad-reference.js @@ -225,6 +225,8 @@ Semantic diagnostics in builder refreshed for:: WatchedFiles:: /user/username/projects/demo/core/tsconfig.json: {"fileName":"/user/username/projects/demo/core/tsconfig.json","pollingInterval":250} +/user/username/projects/demo/tsconfig-base.json: + {"fileName":"/user/username/projects/demo/tsconfig-base.json","pollingInterval":250} /user/username/projects/demo/core/utilities.ts: {"fileName":"/user/username/projects/demo/core/utilities.ts","pollingInterval":250} /user/username/projects/demo/animals/tsconfig.json: @@ -446,6 +448,8 @@ Semantic diagnostics in builder refreshed for:: WatchedFiles:: /user/username/projects/demo/core/tsconfig.json: {"fileName":"/user/username/projects/demo/core/tsconfig.json","pollingInterval":250} +/user/username/projects/demo/tsconfig-base.json: + {"fileName":"/user/username/projects/demo/tsconfig-base.json","pollingInterval":250} /user/username/projects/demo/core/utilities.ts: {"fileName":"/user/username/projects/demo/core/utilities.ts","pollingInterval":250} /user/username/projects/demo/animals/tsconfig.json: diff --git a/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-circular-reference.js b/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-circular-reference.js index b3d953ce202e2..fe11f64715bf9 100644 --- a/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-circular-reference.js +++ b/tests/baselines/reference/tsbuild/watchMode/demo/updates-with-circular-reference.js @@ -170,6 +170,8 @@ Output:: WatchedFiles:: /user/username/projects/demo/animals/tsconfig.json: {"fileName":"/user/username/projects/demo/animals/tsconfig.json","pollingInterval":250} +/user/username/projects/demo/tsconfig-base.json: + {"fileName":"/user/username/projects/demo/tsconfig-base.json","pollingInterval":250} /user/username/projects/demo/animals/animal.ts: {"fileName":"/user/username/projects/demo/animals/animal.ts","pollingInterval":250} /user/username/projects/demo/animals/dog.ts: @@ -281,6 +283,8 @@ Semantic diagnostics in builder refreshed for:: WatchedFiles:: /user/username/projects/demo/animals/tsconfig.json: {"fileName":"/user/username/projects/demo/animals/tsconfig.json","pollingInterval":250} +/user/username/projects/demo/tsconfig-base.json: + {"fileName":"/user/username/projects/demo/tsconfig-base.json","pollingInterval":250} /user/username/projects/demo/animals/animal.ts: {"fileName":"/user/username/projects/demo/animals/animal.ts","pollingInterval":250} /user/username/projects/demo/animals/dog.ts: diff --git a/tests/baselines/reference/tsbuild/watchMode/programUpdates/works-correctly-when-project-with-extended-config-is-removed.js b/tests/baselines/reference/tsbuild/watchMode/programUpdates/works-correctly-when-project-with-extended-config-is-removed.js new file mode 100644 index 0000000000000..5efada1805b32 --- /dev/null +++ b/tests/baselines/reference/tsbuild/watchMode/programUpdates/works-correctly-when-project-with-extended-config-is-removed.js @@ -0,0 +1,220 @@ +Input:: +//// [/a/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; } + +//// [/a/b/tsconfig.json] +{"references":[{"path":"./project1.tsconfig.json"},{"path":"./project2.tsconfig.json"}],"files":[]} + +//// [/a/b/alpha.tsconfig.json] +{"strict":true} + +//// [/a/b/project1.tsconfig.json] +{"extends":"./alpha.tsconfig.json","compilerOptions":{"composite":true},"files":["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]} + +//// [/a/b/commonFile1.ts] +let x = 1 + +//// [/a/b/commonFile2.ts] +let y = 1 + +//// [/a/b/bravo.tsconfig.json] +{"strict":true} + +//// [/a/b/project2.tsconfig.json] +{"extends":"./bravo.tsconfig.json","compilerOptions":{"composite":true},"files":["/a/b/other.ts"]} + +//// [/a/b/other.ts] +let z = 0; + + +/a/lib/tsc.js -b -w /a/b/tsconfig.json +Output:: +>> Screen clear +[12:00:27 AM] Starting compilation in watch mode... + +[12:00:44 AM] Found 0 errors. Watching for file changes. + + + +Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"] +Program options: {"composite":true,"watch":true,"configFilePath":"/a/b/project1.tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/a/b/commonFile1.ts +/a/b/commonFile2.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/a/b/commonFile1.ts +/a/b/commonFile2.ts + +Program root files: ["/a/b/other.ts"] +Program options: {"composite":true,"watch":true,"configFilePath":"/a/b/project2.tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/a/b/other.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/a/b/other.ts + +WatchedFiles:: +/a/b/project1.tsconfig.json: + {"fileName":"/a/b/project1.tsconfig.json","pollingInterval":250} +/a/b/alpha.tsconfig.json: + {"fileName":"/a/b/alpha.tsconfig.json","pollingInterval":250} +/a/b/commonfile1.ts: + {"fileName":"/a/b/commonFile1.ts","pollingInterval":250} +/a/b/commonfile2.ts: + {"fileName":"/a/b/commonFile2.ts","pollingInterval":250} +/a/b/project2.tsconfig.json: + {"fileName":"/a/b/project2.tsconfig.json","pollingInterval":250} +/a/b/bravo.tsconfig.json: + {"fileName":"/a/b/bravo.tsconfig.json","pollingInterval":250} +/a/b/other.ts: + {"fileName":"/a/b/other.ts","pollingInterval":250} +/a/b/tsconfig.json: + {"fileName":"/a/b/tsconfig.json","pollingInterval":250} + +FsWatches:: + +FsWatchesRecursive:: + +exitCode:: ExitStatus.undefined + +//// [/a/b/commonFile1.js] +var x = 1; + + +//// [/a/b/commonFile1.d.ts] +declare let x: number; + + +//// [/a/b/commonFile2.js] +var y = 1; + + +//// [/a/b/commonFile2.d.ts] +declare let y: number; + + +//// [/a/b/project1.tsconfig.tsbuildinfo] +{ + "program": { + "fileInfos": { + "../lib/lib.d.ts": { + "version": "-7698705165-/// \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; }", + "signature": "-7698705165-/// \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; }", + "affectsGlobalScope": true + }, + "./commonfile1.ts": { + "version": "2167136208-let x = 1", + "signature": "2842409786-declare let x: number;\n", + "affectsGlobalScope": true + }, + "./commonfile2.ts": { + "version": "2168322129-let y = 1", + "signature": "784887931-declare let y: number;\n", + "affectsGlobalScope": true + } + }, + "options": { + "composite": true, + "watch": true, + "configFilePath": "./project1.tsconfig.json" + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "./commonfile1.ts", + "./commonfile2.ts", + "../lib/lib.d.ts" + ] + }, + "version": "FakeTSVersion" +} + +//// [/a/b/other.js] +var z = 0; + + +//// [/a/b/other.d.ts] +declare let z: number; + + +//// [/a/b/project2.tsconfig.tsbuildinfo] +{ + "program": { + "fileInfos": { + "../lib/lib.d.ts": { + "version": "-7698705165-/// \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; }", + "signature": "-7698705165-/// \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; }", + "affectsGlobalScope": true + }, + "./other.ts": { + "version": "2874288940-let z = 0;", + "signature": "-1272633924-declare let z: number;\n", + "affectsGlobalScope": true + } + }, + "options": { + "composite": true, + "watch": true, + "configFilePath": "./project2.tsconfig.json" + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "./other.ts", + "../lib/lib.d.ts" + ] + }, + "version": "FakeTSVersion" +} + + +Change:: Remove project2 from base config + +Input:: +//// [/a/b/tsconfig.json] +{"references":[{"path":"./project1.tsconfig.json"}],"files":[]} + + +Output:: +>> Screen clear +[12:00:47 AM] File change detected. Starting incremental compilation... + +[12:00:48 AM] Found 0 errors. Watching for file changes. + + + +WatchedFiles:: +/a/b/project1.tsconfig.json: + {"fileName":"/a/b/project1.tsconfig.json","pollingInterval":250} +/a/b/alpha.tsconfig.json: + {"fileName":"/a/b/alpha.tsconfig.json","pollingInterval":250} +/a/b/commonfile1.ts: + {"fileName":"/a/b/commonFile1.ts","pollingInterval":250} +/a/b/commonfile2.ts: + {"fileName":"/a/b/commonFile2.ts","pollingInterval":250} +/a/b/tsconfig.json: + {"fileName":"/a/b/tsconfig.json","pollingInterval":250} + +FsWatches:: + +FsWatchesRecursive:: + +exitCode:: ExitStatus.undefined +