From 66c690d40102c9a4b98d85b72ab4ac3467a19da4 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Sat, 10 Mar 2018 07:13:42 -0800 Subject: [PATCH 1/2] Better test to see when console clearing happens --- src/harness/unittests/tscWatchMode.ts | 74 +++++++++++++++-------- src/harness/virtualFileSystemWithWatch.ts | 9 +-- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 47116cd5b01..b10c73d4a06 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -72,22 +72,31 @@ namespace ts.tscWatch { checkOutputDoesNotContain(host, expectedNonAffectedFiles); } + const elapsedRegex = /^Elapsed:: [0-9]+ms/; function checkOutputErrors( host: WatchedSystem, + logsBeforeWatchDiagnostic: string[] | undefined, preErrorsWatchDiagnostic: DiagnosticMessage | undefined, + logsBeforeErrors: string[] | undefined, errors: ReadonlyArray, + disableConsoleClears?: boolean | undefined, ...postErrorsWatchDiagnostics: DiagnosticMessage[] ) { + let screenClears = 0; const outputs = host.getOutput(); - const expectedOutputCount = (preErrorsWatchDiagnostic ? 1 : 0) + errors.length + postErrorsWatchDiagnostics.length; - assert.equal(outputs.length, expectedOutputCount); + const expectedOutputCount = (preErrorsWatchDiagnostic ? 1 : 0) + errors.length + postErrorsWatchDiagnostics.length + + (logsBeforeWatchDiagnostic ? logsBeforeWatchDiagnostic.length : 0) + (logsBeforeErrors ? logsBeforeErrors.length : 0); + assert.equal(outputs.length, expectedOutputCount, JSON.stringify(outputs)); let index = 0; + forEach(logsBeforeWatchDiagnostic, log => assertLog("logsBeforeWatchDiagnostic", log)); if (preErrorsWatchDiagnostic) { assertWatchDiagnostic(preErrorsWatchDiagnostic); } + forEach(logsBeforeErrors, log => assertLog("logBeforeError", log)); // Verify errors forEach(errors, assertDiagnostic); forEach(postErrorsWatchDiagnostics, assertWatchDiagnostic); + assert.equal(host.screenClears.length, screenClears, "Expected number of screen clears"); host.clearOutput(); function assertDiagnostic(diagnostic: Diagnostic) { @@ -96,8 +105,18 @@ namespace ts.tscWatch { index++; } + function assertLog(caption: string, expected: string) { + const actual = outputs[index]; + assert.equal(actual.replace(elapsedRegex, ""), expected.replace(elapsedRegex, ""), getOutputAtFailedMessage(caption, expected)); + index++; + } + function assertWatchDiagnostic(diagnosticMessage: DiagnosticMessage) { const expected = getWatchDiagnosticWithoutDate(diagnosticMessage); + if (!disableConsoleClears && diagnosticMessage.code !== Diagnostics.Compilation_complete_Watching_for_file_changes.code) { + assert.equal(host.screenClears[screenClears], index, `Expected screen clear at this diagnostic: ${expected}`); + screenClears++; + } assert.isTrue(endsWith(outputs[index], expected), getOutputAtFailedMessage("Watch diagnostic", expected)); index++; } @@ -111,20 +130,20 @@ namespace ts.tscWatch { } } - function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray) { - checkOutputErrors(host, Diagnostics.Starting_compilation_in_watch_mode, errors, Diagnostics.Compilation_complete_Watching_for_file_changes); + function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { + checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.Starting_compilation_in_watch_mode, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); } function checkOutputErrorsInitialWithConfigErrors(host: WatchedSystem, errors: ReadonlyArray) { - checkOutputErrors(host, /*preErrorsWatchDiagnostic*/ undefined, errors, Diagnostics.Starting_compilation_in_watch_mode, Diagnostics.Compilation_complete_Watching_for_file_changes); + checkOutputErrors(host, /*logsBeforeWatchDiagnostic*/ undefined, /*preErrorsWatchDiagnostic*/ undefined, /*logsBeforeErrors*/ undefined, errors, /*disableConsoleClears*/ undefined, Diagnostics.Starting_compilation_in_watch_mode, Diagnostics.Compilation_complete_Watching_for_file_changes); } - function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray) { - checkOutputErrors(host, Diagnostics.File_change_detected_Starting_incremental_compilation, errors, Diagnostics.Compilation_complete_Watching_for_file_changes); + function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { + checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.File_change_detected_Starting_incremental_compilation, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); } function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray, expectedExitCode: ExitStatus) { - checkOutputErrors(host, Diagnostics.File_change_detected_Starting_incremental_compilation, errors); + checkOutputErrors(host, /*logsBeforeWatchDiagnostic*/ undefined, Diagnostics.File_change_detected_Starting_incremental_compilation, /*logsBeforeErrors*/ undefined, errors, /*disableConsoleClears*/ undefined); assert.equal(host.exitCode, expectedExitCode); } @@ -2161,30 +2180,33 @@ declare module "fs" { path: "f.ts", content: "" }; - const files = [file]; + const files = [file, libFile]; + const disableConsoleClear = options.diagnostics || options.extendedDiagnostics || options.preserveWatchOutput; const host = createWatchedSystem(files); - let clearCount: number | undefined; - checkConsoleClears(); - createWatchOfFilesAndCompilerOptions([file.path], host, options); - checkConsoleClears(); + checkOutputErrorsInitial(host, emptyArray, disableConsoleClear, options.extendedDiagnostics && [ + "Current directory: / CaseSensitiveFileNames: false\n" + ], options.extendedDiagnostics && [ + "Synchronizing program\n", + "CreatingProgramWith::\n", + " roots: [\"f.ts\"]\n", + " options: {\"extendedDiagnostics\":true}\n", + "FileWatcher:: Added:: WatchInfo: f.ts 250 \n", + "FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 250 \n" + ]); file.content = "//"; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); - - checkConsoleClears(); - - function checkConsoleClears() { - if (clearCount === undefined || options.preserveWatchOutput) { - clearCount = 0; - } - else if (!options.diagnostics && !options.extendedDiagnostics) { - clearCount++; - } - host.checkScreenClears(clearCount); - return clearCount; - } + checkOutputErrorsIncremental(host, emptyArray, disableConsoleClear, options.extendedDiagnostics && [ + "FileWatcher:: Triggered with /f.ts1:: WatchInfo: f.ts 250 \n", + "Elapsed:: 0ms FileWatcher:: Triggered with /f.ts1:: WatchInfo: f.ts 250 \n" + ], options.extendedDiagnostics && [ + "Synchronizing program\n", + "CreatingProgramWith::\n", + " roots: [\"f.ts\"]\n", + " options: {\"extendedDiagnostics\":true}\n" + ]); } it("without --diagnostics or --extendedDiagnostics", () => { diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 8b62c210abb..e74eed39afe 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -288,7 +288,7 @@ interface Array {}` private toPath: (f: string) => Path; private timeoutCallbacks = new Callbacks(); private immediateCallbacks = new Callbacks(); - private screenClears = 0; + readonly screenClears: number[] = []; readonly watchedDirectories = createMultiMap(); readonly watchedDirectoriesRecursive = createMultiMap(); @@ -762,7 +762,7 @@ interface Array {}` } clearScreen(): void { - this.screenClears += 1; + this.screenClears.push(this.output.length); } checkTimeoutQueueLengthAndRun(expected: number) { @@ -802,10 +802,6 @@ interface Array {}` this.immediateCallbacks.unregister(timeoutId); } - checkScreenClears(expected: number): void { - assert.equal(this.screenClears, expected); - } - createDirectory(directoryName: string): void { const folder = this.toFolder(directoryName); @@ -839,6 +835,7 @@ interface Array {}` clearOutput() { clear(this.output); + this.screenClears.length = 0; } realpath(s: string): string { From 7329eb1ab1c007c947683e7b432725a912799f3a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 15 Mar 2018 14:32:01 -0700 Subject: [PATCH 2/2] Make sure config file parsing errors are available through program Fixes #22570, #21940 --- src/compiler/builder.ts | 53 +++++++---- src/compiler/program.ts | 17 +++- src/compiler/tsc.ts | 11 +-- src/compiler/types.ts | 1 + src/compiler/watch.ts | 92 +++++++++++-------- src/harness/unittests/tscWatchMode.ts | 25 ++--- .../reference/api/tsserverlibrary.d.ts | 5 +- tests/baselines/reference/api/typescript.d.ts | 28 +++--- 8 files changed, 136 insertions(+), 96 deletions(-) diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index c2f816a4c71..cc506852252 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -218,29 +218,40 @@ namespace ts { newProgram: Program; host: BuilderProgramHost; oldProgram: BuilderProgram | undefined; + configFileParsingDiagnostics: ReadonlyArray; } - export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, oldProgram?: BuilderProgram): BuilderCreationParameters { + export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): BuilderCreationParameters { let host: BuilderProgramHost; let newProgram: Program; - if (isArray(newProgramOrRootNames)) { - newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram()); + let oldProgram: BuilderProgram; + if (newProgramOrRootNames === undefined) { + Debug.assert(hostOrOptions === undefined); + host = oldProgramOrHost as CompilerHost; + oldProgram = configFileParsingDiagnosticsOrOldProgram as BuilderProgram; + Debug.assert(!!oldProgram); + newProgram = oldProgram.getProgram(); + } + else if (isArray(newProgramOrRootNames)) { + oldProgram = configFileParsingDiagnosticsOrOldProgram as BuilderProgram; + newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram(), configFileParsingDiagnostics); host = oldProgramOrHost as CompilerHost; } else { newProgram = newProgramOrRootNames; host = hostOrOptions as BuilderProgramHost; oldProgram = oldProgramOrHost as BuilderProgram; + configFileParsingDiagnostics = configFileParsingDiagnosticsOrOldProgram as ReadonlyArray; } - return { host, newProgram, oldProgram }; + return { host, newProgram, oldProgram, configFileParsingDiagnostics: configFileParsingDiagnostics || emptyArray }; } export function createBuilderProgram(kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): SemanticDiagnosticsBuilderProgram; export function createBuilderProgram(kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): EmitAndSemanticDiagnosticsBuilderProgram; - export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram }: BuilderCreationParameters) { + export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters) { // Return same program if underlying program doesnt change let oldState = oldProgram && oldProgram.getState(); - if (oldState && newProgram === oldState.program) { + if (oldState && newProgram === oldState.program && configFileParsingDiagnostics !== newProgram.getConfigFileParsingDiagnostics()) { newProgram = undefined; oldState = undefined; return oldProgram; @@ -269,6 +280,7 @@ namespace ts { getSourceFiles: () => state.program.getSourceFiles(), getOptionsDiagnostics: cancellationToken => state.program.getOptionsDiagnostics(cancellationToken), getGlobalDiagnostics: cancellationToken => state.program.getGlobalDiagnostics(cancellationToken), + getConfigFileParsingDiagnostics: () => configFileParsingDiagnostics || state.program.getConfigFileParsingDiagnostics(), getSyntacticDiagnostics: (sourceFile, cancellationToken) => state.program.getSyntacticDiagnostics(sourceFile, cancellationToken), getSemanticDiagnostics, emit, @@ -471,6 +483,10 @@ namespace ts { * Get the diagnostics that dont belong to any file */ getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + /** + * Get the diagnostics from config file parsing + */ + getConfigFileParsingDiagnostics(): ReadonlyArray; /** * Get the syntax diagnostics, for all source files if source file is not supplied */ @@ -533,29 +549,29 @@ namespace ts { /** * Create the builder to manage semantic diagnostics and cache them */ - export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram; - export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram; - export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, oldProgram?: SemanticDiagnosticsBuilderProgram) { - return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram)); + export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): SemanticDiagnosticsBuilderProgram; + export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): SemanticDiagnosticsBuilderProgram; + export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray) { + return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics)); } /** * Create the builder that can handle the changes in program and iterate through changed files * to emit the those files and manage semantic diagnostics cache as well */ - export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram; - export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram; - export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram) { - return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram)); + export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): EmitAndSemanticDiagnosticsBuilderProgram; + export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): EmitAndSemanticDiagnosticsBuilderProgram; + export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray) { + return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics)); } /** * Creates a builder thats just abstraction over program and can be used with watch */ - export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram): BuilderProgram; - export function createAbstractBuilder(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram): BuilderProgram; - export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, oldProgram?: BuilderProgram): BuilderProgram { - const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram); + export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): BuilderProgram; + export function createAbstractBuilder(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): BuilderProgram; + export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): BuilderProgram { + const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics); return { // Only return program, all other methods are not implemented getProgram: () => program, @@ -565,6 +581,7 @@ namespace ts { getSourceFiles: notImplemented, getOptionsDiagnostics: notImplemented, getGlobalDiagnostics: notImplemented, + getConfigFileParsingDiagnostics: notImplemented, getSyntacticDiagnostics: notImplemented, getSemanticDiagnostics: notImplemented, emit: notImplemented, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 35772b2f040..d75c19b9f24 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -198,6 +198,7 @@ namespace ts { export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] { const diagnostics = [ + ...program.getConfigFileParsingDiagnostics(), ...program.getOptionsDiagnostics(cancellationToken), ...program.getSyntacticDiagnostics(sourceFile, cancellationToken), ...program.getGlobalDiagnostics(cancellationToken), @@ -454,6 +455,12 @@ namespace ts { } } + export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray { + return configFileParseResult.options.configFile ? + configFileParseResult.options.configFile.parseDiagnostics.concat(configFileParseResult.errors) : + configFileParseResult.errors; + } + /** * Determined if source file needs to be re-created even if its text hasn't changed */ @@ -485,9 +492,10 @@ namespace ts { * @param options - The compiler options which should be used. * @param host - The host interacts with the underlying file system. * @param oldProgram - Reuses an old program structure. + * @param configFileParsingDiagnostics - error during config file parsing * @returns A 'Program' object. */ - export function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program { + export function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray): Program { let program: Program; let files: SourceFile[] = []; let commonSourceDirectory: string; @@ -665,7 +673,8 @@ namespace ts { getSourceFileFromReference, sourceFileToPackageName, redirectTargetsSet, - isEmittedFile + isEmittedFile, + getConfigFileParsingDiagnostics }; verifyCompilerOptions(); @@ -1566,6 +1575,10 @@ namespace ts { return sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice()); } + function getConfigFileParsingDiagnostics(): ReadonlyArray { + return configFileParsingDiagnostics || emptyArray; + } + function processRootFile(fileName: string, isDefaultLib: boolean) { processSourceFile(normalizePath(fileName), isDefaultLib, /*packageId*/ undefined); } diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 04725cebabe..09b64701988 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -117,7 +117,7 @@ namespace ts { createWatchOfConfigFile(configParseResult, commandLineOptions); } else { - performCompilation(configParseResult.fileNames, configParseResult.options); + performCompilation(configParseResult.fileNames, configParseResult.options, getConfigFileParsingDiagnostics(configParseResult)); } } else { @@ -139,11 +139,11 @@ namespace ts { } } - function performCompilation(rootFileNames: string[], compilerOptions: CompilerOptions) { + function performCompilation(rootFileNames: string[], compilerOptions: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray) { const compilerHost = createCompilerHost(compilerOptions); enableStatistics(compilerOptions); - const program = createProgram(rootFileNames, compilerOptions, compilerHost); + const program = createProgram(rootFileNames, compilerOptions, compilerHost, /*oldProgram*/ undefined, configFileParsingDiagnostics); const exitStatus = emitFilesAndReportErrors(program, reportDiagnostic, s => sys.write(s + sys.newLine)); reportStatistics(program); return sys.exit(exitStatus); @@ -169,10 +169,7 @@ namespace ts { function createWatchOfConfigFile(configParseResult: ParsedCommandLine, optionsToExtend: CompilerOptions) { const watchCompilerHost = createWatchCompilerHostOfConfigFile(configParseResult.options.configFilePath, optionsToExtend, sys, /*createProgram*/ undefined, reportDiagnostic, createWatchStatusReporter(configParseResult.options)); updateWatchCompilationHost(watchCompilerHost); - watchCompilerHost.rootFiles = configParseResult.fileNames; - watchCompilerHost.options = configParseResult.options; - watchCompilerHost.configFileSpecs = configParseResult.configFileSpecs; - watchCompilerHost.configFileWildCardDirectories = configParseResult.wildcardDirectories; + watchCompilerHost.configFileParsingResult = configParseResult; createWatchProgram(watchCompilerHost); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2e7005d912e..461d94c9f2c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2662,6 +2662,7 @@ namespace ts { getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; /** * Gets a type checker that can be used to semantically analyze source files in the program. diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 2b9cc9cf694..ed5276e49a4 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -70,10 +70,8 @@ namespace ts { /** Parses config file using System interface */ export function parseConfigFileWithSystem(configFileName: string, optionsToExtend: CompilerOptions, system: System, reportDiagnostic: DiagnosticReporter) { const host: ParseConfigFileHost = system; - host.onConfigFileDiagnostic = reportDiagnostic; host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(sys, reportDiagnostic, diagnostic); const result = getParsedCommandLineOfConfigFile(configFileName, optionsToExtend, host); - host.onConfigFileDiagnostic = undefined; host.onUnRecoverableConfigFileDiagnostic = undefined; return result; } @@ -98,13 +96,8 @@ namespace ts { } const result = parseJsonText(configFileName, configFileText); - result.parseDiagnostics.forEach(diagnostic => host.onConfigFileDiagnostic(diagnostic)); - const cwd = host.getCurrentDirectory(); - const configParseResult = parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd)); - configParseResult.errors.forEach(diagnostic => host.onConfigFileDiagnostic(diagnostic)); - - return configParseResult; + return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd)); } /** @@ -118,6 +111,7 @@ namespace ts { getOptionsDiagnostics(): ReadonlyArray; getGlobalDiagnostics(): ReadonlyArray; getSemanticDiagnostics(): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; emit(): EmitResult; } @@ -126,16 +120,18 @@ namespace ts { */ export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void) { // First get and report any syntactic errors. - const diagnostics = program.getSyntacticDiagnostics().slice(); + const diagnostics = program.getConfigFileParsingDiagnostics().slice(); + const configFileParsingDiagnosticsLength = diagnostics.length; + addRange(diagnostics, program.getSyntacticDiagnostics()); let reportSemanticDiagnostics = false; // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. - if (diagnostics.length === 0) { + if (diagnostics.length === configFileParsingDiagnosticsLength) { addRange(diagnostics, program.getOptionsDiagnostics()); addRange(diagnostics, program.getGlobalDiagnostics()); - if (diagnostics.length === 0) { + if (diagnostics.length === configFileParsingDiagnosticsLength) { reportSemanticDiagnostics = true; } } @@ -238,7 +234,6 @@ namespace ts { export function createWatchCompilerHostOfConfigFile(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile { reportDiagnostic = reportDiagnostic || createDiagnosticReporter(system); const host = createWatchCompilerHost(system, createProgram, reportDiagnostic, reportWatchStatus) as WatchCompilerHostOfConfigFile; - host.onConfigFileDiagnostic = reportDiagnostic; host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic); host.configFileName = configFileName; host.optionsToExtend = optionsToExtend; @@ -259,7 +254,8 @@ namespace ts { namespace ts { export type DiagnosticReporter = (diagnostic: Diagnostic) => void; export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; - export type CreateProgram = (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: T) => T; + /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ + export type CreateProgram = (rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray) => T; export interface WatchCompilerHost { /** * Used to create the program when need for program creation or recreation detected @@ -345,11 +341,6 @@ namespace ts { * Reports config file diagnostics */ export interface ConfigFileDiagnosticsReporter { - /** - * Reports the diagnostics in reading/writing or parsing of the config file - */ - onConfigFileDiagnostic: DiagnosticReporter; - /** * Reports unrecoverable error when parsing config file */ @@ -378,11 +369,8 @@ namespace ts { */ /*@internal*/ export interface WatchCompilerHostOfConfigFile extends WatchCompilerHost { - rootFiles?: string[]; - options?: CompilerOptions; optionsToExtend?: CompilerOptions; - configFileSpecs?: ConfigFileSpecs; - configFileWildCardDirectories?: MapLike; + configFileParsingResult?: ParsedCommandLine; } export interface Watch { @@ -460,7 +448,10 @@ namespace ts { const getCurrentDirectory = () => currentDirectory; const readFile: (path: string, encoding?: string) => string | undefined = (path, encoding) => host.readFile(path, encoding); const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, createProgram } = host; - let { rootFiles: rootFileNames, options: compilerOptions, configFileSpecs, configFileWildCardDirectories } = host; + let { rootFiles: rootFileNames, options: compilerOptions } = host; + let configFileSpecs: ConfigFileSpecs; + let configFileParsingDiagnostics: ReadonlyArray | undefined; + let hasChangedConfigFileParsingErrors = false; const cachedDirectoryStructureHost = configFileName && createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames); if (cachedDirectoryStructureHost && host.onCachedDirectoryStructureHostCreate) { @@ -473,13 +464,22 @@ namespace ts { fileExists: path => host.fileExists(path), readFile, getCurrentDirectory, - onConfigFileDiagnostic: host.onConfigFileDiagnostic, onUnRecoverableConfigFileDiagnostic: host.onUnRecoverableConfigFileDiagnostic }; // From tsc we want to get already parsed result and hence check for rootFileNames - if (configFileName && !rootFileNames) { - parseConfigFile(); + let newLine = updateNewLine(); + reportWatchDiagnostic(Diagnostics.Starting_compilation_in_watch_mode); + if (configFileName) { + newLine = getNewLineCharacter(optionsToExtendForConfigFile, () => host.getNewLine()); + if (host.configFileParsingResult) { + setConfigFileParsingResult(host.configFileParsingResult); + } + else { + Debug.assert(!rootFileNames); + parseConfigFile(); + } + newLine = updateNewLine(); } const trace = host.trace && ((s: string) => { host.trace(s + newLine); }); @@ -489,7 +489,6 @@ namespace ts { const { watchFile, watchFilePath, watchDirectory: watchDirectoryWorker } = getWatchFactory(watchLogLevel, writeLog); const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames); - let newLine = updateNewLine(); writeLog(`Current directory: ${currentDirectory} CaseSensitiveFileNames: ${useCaseSensitiveFileNames}`); if (configFileName) { @@ -546,7 +545,6 @@ namespace ts { ((typeDirectiveNames, containingFile) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile)); const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives; - reportWatchDiagnostic(Diagnostics.Starting_compilation_in_watch_mode); synchronizeProgram(); // Update the wild card directory watch @@ -578,6 +576,10 @@ namespace ts { // All resolutions are invalid if user provided resolutions const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(userProvidedResolution); if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) { + if (hasChangedConfigFileParsingErrors) { + builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics); + hasChangedConfigFileParsingErrors = false; + } return builderProgram; } @@ -590,10 +592,11 @@ namespace ts { const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || !program; hasChangedCompilerOptions = false; + hasChangedConfigFileParsingErrors = false; resolutionCache.startCachingPerDirectoryResolution(); compilerHost.hasInvalidatedResolution = hasInvalidatedResolution; compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; - builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram); + builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics); resolutionCache.finishCachingPerDirectoryResolution(); // Update watches @@ -630,7 +633,7 @@ namespace ts { } function updateNewLine() { - return getNewLineCharacter(compilerOptions, () => host.getNewLine()); + return getNewLineCharacter(compilerOptions || optionsToExtendForConfigFile, () => host.getNewLine()); } function toPath(fileName: string) { @@ -760,7 +763,7 @@ namespace ts { function reportWatchDiagnostic(message: DiagnosticMessage) { if (host.onWatchStatusChange) { - host.onWatchStatusChange(createCompilerDiagnostic(message), newLine, compilerOptions); + host.onWatchStatusChange(createCompilerDiagnostic(message), newLine, compilerOptions || optionsToExtendForConfigFile); } } @@ -801,8 +804,13 @@ namespace ts { function reloadFileNamesFromConfigFile() { const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, parseConfigFileHost); - if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) { - host.onConfigFileDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName)); + if (result.fileNames.length) { + configFileParsingDiagnostics = filter(configFileParsingDiagnostics, error => !isErrorNoInputFiles(error)); + hasChangedConfigFileParsingErrors = true; + } + else if (!configFileSpecs.filesSpecs && !some(configFileParsingDiagnostics, isErrorNoInputFiles)) { + configFileParsingDiagnostics = configFileParsingDiagnostics!.concat(getErrorForNoInputFiles(configFileSpecs, configFileName)); + hasChangedConfigFileParsingErrors = true; } rootFileNames = result.fileNames; @@ -826,11 +834,15 @@ namespace ts { } function parseConfigFile() { - const configParseResult = getParsedCommandLineOfConfigFile(configFileName, optionsToExtendForConfigFile, parseConfigFileHost); - rootFileNames = configParseResult.fileNames; - compilerOptions = configParseResult.options; - configFileSpecs = configParseResult.configFileSpecs; - configFileWildCardDirectories = configParseResult.wildcardDirectories; + setConfigFileParsingResult(getParsedCommandLineOfConfigFile(configFileName, optionsToExtendForConfigFile, parseConfigFileHost)); + } + + function setConfigFileParsingResult(configFileParseResult: ParsedCommandLine) { + rootFileNames = configFileParseResult.fileNames; + compilerOptions = configFileParseResult.options; + configFileSpecs = configFileParseResult.configFileSpecs; + configFileParsingDiagnostics = getConfigFileParsingDiagnostics(configFileParseResult); + hasChangedConfigFileParsingErrors = true; } function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) { @@ -876,10 +888,10 @@ namespace ts { } function watchConfigFileWildCardDirectories() { - if (configFileWildCardDirectories) { + if (configFileSpecs) { updateWatchingWildcardDirectories( watchedWildcardDirectories || (watchedWildcardDirectories = createMap()), - createMapFromTemplate(configFileWildCardDirectories), + createMapFromTemplate(configFileSpecs.wildcardDirectories), watchWildcardDirectory ); } diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index b10c73d4a06..bcc65f8bdd1 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -76,7 +76,7 @@ namespace ts.tscWatch { function checkOutputErrors( host: WatchedSystem, logsBeforeWatchDiagnostic: string[] | undefined, - preErrorsWatchDiagnostic: DiagnosticMessage | undefined, + preErrorsWatchDiagnostic: DiagnosticMessage, logsBeforeErrors: string[] | undefined, errors: ReadonlyArray, disableConsoleClears?: boolean | undefined, @@ -84,14 +84,12 @@ namespace ts.tscWatch { ) { let screenClears = 0; const outputs = host.getOutput(); - const expectedOutputCount = (preErrorsWatchDiagnostic ? 1 : 0) + errors.length + postErrorsWatchDiagnostics.length + + const expectedOutputCount = 1 + errors.length + postErrorsWatchDiagnostics.length + (logsBeforeWatchDiagnostic ? logsBeforeWatchDiagnostic.length : 0) + (logsBeforeErrors ? logsBeforeErrors.length : 0); assert.equal(outputs.length, expectedOutputCount, JSON.stringify(outputs)); let index = 0; forEach(logsBeforeWatchDiagnostic, log => assertLog("logsBeforeWatchDiagnostic", log)); - if (preErrorsWatchDiagnostic) { - assertWatchDiagnostic(preErrorsWatchDiagnostic); - } + assertWatchDiagnostic(preErrorsWatchDiagnostic); forEach(logsBeforeErrors, log => assertLog("logBeforeError", log)); // Verify errors forEach(errors, assertDiagnostic); @@ -130,20 +128,16 @@ namespace ts.tscWatch { } } - function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { - checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.Starting_compilation_in_watch_mode, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); - } - - function checkOutputErrorsInitialWithConfigErrors(host: WatchedSystem, errors: ReadonlyArray) { - checkOutputErrors(host, /*logsBeforeWatchDiagnostic*/ undefined, /*preErrorsWatchDiagnostic*/ undefined, /*logsBeforeErrors*/ undefined, errors, /*disableConsoleClears*/ undefined, Diagnostics.Starting_compilation_in_watch_mode, Diagnostics.Compilation_complete_Watching_for_file_changes); + function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) { + checkOutputErrors(host, /*logsBeforeWatchDiagnostic*/ undefined, Diagnostics.Starting_compilation_in_watch_mode, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); } function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.File_change_detected_Starting_incremental_compilation, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); } - function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray, expectedExitCode: ExitStatus) { - checkOutputErrors(host, /*logsBeforeWatchDiagnostic*/ undefined, Diagnostics.File_change_detected_Starting_incremental_compilation, /*logsBeforeErrors*/ undefined, errors, /*disableConsoleClears*/ undefined); + function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { + checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.File_change_detected_Starting_incremental_compilation, logsBeforeErrors, errors, disableConsoleClears); assert.equal(host.exitCode, expectedExitCode); } @@ -916,7 +910,7 @@ namespace ts.tscWatch { const host = createWatchedSystem([file, configFile, libFile]); const watch = createWatchOfConfigFile(configFile.path, host); - checkOutputErrorsInitialWithConfigErrors(host, [ + checkOutputErrorsInitial(host, [ getUnknownCompilerOption(watch(), configFile, "foo"), getUnknownCompilerOption(watch(), configFile, "allowJS") ]); @@ -2185,8 +2179,7 @@ declare module "fs" { const host = createWatchedSystem(files); createWatchOfFilesAndCompilerOptions([file.path], host, options); checkOutputErrorsInitial(host, emptyArray, disableConsoleClear, options.extendedDiagnostics && [ - "Current directory: / CaseSensitiveFileNames: false\n" - ], options.extendedDiagnostics && [ + "Current directory: / CaseSensitiveFileNames: false\n", "Synchronizing program\n", "CreatingProgramWith::\n", " roots: [\"f.ts\"]\n", diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 8b9e078716c..faaa2759d5c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1685,6 +1685,7 @@ declare namespace ts { getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; /** * Gets a type checker that can be used to semantically analyze source files in the program. */ @@ -3917,6 +3918,7 @@ declare namespace ts { function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string; function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray, host: FormatDiagnosticsHost): string; function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string; + function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray; /** * Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions' * that represent a compilation unit. @@ -3928,9 +3930,10 @@ declare namespace ts { * @param options - The compiler options which should be used. * @param host - The host interacts with the underlying file system. * @param oldProgram - Reuses an old program structure. + * @param configFileParsingDiagnostics - error during config file parsing * @returns A 'Program' object. */ - function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program; + function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray): Program; } declare namespace ts { interface Node { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 87204f489d8..d9bfbc13a40 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1685,6 +1685,7 @@ declare namespace ts { getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray; + getConfigFileParsingDiagnostics(): ReadonlyArray; /** * Gets a type checker that can be used to semantically analyze source files in the program. */ @@ -3864,6 +3865,7 @@ declare namespace ts { function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string; function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray, host: FormatDiagnosticsHost): string; function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string; + function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray; /** * Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions' * that represent a compilation unit. @@ -3875,9 +3877,10 @@ declare namespace ts { * @param options - The compiler options which should be used. * @param host - The host interacts with the underlying file system. * @param oldProgram - Reuses an old program structure. + * @param configFileParsingDiagnostics - error during config file parsing * @returns A 'Program' object. */ - function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program; + function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray): Program; } declare namespace ts { interface EmitOutput { @@ -3938,6 +3941,10 @@ declare namespace ts { * Get the diagnostics that dont belong to any file */ getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray; + /** + * Get the diagnostics from config file parsing + */ + getConfigFileParsingDiagnostics(): ReadonlyArray; /** * Get the syntax diagnostics, for all source files if source file is not supplied */ @@ -3997,24 +4004,25 @@ declare namespace ts { /** * Create the builder to manage semantic diagnostics and cache them */ - function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram; - function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram; + function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): SemanticDiagnosticsBuilderProgram; + function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): SemanticDiagnosticsBuilderProgram; /** * Create the builder that can handle the changes in program and iterate through changed files * to emit the those files and manage semantic diagnostics cache as well */ - function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram; - function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram; + function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): EmitAndSemanticDiagnosticsBuilderProgram; + function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): EmitAndSemanticDiagnosticsBuilderProgram; /** * Creates a builder thats just abstraction over program and can be used with watch */ - function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram): BuilderProgram; - function createAbstractBuilder(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram): BuilderProgram; + function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): BuilderProgram; + function createAbstractBuilder(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray): BuilderProgram; } declare namespace ts { type DiagnosticReporter = (diagnostic: Diagnostic) => void; type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; - type CreateProgram = (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: T) => T; + /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ + type CreateProgram = (rootNames: ReadonlyArray | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray) => T; interface WatchCompilerHost { /** * Used to create the program when need for program creation or recreation detected @@ -4078,10 +4086,6 @@ declare namespace ts { * Reports config file diagnostics */ interface ConfigFileDiagnosticsReporter { - /** - * Reports the diagnostics in reading/writing or parsing of the config file - */ - onConfigFileDiagnostic: DiagnosticReporter; /** * Reports unrecoverable error when parsing config file */