mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #26717 from Microsoft/buildWatchReporting30
[release-3.0] Refactor ts build and report watch status when doing --build --watch
This commit is contained in:
@@ -797,10 +797,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getOptionNameMap(): OptionNameMap {
|
||||
if (optionNameMapCache) {
|
||||
return optionNameMapCache;
|
||||
}
|
||||
return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations));
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function createOptionNameMap(optionDeclarations: ReadonlyArray<CommandLineOption>): OptionNameMap {
|
||||
const optionNameMap = createMap<CommandLineOption>();
|
||||
const shortOptionNames = createMap<string>();
|
||||
forEach(optionDeclarations, option => {
|
||||
@@ -810,8 +811,7 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
optionNameMapCache = { optionNameMap, shortOptionNames };
|
||||
return optionNameMapCache;
|
||||
return { optionNameMap, shortOptionNames };
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -961,7 +961,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
|
||||
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
|
||||
@@ -2872,6 +2872,11 @@
|
||||
"category": "Error",
|
||||
"code": 5071
|
||||
},
|
||||
"Unknown build option '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
|
||||
+27
-25
@@ -67,19 +67,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
|
||||
return createCompilerHostWorker(options, setParentNodes);
|
||||
}
|
||||
/*@internal*/
|
||||
// TODO(shkamat): update this after reworking ts build API
|
||||
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
|
||||
const existingDirectories = createMap<boolean>();
|
||||
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
|
||||
let text: string | undefined;
|
||||
try {
|
||||
performance.mark("beforeIORead");
|
||||
text = sys.readFile(fileName, options.charset);
|
||||
text = system.readFile(fileName, options.charset);
|
||||
performance.mark("afterIORead");
|
||||
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
||||
}
|
||||
@@ -97,7 +102,7 @@ namespace ts {
|
||||
if (existingDirectories.has(directoryPath)) {
|
||||
return true;
|
||||
}
|
||||
if (sys.directoryExists(directoryPath)) {
|
||||
if (system.directoryExists(directoryPath)) {
|
||||
existingDirectories.set(directoryPath, true);
|
||||
return true;
|
||||
}
|
||||
@@ -108,7 +113,7 @@ namespace ts {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||
const parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
sys.createDirectory(directoryPath);
|
||||
system.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +124,8 @@ namespace ts {
|
||||
outputFingerprints = createMap<OutputFingerprint>();
|
||||
}
|
||||
|
||||
const hash = sys.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
const hash = system.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
|
||||
if (mtimeBefore) {
|
||||
const fingerprint = outputFingerprints.get(fileName);
|
||||
@@ -133,9 +138,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
|
||||
const mtimeAfter = sys.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
|
||||
outputFingerprints.set(fileName, {
|
||||
hash,
|
||||
@@ -149,11 +154,11 @@ namespace ts {
|
||||
performance.mark("beforeIOWrite");
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
|
||||
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
|
||||
writeFileIfUpdated(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
else {
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
|
||||
performance.mark("afterIOWrite");
|
||||
@@ -167,32 +172,29 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getDefaultLibLocation(): string {
|
||||
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
|
||||
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
|
||||
}
|
||||
|
||||
const newLine = getNewLineCharacter(options);
|
||||
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
|
||||
const newLine = getNewLineCharacter(options, () => system.newLine);
|
||||
const realpath = system.realpath && ((path: string) => system.realpath!(path));
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
getDefaultLibLocation,
|
||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||
writeFile,
|
||||
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
trace: (s: string) => sys.write(s + newLine),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => sys.getDirectories(path),
|
||||
fileExists: fileName => system.fileExists(fileName),
|
||||
readFile: fileName => system.readFile(fileName),
|
||||
trace: (s: string) => system.write(s + newLine),
|
||||
directoryExists: directoryName => system.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => system.getDirectories(path),
|
||||
realpath,
|
||||
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
|
||||
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
|
||||
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
|
||||
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
|
||||
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+401
-403
File diff suppressed because it is too large
Load Diff
@@ -4681,16 +4681,6 @@ namespace ts {
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface UpToDateHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
getModifiedTime(fileName: string): Date;
|
||||
getUnchangedTime?(fileName: string): Date | undefined;
|
||||
getLastStatus?(fileName: string): UpToDateStatus | undefined;
|
||||
setLastStatus?(fileName: string, status: UpToDateStatus): void;
|
||||
parseConfigFile?(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined;
|
||||
}
|
||||
|
||||
export interface ModuleResolutionHost {
|
||||
// TODO: GH#18217 Optional methods frequently used as non-optional
|
||||
|
||||
@@ -4821,10 +4811,6 @@ namespace ts {
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
createHash?(data: string): string;
|
||||
|
||||
getModifiedTime?(fileName: string): Date;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
+34
-26
@@ -27,12 +27,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const nonClearingMessageCodes: number[] = [
|
||||
Diagnostics.Found_1_error_Watching_for_file_changes.code,
|
||||
Diagnostics.Found_0_errors_Watching_for_file_changes.code
|
||||
];
|
||||
|
||||
/**
|
||||
* @returns Whether the screen was cleared.
|
||||
*/
|
||||
@@ -41,7 +35,7 @@ namespace ts {
|
||||
!options.preserveWatchOutput &&
|
||||
!options.extendedDiagnostics &&
|
||||
!options.diagnostics &&
|
||||
!contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
system.clearScreen();
|
||||
return true;
|
||||
}
|
||||
@@ -174,6 +168,17 @@ namespace ts {
|
||||
|
||||
const noopFileWatcher: FileWatcher = { close: noop };
|
||||
|
||||
export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusReporter): WatchHost {
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
return {
|
||||
onWatchStatusChange,
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the watch compiler host that can be extended with config file or root file names and options host
|
||||
*/
|
||||
@@ -185,7 +190,7 @@ namespace ts {
|
||||
let host: DirectoryStructureHost = system;
|
||||
const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames;
|
||||
const writeFileName = (s: string) => system.write(s + system.newLine);
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
const { onWatchStatusChange, watchFile, watchDirectory, setTimeout, clearTimeout } = createWatchHost(system, reportWatchStatus);
|
||||
return {
|
||||
useCaseSensitiveFileNames,
|
||||
getNewLine: () => system.newLine,
|
||||
@@ -199,10 +204,10 @@ namespace ts {
|
||||
readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth),
|
||||
realpath: system.realpath && (path => system.realpath!(path)),
|
||||
getEnvironmentVariable: system.getEnvironmentVariable && (name => system.getEnvironmentVariable(name)),
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop,
|
||||
watchFile,
|
||||
watchDirectory,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
trace: s => system.write(s),
|
||||
onWatchStatusChange,
|
||||
createDirectory: path => system.createDirectory(path),
|
||||
@@ -223,10 +228,10 @@ namespace ts {
|
||||
|
||||
const reportSummary = (errorCount: number) => {
|
||||
if (errorCount === 1) {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
else {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -269,7 +274,21 @@ namespace ts {
|
||||
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
export interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
// TODO: GH#18217 Optional methods are frequently asserted
|
||||
|
||||
/**
|
||||
@@ -278,8 +297,6 @@ namespace ts {
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
// Only for testing
|
||||
/*@internal*/
|
||||
@@ -322,15 +339,6 @@ namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
|
||||
/** Internal interface used to wire emit through same host */
|
||||
|
||||
@@ -374,5 +374,41 @@ namespace fakes {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost {
|
||||
diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
reportDiagnostic(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
reportSolutionBuilderStatus(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
clearDiagnostics() {
|
||||
this.diagnostics.length = 0;
|
||||
}
|
||||
|
||||
assertDiagnosticMessages(...expected: ts.DiagnosticMessage[]) {
|
||||
const actual = this.diagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = ts.createDiagnosticReporter(ts.sys);
|
||||
ts.sys.write(header + "\r\n");
|
||||
for (const d of this.diagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -617,14 +617,14 @@ interface Array<T> {}`
|
||||
}
|
||||
}
|
||||
|
||||
removeFile(filePath: string) {
|
||||
deleteFile(filePath: string) {
|
||||
const path = this.toFullPath(filePath);
|
||||
const currentEntry = this.fs.get(path) as FsFile;
|
||||
Debug.assert(isFsFile(currentEntry));
|
||||
this.removeFileOrFolder(currentEntry, returnFalse);
|
||||
}
|
||||
|
||||
removeFolder(folderPath: string, recursive?: boolean) {
|
||||
deleteFolder(folderPath: string, recursive?: boolean) {
|
||||
const path = this.toFullPath(folderPath);
|
||||
const currentEntry = this.fs.get(path) as FsFolder;
|
||||
Debug.assert(isFsFolder(currentEntry));
|
||||
@@ -632,7 +632,7 @@ interface Array<T> {}`
|
||||
const subEntries = currentEntry.entries.slice();
|
||||
subEntries.forEach(fsEntry => {
|
||||
if (isFsFolder(fsEntry)) {
|
||||
this.removeFolder(fsEntry.fullPath, recursive);
|
||||
this.deleteFolder(fsEntry.fullPath, recursive);
|
||||
}
|
||||
else {
|
||||
this.removeFileOrFolder(fsEntry, returnFalse);
|
||||
@@ -763,6 +763,14 @@ interface Array<T> {}`
|
||||
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
setModifiedTime(s: string, date: Date) {
|
||||
const path = this.toFullPath(s);
|
||||
const fsEntry = this.fs.get(path);
|
||||
if (fsEntry) {
|
||||
fsEntry.modifiedTime = date;
|
||||
}
|
||||
}
|
||||
|
||||
readFile(s: string): string | undefined {
|
||||
const fsEntry = this.getRealFile(this.toFullPath(s));
|
||||
return fsEntry ? fsEntry.content : undefined;
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"unittests/transform.ts",
|
||||
"unittests/transpile.ts",
|
||||
"unittests/tsbuild.ts",
|
||||
"unittests/tsbuildWatchMode.ts",
|
||||
"unittests/tsconfigParsing.ts",
|
||||
"unittests/tscWatchMode.ts",
|
||||
"unittests/versionCache.ts",
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
namespace ts {
|
||||
let currentTime = 100;
|
||||
let lastDiagnostics: Diagnostic[] = [];
|
||||
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiagnostic(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiagnostic(d)
|
||||
};
|
||||
|
||||
export namespace Sample1 {
|
||||
tick();
|
||||
const projFs = loadProjectFromDisk("tests/projects/sample1");
|
||||
@@ -21,12 +11,12 @@ namespace ts {
|
||||
describe("tsbuild - sanity check of clean build of 'sample1' project", () => {
|
||||
it("can build the sample project 'sample1' without error", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -37,12 +27,11 @@ namespace ts {
|
||||
|
||||
describe("tsbuild - dry builds", () => {
|
||||
it("doesn't write any files in a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
host.assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
|
||||
// Check for outputs to not be written. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -51,28 +40,26 @@ namespace ts {
|
||||
});
|
||||
|
||||
it("indicates that it would skip builds during a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
let builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
let builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
tick();
|
||||
|
||||
clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
host.assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - clean builds", () => {
|
||||
it("removes all files it built", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
// Verify they exist
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -91,9 +78,9 @@ namespace ts {
|
||||
describe("tsbuild - force builds", () => {
|
||||
it("always builds under --force", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
let currentTime = time();
|
||||
checkOutputTimestamps(currentTime);
|
||||
@@ -116,14 +103,14 @@ namespace ts {
|
||||
|
||||
describe("tsbuild - can detect when and what to rebuild", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
it("Builds the project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
@@ -135,10 +122,10 @@ namespace ts {
|
||||
|
||||
// All three projects are up to date
|
||||
it("Detects that all projects are up to date", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
|
||||
@@ -147,12 +134,12 @@ namespace ts {
|
||||
|
||||
// Update a file in the leaf node (tests), only it should rebuild the last one
|
||||
it("Only builds the leaf node project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
fs.writeFileSync("/src/tests/index.ts", "const m = 10;");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
@@ -162,12 +149,12 @@ namespace ts {
|
||||
|
||||
// Update a file in the parent (without affecting types), should get fast downstream builds
|
||||
it("Detects type-only changes in upstream projects", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies,
|
||||
@@ -180,15 +167,13 @@ namespace ts {
|
||||
describe("tsbuild - downstream-blocked compilations", () => {
|
||||
it("won't build downstream projects if upstream projects have errors", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
// Induce an error in the middle project
|
||||
replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`);
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(
|
||||
host.assertDiagnosticMessages(
|
||||
Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
@@ -204,12 +189,11 @@ namespace ts {
|
||||
describe("tsbuild - project invalidation", () => {
|
||||
it("invalidates projects correctly", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Update a timestamp in the middle project
|
||||
tick();
|
||||
@@ -221,14 +205,14 @@ namespace ts {
|
||||
// Rebuild this project
|
||||
tick();
|
||||
builder.invalidateProject("/src/logic");
|
||||
builder.buildInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
// The file should be updated
|
||||
assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should *not* have been rebuilt");
|
||||
|
||||
// Build downstream projects should update 'tests', but not 'core'
|
||||
tick();
|
||||
builder.buildDependentInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.equal(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/core/index.js").mtimeMs, time(), "Upstream JS file should not have been rebuilt");
|
||||
});
|
||||
@@ -240,11 +224,10 @@ namespace ts {
|
||||
|
||||
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, [configFile], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
host.assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
if (!expectedDiagnosticMessages.length) {
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -274,11 +257,11 @@ namespace ts {
|
||||
let fs: vfs.FileSystem | undefined;
|
||||
before(() => {
|
||||
fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
});
|
||||
after(() => {
|
||||
fs = undefined;
|
||||
@@ -295,25 +278,24 @@ namespace ts {
|
||||
describe("tsbuild - downstream prepend projects always get rebuilt", () => {
|
||||
it("", () => {
|
||||
const fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "First build timestamp is correct");
|
||||
tick();
|
||||
replaceText(fs, "src/first/first_PART1.ts", "Hello", "Hola");
|
||||
tick();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "Second build timestamp is correct");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("tsbuild - graph-ordering", () => {
|
||||
let host: fakes.CompilerHost | undefined;
|
||||
let host: fakes.SolutionBuilderHost | undefined;
|
||||
const deps: [string, string][] = [
|
||||
["A", "B"],
|
||||
["B", "C"],
|
||||
@@ -326,7 +308,7 @@ namespace ts {
|
||||
|
||||
before(() => {
|
||||
const fs = new vfs.FileSystem(false);
|
||||
host = new fakes.CompilerHost(fs);
|
||||
host = new fakes.SolutionBuilderHost(fs);
|
||||
writeProjects(fs, ["A", "B", "C", "D", "E", "F", "G"], deps);
|
||||
});
|
||||
|
||||
@@ -351,7 +333,7 @@ namespace ts {
|
||||
});
|
||||
|
||||
function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[]) {
|
||||
const builder = createSolutionBuilder(host!, buildHost, rootNames, { dry: true, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host!, rootNames, { dry: true, force: false, verbose: false });
|
||||
|
||||
const projFileNames = rootNames.map(getProjectFileName);
|
||||
const graph = builder.getBuildGraph(projFileNames);
|
||||
@@ -406,30 +388,6 @@ namespace ts {
|
||||
fs.writeFileSync(path, newContent, "utf-8");
|
||||
}
|
||||
|
||||
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
|
||||
const actual = lastDiagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearDiagnostics() {
|
||||
lastDiagnostics = [];
|
||||
}
|
||||
|
||||
export function printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = createDiagnosticReporter(sys);
|
||||
sys.write(header + "\r\n");
|
||||
for (const d of lastDiagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
|
||||
function tick() {
|
||||
currentTime += 60_000;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions);
|
||||
solutionBuilder.buildAllProjects();
|
||||
solutionBuilder.startWatching();
|
||||
return solutionBuilder;
|
||||
}
|
||||
|
||||
describe("tsbuild-watch program updates", () => {
|
||||
const projectsLocation = "/user/username/projects";
|
||||
const project = "sample1";
|
||||
const enum SubProject {
|
||||
core = "core",
|
||||
logic = "logic",
|
||||
tests = "tests",
|
||||
ui = "ui"
|
||||
}
|
||||
type ReadonlyFile = Readonly<File>;
|
||||
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
return {
|
||||
path: projectFilePath(subProject, baseFileName),
|
||||
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${subProject}/${baseFileName}`)!
|
||||
};
|
||||
}
|
||||
|
||||
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
|
||||
const tsconfig = projectFile(subProject, "tsconfig.json");
|
||||
const index = projectFile(subProject, "index.ts");
|
||||
if (!anotherModuleAndSomeDecl) {
|
||||
return [tsconfig, index];
|
||||
}
|
||||
const anotherModule = projectFile(SubProject.core, "anotherModule.ts");
|
||||
const someDecl = projectFile(SubProject.core, "some_decl.ts");
|
||||
return [tsconfig, index, anotherModule, someDecl];
|
||||
}
|
||||
|
||||
function getOutputFileNames(subProject: SubProject, baseFileNameWithoutExtension: string) {
|
||||
const file = projectFilePath(subProject, baseFileNameWithoutExtension);
|
||||
return [`${file}.js`, `${file}.d.ts`];
|
||||
}
|
||||
|
||||
type OutputFileStamp = [string, Date | undefined];
|
||||
function getOutputStamps(host: WatchedSystem, subProject: SubProject, baseFileNameWithoutExtension: string): OutputFileStamp[] {
|
||||
return getOutputFileNames(subProject, baseFileNameWithoutExtension).map(f => [f, host.getModifiedTime(f)] as OutputFileStamp);
|
||||
}
|
||||
|
||||
function getOutputFileStamps(host: WatchedSystem): OutputFileStamp[] {
|
||||
return [
|
||||
...getOutputStamps(host, SubProject.core, "anotherModule"),
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
...getOutputStamps(host, SubProject.tests, "index"),
|
||||
];
|
||||
}
|
||||
|
||||
function verifyChangedFiles(actualStamps: OutputFileStamp[], oldTimeStamps: OutputFileStamp[], changedFiles: string[]) {
|
||||
for (let i = 0; i < oldTimeStamps.length; i++) {
|
||||
const actual = actualStamps[i];
|
||||
const old = oldTimeStamps[i];
|
||||
if (contains(changedFiles, actual[0])) {
|
||||
assert.isTrue((actual[1] || 0) > (old[1] || 0), `${actual[0]} expected to written`);
|
||||
}
|
||||
else {
|
||||
assert.equal(actual[1], old[1], `${actual[0]} expected to not change`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
|
||||
const logic = subProjectFiles(SubProject.logic);
|
||||
const tests = subProjectFiles(SubProject.tests);
|
||||
const ui = subProjectFiles(SubProject.ui);
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
|
||||
function createSolutionInWatchMode() {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return { host, outputFileStamps };
|
||||
}
|
||||
it("creates solution in watch mode", () => {
|
||||
createSolutionInWatchMode();
|
||||
});
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const { host, outputFileStamps } = createSolutionInWatchMode();
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
export class someClass { }`);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedCore, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, changedTests, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
namespace ts.tscWatch {
|
||||
import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
type File = TestFSWithWatch.File;
|
||||
type SymLink = TestFSWithWatch.SymLink;
|
||||
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
import checkArray = TestFSWithWatch.checkArray;
|
||||
import libFile = TestFSWithWatch.libFile;
|
||||
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
export import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
export type File = TestFSWithWatch.File;
|
||||
export type SymLink = TestFSWithWatch.SymLink;
|
||||
export import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
export import checkArray = TestFSWithWatch.checkArray;
|
||||
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
export import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
export import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
export import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
export import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
|
||||
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
|
||||
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
|
||||
@@ -111,7 +110,7 @@ namespace ts.tscWatch {
|
||||
|
||||
function assertWatchDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = getWatchDiagnosticWithoutDate(diagnostic);
|
||||
if (!disableConsoleClears && !contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
if (!disableConsoleClears && contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
assert.equal(host.screenClears[screenClears], index, `Expected screen clear at this diagnostic: ${expected}`);
|
||||
screenClears++;
|
||||
}
|
||||
@@ -137,7 +136,7 @@ namespace ts.tscWatch {
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
@@ -148,7 +147,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
||||
@@ -8074,7 +8074,7 @@ new C();`
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
|
||||
host.removeFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
@@ -8906,7 +8906,7 @@ describe("Test Suite 1", () => {
|
||||
checkProjectActualFiles(project, expectedFilesWithUnitTest1);
|
||||
|
||||
const navBarResultUnitTest1 = navBarFull(session, unitTest1);
|
||||
host.removeFile(unitTest1.path);
|
||||
host.deleteFile(unitTest1.path);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(project, expectedFilesWithoutUnitTest1);
|
||||
|
||||
@@ -9011,7 +9011,7 @@ export function Test2() {
|
||||
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
|
||||
|
||||
// Testing what happens if we delete the original sources.
|
||||
host.removeFile(bTs.path);
|
||||
host.deleteFile(bTs.path);
|
||||
|
||||
openFilesForSession([userTs], session);
|
||||
|
||||
|
||||
+145
-13
@@ -13,7 +13,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
let reportDiagnostic = createDiagnosticReporter(sys);
|
||||
function updateReportDiagnostic(options: CompilerOptions) {
|
||||
function updateReportDiagnostic(options?: CompilerOptions) {
|
||||
if (shouldBePretty(options)) {
|
||||
reportDiagnostic = createDiagnosticReporter(sys, /*pretty*/ true);
|
||||
}
|
||||
@@ -23,8 +23,8 @@ namespace ts {
|
||||
return !!sys.writeOutputIsTTY && sys.writeOutputIsTTY();
|
||||
}
|
||||
|
||||
function shouldBePretty(options: CompilerOptions) {
|
||||
if (typeof options.pretty === "undefined") {
|
||||
function shouldBePretty(options?: CompilerOptions) {
|
||||
if (!options || typeof options.pretty === "undefined") {
|
||||
return defaultIsPretty();
|
||||
}
|
||||
return options.pretty;
|
||||
@@ -54,15 +54,7 @@ namespace ts {
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const reportDiag = createDiagnosticReporter(sys, defaultIsPretty());
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiag(d)
|
||||
};
|
||||
const result = performBuild(args.slice(1), createCompilerHost({}), buildHost, sys);
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
@@ -172,6 +164,146 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
const buildOpts: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Print_this_message,
|
||||
},
|
||||
{
|
||||
name: "help",
|
||||
shortName: "?",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "verbose",
|
||||
shortName: "v",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Enable_verbose_logging,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "dry",
|
||||
shortName: "d",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "force",
|
||||
shortName: "f",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "clean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Delete_the_outputs_of_all_projects,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Watch_input_files,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "preserveWatchOutput",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
];
|
||||
let buildOptionNameMap: OptionNameMap | undefined;
|
||||
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
|
||||
|
||||
const buildOptions: BuildOptions = {};
|
||||
const projects: string[] = [];
|
||||
for (const arg of args) {
|
||||
if (arg.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
buildOptions[opt.name as keyof BuildOptions] = true;
|
||||
}
|
||||
else {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a flag, parse as filename
|
||||
addProject(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
// Update to pretty if host supports it
|
||||
updateReportDiagnostic();
|
||||
|
||||
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
}
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.verbose) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.watch) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch && buildOptions.dry) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
addProject(".");
|
||||
}
|
||||
|
||||
// TODO: change this to host if watch => watchHost otherwiue without wathc
|
||||
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
|
||||
if (buildOptions.clean) {
|
||||
return builder.cleanAllProjects();
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
|
||||
function addProject(projectSpecification: string) {
|
||||
const fileName = resolvePath(sys.getCurrentDirectory(), projectSpecification);
|
||||
const refPath = resolveProjectReferencePath(sys, { path: fileName });
|
||||
if (!sys.fileExists(refPath)) {
|
||||
return reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
}
|
||||
projects.push(refPath);
|
||||
}
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
const host = createCompilerHost(options);
|
||||
enableStatistics(options);
|
||||
@@ -205,7 +337,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createWatchStatusReporter(options: CompilerOptions) {
|
||||
function createWatchStatusReporter(options?: CompilerOptions) {
|
||||
return ts.createWatchStatusReporter(sys, shouldBePretty(options));
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -2677,9 +2677,6 @@ declare namespace ts {
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
@@ -4295,15 +4292,26 @@ declare namespace ts {
|
||||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
@@ -4336,14 +4344,6 @@ declare namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
|
||||
+14
-14
@@ -2677,9 +2677,6 @@ declare namespace ts {
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
@@ -4295,15 +4292,26 @@ declare namespace ts {
|
||||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
@@ -4336,14 +4344,6 @@ declare namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
|
||||
Reference in New Issue
Block a user