Watch extended configs if present (#41493)

* Watch extended configs if present

* Address code review comments

Added new `WatchType` for extended config files. Refactored watch map
update to separate function, relocated call sites. Removed unnecessary
test cases and relocated with new tests in programUpdates.

* Unify extended config file watching between tsc/tsserver

Update `updateExtendedConfigFilesWatch` to read from a
`TsConfigSourceFile` to get `extendedSourceFiles`. Add watcher map to
`ConfiguredProject` in the server. New test cases to verify correct
events triggered and extended files are being watched properly.

* Simplify watcher callback, fix tests

Removes unnecessary actions in extended config watcher callback
function. Updates tests to match.

* Share extended config watchers across projects in server

New shared watcher map in ProjectService that stores callbacks per
project to be invoked when the file watcher is triggered. The
FileWatcher is created with the watch options of the first Project to
watch the extended config.

* Refactor shared extended config map and watchers

Remove all server-related utility functions/types from
watchUtilities. Store config-project mapping and config file watchers
inside ProjectService with new private methods to add or remove
projects.

* 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.

* Apply suggestions from code review

Co-authored-by: Sheetal Nandi <shkamat@microsoft.com>

* Map extended config files by path

* Move shared watcher into utilities and add more tests

Co-authored-by: Sheetal Nandi <shkamat@microsoft.com>
This commit is contained in:
Michael Molisani 2020-12-10 20:20:02 -05:00 committed by GitHub
parent 3e72526600
commit 716b167f2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1614 additions and 1 deletions

View File

@ -254,6 +254,7 @@ namespace ts {
readonly allWatchedWildcardDirectories: ESMap<ResolvedConfigFilePath, ESMap<string, WildcardDirectoryWatcher>>;
readonly allWatchedInputFiles: ESMap<ResolvedConfigFilePath, ESMap<Path, FileWatcher>>;
readonly allWatchedConfigFiles: ESMap<ResolvedConfigFilePath, FileWatcher>;
readonly allWatchedExtendedConfigFiles: ESMap<Path, SharedExtendedConfigFileWatcher<ResolvedConfigFilePath>>;
timerToBuildInvalidatedProject: any;
reportFileChangeDetected: boolean;
@ -325,6 +326,7 @@ namespace ts {
allWatchedWildcardDirectories: new Map(),
allWatchedInputFiles: new Map(),
allWatchedConfigFiles: new Map(),
allWatchedExtendedConfigFiles: new Map(),
timerToBuildInvalidatedProject: undefined,
reportFileChangeDetected: false,
@ -462,6 +464,15 @@ namespace ts {
{ onDeleteValue: closeFileWatcher }
);
state.allWatchedExtendedConfigFiles.forEach(watcher => {
watcher.projects.forEach(project => {
if (!currentProjects.has(project)) {
watcher.projects.delete(project);
}
});
watcher.close();
});
mutateMapSkippingNewValues(
state.allWatchedWildcardDirectories,
currentProjects,
@ -1165,6 +1176,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);
}
@ -1789,6 +1801,24 @@ namespace ts {
));
}
function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) {
updateSharedExtendedConfigFileWatcher(
resolvedPath,
parsed,
state.allWatchedExtendedConfigFiles,
(extendedConfigFileName, extendedConfigFilePath) => state.watchFile(
extendedConfigFileName,
() => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath =>
invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ConfigFileProgramReloadLevel.Full)
),
PollingInterval.High,
parsed?.watchOptions,
WatchType.ExtendedConfigFile,
),
fileName => toPath(state, fileName),
);
}
function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) {
if (!state.watch) return;
updateWatchingWildcardDirectories(
@ -1846,6 +1876,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);
@ -1858,6 +1889,10 @@ namespace ts {
function stopWatching(state: SolutionBuilderState) {
clearMap(state.allWatchedConfigFiles, closeFileWatcher);
clearMap(state.allWatchedExtendedConfigFiles, watcher => {
watcher.projects.clear();
watcher.close();
});
clearMap(state.allWatchedWildcardDirectories, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf));
clearMap(state.allWatchedInputFiles, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcher));
}

View File

@ -409,6 +409,7 @@ namespace ts {
export type WatchType = WatchTypeRegistry[keyof WatchTypeRegistry];
export const WatchType: WatchTypeRegistry = {
ConfigFile: "Config file",
ExtendedConfigFile: "Extended config file",
SourceFile: "Source file",
MissingFile: "Missing file",
WildcardDirectory: "Wild card directory",
@ -418,6 +419,7 @@ namespace ts {
export interface WatchTypeRegistry {
ConfigFile: "Config file",
ExtendedConfigFile: "Extended config file",
SourceFile: "Source file",
MissingFile: "Missing file",
WildcardDirectory: "Wild card directory",

View File

@ -246,6 +246,7 @@ namespace ts {
let builderProgram: T;
let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc
let extendedConfigFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the extended config files
let missingFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the missing files
let watchedWildcardDirectories: ESMap<string, WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
let timerToUpdateProgram: any; // timer callback to recompile the program
@ -337,6 +338,9 @@ namespace ts {
// Update the wild card directory watch
watchConfigFileWildCardDirectories();
// Update extended config file watch
watchExtendedConfigFiles();
return configFileName ?
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } :
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close };
@ -354,6 +358,10 @@ namespace ts {
configFileWatcher.close();
configFileWatcher = undefined;
}
if (extendedConfigFilesMap) {
clearMap(extendedConfigFilesMap, closeFileWatcher);
extendedConfigFilesMap = undefined!;
}
if (watchedWildcardDirectories) {
clearMap(watchedWildcardDirectories, closeFileWatcherOf);
watchedWildcardDirectories = undefined!;
@ -657,6 +665,9 @@ namespace ts {
// Update the wild card directory watch
watchConfigFileWildCardDirectories();
// Update extended config file watch
watchExtendedConfigFiles();
}
function parseConfigFile() {
@ -777,5 +788,23 @@ namespace ts {
WatchType.WildcardDirectory
);
}
function watchExtendedConfigFiles() {
// Update the extended config files watcher
mutateMap(
extendedConfigFilesMap ||= new Map(),
arrayToMap(compilerOptions.configFile?.extendedSourceFiles || emptyArray, toPath),
{
// Watch the extended config files
createNewValue: watchExtendedConfigFile,
// Config files that are no longer extended should no longer be watched.
onDeleteValue: closeFileWatcher
}
);
}
function watchExtendedConfigFile(extendedConfigFile: Path) {
return watchFile(extendedConfigFile, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ExtendedConfigFile);
}
}
}

View File

@ -257,6 +257,51 @@ namespace ts {
Full
}
export interface SharedExtendedConfigFileWatcher<T> extends FileWatcher {
fileWatcher: FileWatcher;
projects: Set<T>;
}
/**
* Updates the map of shared extended config file watches with a new set of extended config files from a base config file of the project
*/
export function updateSharedExtendedConfigFileWatcher<T>(
projectPath: T,
parsed: ParsedCommandLine | undefined,
extendedConfigFilesMap: ESMap<Path, SharedExtendedConfigFileWatcher<T>>,
createExtendedConfigFileWatch: (extendedConfigPath: string, extendedConfigFilePath: Path) => FileWatcher,
toPath: (fileName: string) => Path,
) {
const extendedConfigs = arrayToMap(parsed?.options.configFile?.extendedSourceFiles || emptyArray, toPath);
// remove project from all unrelated watchers
extendedConfigFilesMap.forEach((watcher, extendedConfigFilePath) => {
if (!extendedConfigs.has(extendedConfigFilePath)) {
watcher.projects.delete(projectPath);
watcher.close();
}
});
// Update the extended config files watcher
extendedConfigs.forEach((extendedConfigFileName, extendedConfigFilePath) => {
const existing = extendedConfigFilesMap.get(extendedConfigFilePath);
if (existing) {
existing.projects.add(projectPath);
}
else {
// start watching previously unseen extended config
extendedConfigFilesMap.set(extendedConfigFilePath, {
projects: new Set([projectPath]),
fileWatcher: createExtendedConfigFileWatch(extendedConfigFileName, extendedConfigFilePath),
close: () => {
const existing = extendedConfigFilesMap.get(extendedConfigFilePath);
if (!existing || existing.projects.size !== 0) return;
existing.fileWatcher.close();
extendedConfigFilesMap.delete(extendedConfigFilePath);
},
});
}
});
}
/**
* Updates the existing missing file watches with the new set of missing files after new program is created
*/

View File

@ -756,6 +756,9 @@ namespace ts.server {
/*@internal*/
readonly watchFactory: WatchFactory<WatchType, Project>;
/*@internal*/
private readonly sharedExtendedConfigFileWatchers = new Map<Path, SharedExtendedConfigFileWatcher<NormalizedPath>>();
/*@internal*/
readonly packageJsonCache: PackageJsonCache;
/*@internal*/
@ -1350,6 +1353,43 @@ namespace ts.server {
}
}
/*@internal*/
updateSharedExtendedConfigFileMap({ canonicalConfigFilePath }: ConfiguredProject, parsedCommandLine: ParsedCommandLine) {
updateSharedExtendedConfigFileWatcher(
canonicalConfigFilePath,
parsedCommandLine,
this.sharedExtendedConfigFileWatchers,
(extendedConfigFileName, extendedConfigFilePath) => this.watchFactory.watchFile(
extendedConfigFileName,
() => {
let ensureProjectsForOpenFiles = false;
this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects.forEach(canonicalPath => {
const project = this.configuredProjects.get(canonicalPath);
// Skip refresh if project is not yet loaded
if (!project || project.isInitialLoadPending()) return;
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = `Change in extended config file ${extendedConfigFileName} detected`;
this.delayUpdateProjectGraph(project);
ensureProjectsForOpenFiles = true;
});
if (ensureProjectsForOpenFiles) this.delayEnsureProjectForOpenFiles();
},
PollingInterval.High,
this.hostConfiguration.watchOptions,
WatchType.ExtendedConfigFile
),
fileName => this.toPath(fileName),
);
}
/*@internal*/
removeProjectFromSharedExtendedConfigFileMap(project: ConfiguredProject) {
this.sharedExtendedConfigFileWatchers.forEach(watcher => {
watcher.projects.delete(project.canonicalConfigFilePath);
watcher.close();
});
}
/**
* 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
@ -2051,7 +2091,6 @@ namespace ts.server {
this,
this.documentRegistry,
cachedDirectoryStructureHost);
// TODO: We probably should also watch the configFiles that are extended
project.createConfigFileWatcher();
this.configuredProjects.set(project.canonicalConfigFilePath, project);
this.setConfigFileExistenceByNewConfiguredProject(project);
@ -2134,12 +2173,14 @@ namespace ts.server {
if (lastFileExceededProgramSize) {
project.disableLanguageService(lastFileExceededProgramSize);
project.stopWatchingWildCards();
this.removeProjectFromSharedExtendedConfigFileMap(project);
}
else {
project.setCompilerOptions(compilerOptions);
project.setWatchOptions(parsedCommandLine.watchOptions);
project.enableLanguageService();
project.watchWildcards(new Map(getEntries(parsedCommandLine.wildcardDirectories!))); // TODO: GH#18217
this.updateSharedExtendedConfigFileMap(project, parsedCommandLine);
}
project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides);
const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles());

View File

@ -2292,6 +2292,7 @@ namespace ts.server {
}
this.stopWatchingWildCards();
this.projectService.removeProjectFromSharedExtendedConfigFileMap(this);
this.projectErrors = undefined;
this.openFileWatchTriggered.clear();
this.compilerHost = undefined;

View File

@ -1219,6 +1219,169 @@ export function someFn() { }`),
noopChange
]
});
verifyTscWatch({
scenario,
subScenario: "works with extended source files",
commandLineArgs: ["-b", "-w", "-v", "project1.tsconfig.json", "project2.tsconfig.json"],
sys: () => {
const alphaExtendedConfigFile: File = {
path: "/a/b/alpha.tsconfig.json",
content: "{}"
};
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({
extends: "./alpha.tsconfig.json"
})
};
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]
})
};
return createWatchedSystem([
libFile,
alphaExtendedConfigFile, project1Config, commonFile1, commonFile2,
bravoExtendedConfigFile, project2Config, otherFile
], { currentDirectory: "/a/b" });
},
changes: [
{
caption: "Modify alpha config",
change: sys => sys.writeFile("/a/b/alpha.tsconfig.json", JSON.stringify({
compilerOptions: { strict: true }
})),
timeouts: checkSingleTimeoutQueueLengthAndRun // Build project1
},
{
caption: "Build project 2",
change: noop,
timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
},
{
caption: "change bravo config",
change: sys => sys.writeFile("/a/b/bravo.tsconfig.json", JSON.stringify({
extends: "./alpha.tsconfig.json",
compilerOptions: { strict: false }
})),
timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
},
{
caption: "project 2 extends alpha",
change: sys => sys.writeFile("/a/b/project2.tsconfig.json", JSON.stringify({
extends: "./alpha.tsconfig.json",
})),
timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
},
{
caption: "update aplha config",
change: sys => sys.writeFile("/a/b/alpha.tsconfig.json", "{}"),
timeouts: checkSingleTimeoutQueueLengthAndRun, // build project1
},
{
caption: "Build project 2",
change: noop,
timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
},
]
});
verifyTscWatch({
scenario,
subScenario: "works correctly when project with extended config is removed",
commandLineArgs: ["-b", "-w", "-v"],
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: "/a/b/tsconfig.json",
content: JSON.stringify({
references: [
{
path: "./project1.tsconfig.json",
},
{
path: "./project2.tsconfig.json",
},
],
files: [],
})
};
return createWatchedSystem([
libFile, configFile,
alphaExtendedConfigFile, project1Config, commonFile1, commonFile2,
bravoExtendedConfigFile, project2Config, otherFile
], { currentDirectory: "/a/b" });
},
changes: [
{
caption: "Remove project2 from base config",
change: sys => sys.modifyFile("/a/b/tsconfig.json", JSON.stringify({
references: [
{
path: "./project1.tsconfig.json",
},
],
files: [],
})),
timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
}
]
});
});
describe("unittests:: tsbuild:: watchMode:: with demo project", () => {

View File

@ -1626,5 +1626,75 @@ import { x } from "../b";`),
},
]
});
verifyTscWatch({
scenario,
subScenario: "extended source files are watched",
commandLineArgs: ["-w", "-p", configFilePath],
sys: () => {
const firstExtendedConfigFile: File = {
path: "/a/b/first.tsconfig.json",
content: JSON.stringify({
compilerOptions: {
strict: true
}
})
};
const secondExtendedConfigFile: File = {
path: "/a/b/second.tsconfig.json",
content: JSON.stringify({
extends: "./first.tsconfig.json"
})
};
const configFile: File = {
path: configFilePath,
content: JSON.stringify({
compilerOptions: {},
files: [commonFile1.path, commonFile2.path]
})
};
return createWatchedSystem([
libFile, commonFile1, commonFile2, configFile, firstExtendedConfigFile, secondExtendedConfigFile
]);
},
changes: [
{
caption: "Change config to extend another config",
change: sys => sys.modifyFile(configFilePath, JSON.stringify({
extends: "./second.tsconfig.json",
compilerOptions: {},
files: [commonFile1.path, commonFile2.path]
})),
timeouts: checkSingleTimeoutQueueLengthAndRun,
},
{
caption: "Change first extended config",
change: sys => sys.modifyFile("/a/b/first.tsconfig.json", JSON.stringify({
compilerOptions: {
strict: false,
}
})),
timeouts: checkSingleTimeoutQueueLengthAndRun,
},
{
caption: "Change second extended config",
change: sys => sys.modifyFile("/a/b/second.tsconfig.json", JSON.stringify({
extends: "./first.tsconfig.json",
compilerOptions: {
strictNullChecks: true,
}
})),
timeouts: checkSingleTimeoutQueueLengthAndRun,
},
{
caption: "Change config to stop extending another config",
change: sys => sys.modifyFile(configFilePath, JSON.stringify({
compilerOptions: {},
files: [commonFile1.path, commonFile2.path]
})),
timeouts: checkSingleTimeoutQueueLengthAndRun,
},
]
});
});
}

View File

@ -1093,6 +1093,137 @@ foo();`
});
assert.equal(service.tryGetDefaultProjectForFile(server.toNormalizedPath(fooDts)), service.configuredProjects.get(barConfig.path));
});
describe("watches extended config files", () => {
function getService(additionalFiles?: File[]) {
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, ...(additionalFiles || emptyArray)]);
const projectService = createProjectService(host);
return { host, projectService, aFile, bFile, aConfig, bConfig, alphaExtendedConfig, bravoExtendedConfig };
}
it("should watch the extended configs of multiple projects", () => {
const { host, projectService, aFile, bFile, aConfig, bConfig, alphaExtendedConfig, bravoExtendedConfig } = getService();
projectService.openClientFile(aFile.path);
projectService.openClientFile(bFile.path);
checkNumberOfConfiguredProjects(projectService, 2);
const aProject = projectService.configuredProjects.get(aConfig.path)!;
const bProject = projectService.configuredProjects.get(bConfig.path)!;
checkProjectActualFiles(aProject, [aFile.path, aConfig.path, alphaExtendedConfig.path]);
checkProjectActualFiles(bProject, [bFile.path, bConfig.path, bravoExtendedConfig.path, alphaExtendedConfig.path]);
assert.isUndefined(aProject.getCompilerOptions().strict);
assert.isUndefined(bProject.getCompilerOptions().strict);
checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, bravoExtendedConfig.path, alphaExtendedConfig.path]);
host.writeFile(alphaExtendedConfig.path, JSON.stringify({
compilerOptions: {
strict: true
}
}));
assert.isTrue(projectService.hasPendingProjectUpdate(aProject));
assert.isTrue(projectService.hasPendingProjectUpdate(bProject));
host.checkTimeoutQueueLengthAndRun(3);
assert.isTrue(aProject.getCompilerOptions().strict);
assert.isTrue(bProject.getCompilerOptions().strict);
checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, bravoExtendedConfig.path, alphaExtendedConfig.path]);
host.writeFile(bravoExtendedConfig.path, JSON.stringify({
extends: "./alpha.tsconfig.json",
compilerOptions: {
strict: false
}
}));
assert.isFalse(projectService.hasPendingProjectUpdate(aProject));
assert.isTrue(projectService.hasPendingProjectUpdate(bProject));
host.checkTimeoutQueueLengthAndRun(2);
assert.isTrue(aProject.getCompilerOptions().strict);
assert.isFalse(bProject.getCompilerOptions().strict);
checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, bravoExtendedConfig.path, alphaExtendedConfig.path]);
host.writeFile(bConfig.path, JSON.stringify({
extends: "../extended/alpha.tsconfig.json",
}));
assert.isFalse(projectService.hasPendingProjectUpdate(aProject));
assert.isTrue(projectService.hasPendingProjectUpdate(bProject));
host.checkTimeoutQueueLengthAndRun(2);
assert.isTrue(aProject.getCompilerOptions().strict);
assert.isTrue(bProject.getCompilerOptions().strict);
checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, alphaExtendedConfig.path]);
host.writeFile(alphaExtendedConfig.path, "{}");
assert.isTrue(projectService.hasPendingProjectUpdate(aProject));
assert.isTrue(projectService.hasPendingProjectUpdate(bProject));
host.checkTimeoutQueueLengthAndRun(3);
assert.isUndefined(aProject.getCompilerOptions().strict);
assert.isUndefined(bProject.getCompilerOptions().strict);
checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, alphaExtendedConfig.path]);
});
it("should stop watching the extended configs of closed projects", () => {
const dummy: File = {
path: `${tscWatch.projectRoot}/dummy/dummy.ts`,
content: `let dummy = 1;`
};
const dummyConfig: File = {
path: `${tscWatch.projectRoot}/dummy/tsconfig.json`,
content: "{}"
};
const { host, projectService, aFile, bFile, aConfig, bConfig, alphaExtendedConfig, bravoExtendedConfig } = getService([dummy, dummyConfig]);
projectService.openClientFile(aFile.path);
projectService.openClientFile(bFile.path);
projectService.openClientFile(dummy.path);
checkNumberOfConfiguredProjects(projectService, 3);
checkWatchedFiles(host, [aConfig.path, bConfig.path, libFile.path, bravoExtendedConfig.path, alphaExtendedConfig.path, dummyConfig.path]);
projectService.closeClientFile(bFile.path);
projectService.closeClientFile(dummy.path);
projectService.openClientFile(dummy.path);
checkNumberOfConfiguredProjects(projectService, 2);
checkWatchedFiles(host, [aConfig.path, libFile.path, alphaExtendedConfig.path, dummyConfig.path]);
projectService.closeClientFile(aFile.path);
projectService.closeClientFile(dummy.path);
projectService.openClientFile(dummy.path);
checkNumberOfConfiguredProjects(projectService, 1);
checkWatchedFiles(host, [libFile.path, dummyConfig.path]);
});
});
});
describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories listed in config file input array", () => {

View File

@ -72,6 +72,26 @@ namespace ts.projectSystem {
verifyEvent(project, `Change in config file detected`);
});
it("when change is detected in an extended config file", () => {
const bTs: File = {
path: bTsPath,
content: "export class B {}"
};
const configB: File = {
path: configBPath,
content: JSON.stringify({
extends: "../a/tsconfig.json",
})
};
const { host, verifyEvent, verifyEventWithOpenTs, service } = createSessionToVerifyEvent(files.concat(bTs, configB));
verifyEventWithOpenTs(bTs, configB.path, 1);
host.writeFile(configA.path, configA.content);
host.checkTimeoutQueueLengthAndRun(2);
const project = service.configuredProjects.get(configB.path)!;
verifyEvent(project, `Change in extended config file ${configA.path} detected`);
});
describe("when opening original location project", () => {
it("with project references", () => {
verify();

View File

@ -241,6 +241,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:
@ -478,6 +480,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:

View File

@ -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:

View File

@ -0,0 +1,233 @@
Input::
//// [/a/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { 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 -v
Output::
>> Screen clear
[12:00:27 AM] Starting compilation in watch mode...
[12:00:28 AM] Projects in this build:
* project1.tsconfig.json
* project2.tsconfig.json
* tsconfig.json
[12:00:29 AM] Project 'project1.tsconfig.json' is out of date because output file 'commonFile1.js' does not exist
[12:00:30 AM] Building project '/a/b/project1.tsconfig.json'...
[12:00:41 AM] Project 'project2.tsconfig.json' is out of date because output file 'other.js' does not exist
[12:00:42 AM] Building project '/a/b/project2.tsconfig.json'...
[12:00:49 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-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
"signature": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { 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-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
"signature": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { 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:52 AM] File change detected. Starting incremental compilation...
[12:00:53 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

View File

@ -0,0 +1,557 @@
Input::
//// [/a/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
//// [/a/b/alpha.tsconfig.json]
{}
//// [/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]
{"extends":"./alpha.tsconfig.json"}
//// [/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 -v project1.tsconfig.json project2.tsconfig.json
Output::
>> Screen clear
[12:00:25 AM] Starting compilation in watch mode...
[12:00:26 AM] Projects in this build:
* project1.tsconfig.json
* project2.tsconfig.json
[12:00:27 AM] Project 'project1.tsconfig.json' is out of date because output file 'commonFile1.js' does not exist
[12:00:28 AM] Building project '/a/b/project1.tsconfig.json'...
[12:00:39 AM] Project 'project2.tsconfig.json' is out of date because output file 'other.js' does not exist
[12:00:40 AM] Building project '/a/b/project2.tsconfig.json'...
[12:00:47 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}
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-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
"signature": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { 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-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
"signature": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { 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:: Modify alpha config
Input::
//// [/a/b/alpha.tsconfig.json]
{"compilerOptions":{"strict":true}}
Output::
>> Screen clear
[12:00:51 AM] File change detected. Starting incremental compilation...
[12:00:52 AM] Project 'project1.tsconfig.json' is out of date because oldest output 'commonFile1.js' is older than newest input 'alpha.tsconfig.json'
[12:00:53 AM] Building project '/a/b/project1.tsconfig.json'...
[12:00:55 AM] Updating unchanged output timestamps of project '/a/b/project1.tsconfig.json'...
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"strict":true,"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
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}
FsWatches::
FsWatchesRecursive::
exitCode:: ExitStatus.undefined
//// [/a/b/commonFile1.js] file changed its modified time
//// [/a/b/commonFile1.d.ts] file changed its modified time
//// [/a/b/commonFile2.js] file changed its modified time
//// [/a/b/commonFile2.d.ts] file changed its modified time
//// [/a/b/project1.tsconfig.tsbuildinfo] file changed its modified time
Change:: Build project 2
Input::
Output::
[12:00:56 AM] Project 'project2.tsconfig.json' is out of date because oldest output 'other.js' is older than newest input 'alpha.tsconfig.json'
[12:00:57 AM] Building project '/a/b/project2.tsconfig.json'...
[12:00:59 AM] Updating unchanged output timestamps of project '/a/b/project2.tsconfig.json'...
[12:01:00 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/other.ts"]
Program options: {"strict":true,"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}
FsWatches::
FsWatchesRecursive::
exitCode:: ExitStatus.undefined
//// [/a/b/other.js] file changed its modified time
//// [/a/b/other.d.ts] file changed its modified time
//// [/a/b/project2.tsconfig.tsbuildinfo] file changed its modified time
Change:: change bravo config
Input::
//// [/a/b/bravo.tsconfig.json]
{"extends":"./alpha.tsconfig.json","compilerOptions":{"strict":false}}
Output::
>> Screen clear
[12:01:04 AM] File change detected. Starting incremental compilation...
[12:01:05 AM] Project 'project2.tsconfig.json' is out of date because oldest output 'other.js' is older than newest input 'bravo.tsconfig.json'
[12:01:06 AM] Building project '/a/b/project2.tsconfig.json'...
[12:01:08 AM] Updating unchanged output timestamps of project '/a/b/project2.tsconfig.json'...
[12:01:09 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/other.ts"]
Program options: {"strict":false,"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}
FsWatches::
FsWatchesRecursive::
exitCode:: ExitStatus.undefined
//// [/a/b/other.js] file changed its modified time
//// [/a/b/other.d.ts] file changed its modified time
//// [/a/b/project2.tsconfig.tsbuildinfo] file changed its modified time
Change:: project 2 extends alpha
Input::
//// [/a/b/project2.tsconfig.json]
{"extends":"./alpha.tsconfig.json"}
Output::
>> Screen clear
[12:01:13 AM] File change detected. Starting incremental compilation...
[12:01:14 AM] Project 'project2.tsconfig.json' is out of date because oldest output 'commonFile1.js' is older than newest input 'project2.tsconfig.json'
[12:01:15 AM] Building project '/a/b/project2.tsconfig.json'...
[12:01:25 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts","/a/b/other.ts"]
Program options: {"strict":true,"watch":true,"configFilePath":"/a/b/project2.tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.d.ts
/a/b/commonFile1.ts
/a/b/commonFile2.ts
/a/b/other.ts
Semantic diagnostics in builder refreshed for::
/a/lib/lib.d.ts
/a/b/commonFile1.ts
/a/b/commonFile2.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}
{"fileName":"/a/b/commonFile1.ts","pollingInterval":250}
/a/b/commonfile2.ts:
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
/a/b/project2.tsconfig.json:
{"fileName":"/a/b/project2.tsconfig.json","pollingInterval":250}
/a/b/other.ts:
{"fileName":"/a/b/other.ts","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b:
{"directoryName":"/a/b","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
//// [/a/b/commonFile1.js]
"use strict";
var x = 1;
//// [/a/b/commonFile2.js]
"use strict";
var y = 1;
//// [/a/b/other.js]
"use strict";
var z = 0;
Change:: update aplha config
Input::
//// [/a/b/alpha.tsconfig.json]
{}
Output::
>> Screen clear
[12:01:29 AM] File change detected. Starting incremental compilation...
[12:01:30 AM] Project 'project1.tsconfig.json' is out of date because oldest output 'commonFile1.d.ts' is older than newest input 'alpha.tsconfig.json'
[12:01:31 AM] Building project '/a/b/project1.tsconfig.json'...
[12:01:33 AM] Updating unchanged output timestamps of project '/a/b/project1.tsconfig.json'...
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
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}
{"fileName":"/a/b/commonFile1.ts","pollingInterval":250}
/a/b/commonfile2.ts:
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
/a/b/project2.tsconfig.json:
{"fileName":"/a/b/project2.tsconfig.json","pollingInterval":250}
/a/b/other.ts:
{"fileName":"/a/b/other.ts","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b:
{"directoryName":"/a/b","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
//// [/a/b/commonFile1.js] file changed its modified time
//// [/a/b/commonFile1.d.ts] file changed its modified time
//// [/a/b/commonFile2.js] file changed its modified time
//// [/a/b/commonFile2.d.ts] file changed its modified time
//// [/a/b/project1.tsconfig.tsbuildinfo] file changed its modified time
Change:: Build project 2
Input::
Output::
[12:01:34 AM] Project 'project2.tsconfig.json' is out of date because oldest output 'other.js' is older than newest input 'alpha.tsconfig.json'
[12:01:35 AM] Building project '/a/b/project2.tsconfig.json'...
[12:01:37 AM] Updating unchanged output timestamps of project '/a/b/project2.tsconfig.json'...
[12:01:38 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts","/a/b/other.ts"]
Program options: {"watch":true,"configFilePath":"/a/b/project2.tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.d.ts
/a/b/commonFile1.ts
/a/b/commonFile2.ts
/a/b/other.ts
Semantic diagnostics in builder refreshed for::
/a/lib/lib.d.ts
/a/b/commonFile1.ts
/a/b/commonFile2.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}
{"fileName":"/a/b/commonFile1.ts","pollingInterval":250}
/a/b/commonfile2.ts:
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
/a/b/project2.tsconfig.json:
{"fileName":"/a/b/project2.tsconfig.json","pollingInterval":250}
/a/b/other.ts:
{"fileName":"/a/b/other.ts","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b:
{"directoryName":"/a/b","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
//// [/a/b/commonFile1.js] file changed its modified time
//// [/a/b/commonFile2.js] file changed its modified time
//// [/a/b/other.js] file changed its modified time

View File

@ -0,0 +1,278 @@
Input::
//// [/a/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
//// [/a/b/commonFile1.ts]
let x = 1
//// [/a/b/commonFile2.ts]
let y = 1
//// [/a/b/tsconfig.json]
{"compilerOptions":{},"files":["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]}
//// [/a/b/first.tsconfig.json]
{"compilerOptions":{"strict":true}}
//// [/a/b/second.tsconfig.json]
{"extends":"./first.tsconfig.json"}
/a/lib/tsc.js -w -p /a/b/tsconfig.json
Output::
>> Screen clear
[12:00:21 AM] Starting compilation in watch mode...
[12:00:26 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/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
WatchedFiles::
/a/b/tsconfig.json:
{"fileName":"/a/b/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/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b/node_modules/@types:
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
//// [/a/b/commonFile1.js]
var x = 1;
//// [/a/b/commonFile2.js]
var y = 1;
Change:: Change config to extend another config
Input::
//// [/a/b/tsconfig.json]
{"extends":"./second.tsconfig.json","compilerOptions":{},"files":["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]}
Output::
>> Screen clear
[12:00:29 AM] File change detected. Starting incremental compilation...
[12:00:30 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"strict":true,"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
Program structureReused: Completely
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
WatchedFiles::
/a/b/tsconfig.json:
{"fileName":"/a/b/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/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
/a/b/second.tsconfig.json:
{"fileName":"/a/b/second.tsconfig.json","pollingInterval":250}
/a/b/first.tsconfig.json:
{"fileName":"/a/b/first.tsconfig.json","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b/node_modules/@types:
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
Change:: Change first extended config
Input::
//// [/a/b/first.tsconfig.json]
{"compilerOptions":{"strict":false}}
Output::
>> Screen clear
[12:00:33 AM] File change detected. Starting incremental compilation...
[12:00:34 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"strict":false,"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
Program structureReused: Completely
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
WatchedFiles::
/a/b/tsconfig.json:
{"fileName":"/a/b/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/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
/a/b/second.tsconfig.json:
{"fileName":"/a/b/second.tsconfig.json","pollingInterval":250}
/a/b/first.tsconfig.json:
{"fileName":"/a/b/first.tsconfig.json","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b/node_modules/@types:
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
Change:: Change second extended config
Input::
//// [/a/b/second.tsconfig.json]
{"extends":"./first.tsconfig.json","compilerOptions":{"strictNullChecks":true}}
Output::
>> Screen clear
[12:00:37 AM] File change detected. Starting incremental compilation...
[12:00:38 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"strict":false,"strictNullChecks":true,"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
Program structureReused: Completely
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
WatchedFiles::
/a/b/tsconfig.json:
{"fileName":"/a/b/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/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
/a/b/second.tsconfig.json:
{"fileName":"/a/b/second.tsconfig.json","pollingInterval":250}
/a/b/first.tsconfig.json:
{"fileName":"/a/b/first.tsconfig.json","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b/node_modules/@types:
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined
Change:: Change config to stop extending another config
Input::
//// [/a/b/tsconfig.json]
{"compilerOptions":{},"files":["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]}
Output::
>> Screen clear
[12:00:41 AM] File change detected. Starting incremental compilation...
[12:00:42 AM] Found 0 errors. Watching for file changes.
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
Program structureReused: Completely
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
WatchedFiles::
/a/b/tsconfig.json:
{"fileName":"/a/b/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/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
FsWatches::
FsWatchesRecursive::
/a/b/node_modules/@types:
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
exitCode:: ExitStatus.undefined