Skip to content

Commit a0fe072

Browse files
authored
Merge pull request #22613 from Microsoft/configFileErrors
Make config file parsing errors available through program and expose API
2 parents d5a7dc1 + 7329eb1 commit a0fe072

File tree

9 files changed

+180
-121
lines changed

9 files changed

+180
-121
lines changed

src/compiler/builder.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -218,29 +218,40 @@ namespace ts {
218218
newProgram: Program;
219219
host: BuilderProgramHost;
220220
oldProgram: BuilderProgram | undefined;
221+
configFileParsingDiagnostics: ReadonlyArray<Diagnostic>;
221222
}
222223

223-
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, oldProgram?: BuilderProgram): BuilderCreationParameters {
224+
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderCreationParameters {
224225
let host: BuilderProgramHost;
225226
let newProgram: Program;
226-
if (isArray(newProgramOrRootNames)) {
227-
newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram());
227+
let oldProgram: BuilderProgram;
228+
if (newProgramOrRootNames === undefined) {
229+
Debug.assert(hostOrOptions === undefined);
230+
host = oldProgramOrHost as CompilerHost;
231+
oldProgram = configFileParsingDiagnosticsOrOldProgram as BuilderProgram;
232+
Debug.assert(!!oldProgram);
233+
newProgram = oldProgram.getProgram();
234+
}
235+
else if (isArray(newProgramOrRootNames)) {
236+
oldProgram = configFileParsingDiagnosticsOrOldProgram as BuilderProgram;
237+
newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram(), configFileParsingDiagnostics);
228238
host = oldProgramOrHost as CompilerHost;
229239
}
230240
else {
231241
newProgram = newProgramOrRootNames;
232242
host = hostOrOptions as BuilderProgramHost;
233243
oldProgram = oldProgramOrHost as BuilderProgram;
244+
configFileParsingDiagnostics = configFileParsingDiagnosticsOrOldProgram as ReadonlyArray<Diagnostic>;
234245
}
235-
return { host, newProgram, oldProgram };
246+
return { host, newProgram, oldProgram, configFileParsingDiagnostics: configFileParsingDiagnostics || emptyArray };
236247
}
237248

238249
export function createBuilderProgram(kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): SemanticDiagnosticsBuilderProgram;
239250
export function createBuilderProgram(kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): EmitAndSemanticDiagnosticsBuilderProgram;
240-
export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram }: BuilderCreationParameters) {
251+
export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters) {
241252
// Return same program if underlying program doesnt change
242253
let oldState = oldProgram && oldProgram.getState();
243-
if (oldState && newProgram === oldState.program) {
254+
if (oldState && newProgram === oldState.program && configFileParsingDiagnostics !== newProgram.getConfigFileParsingDiagnostics()) {
244255
newProgram = undefined;
245256
oldState = undefined;
246257
return oldProgram;
@@ -269,6 +280,7 @@ namespace ts {
269280
getSourceFiles: () => state.program.getSourceFiles(),
270281
getOptionsDiagnostics: cancellationToken => state.program.getOptionsDiagnostics(cancellationToken),
271282
getGlobalDiagnostics: cancellationToken => state.program.getGlobalDiagnostics(cancellationToken),
283+
getConfigFileParsingDiagnostics: () => configFileParsingDiagnostics || state.program.getConfigFileParsingDiagnostics(),
272284
getSyntacticDiagnostics: (sourceFile, cancellationToken) => state.program.getSyntacticDiagnostics(sourceFile, cancellationToken),
273285
getSemanticDiagnostics,
274286
emit,
@@ -471,6 +483,10 @@ namespace ts {
471483
* Get the diagnostics that dont belong to any file
472484
*/
473485
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
486+
/**
487+
* Get the diagnostics from config file parsing
488+
*/
489+
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
474490
/**
475491
* Get the syntax diagnostics, for all source files if source file is not supplied
476492
*/
@@ -533,29 +549,29 @@ namespace ts {
533549
/**
534550
* Create the builder to manage semantic diagnostics and cache them
535551
*/
536-
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
537-
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
538-
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, oldProgram?: SemanticDiagnosticsBuilderProgram) {
539-
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram));
552+
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
553+
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
554+
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
555+
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics));
540556
}
541557

542558
/**
543559
* Create the builder that can handle the changes in program and iterate through changed files
544560
* to emit the those files and manage semantic diagnostics cache as well
545561
*/
546-
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
547-
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
548-
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram) {
549-
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram));
562+
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
563+
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
564+
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
565+
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics));
550566
}
551567

552568
/**
553569
* Creates a builder thats just abstraction over program and can be used with watch
554570
*/
555-
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram): BuilderProgram;
556-
export function createAbstractBuilder(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram): BuilderProgram;
557-
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, oldProgram?: BuilderProgram): BuilderProgram {
558-
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram);
571+
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
572+
export function createAbstractBuilder(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
573+
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram {
574+
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics);
559575
return {
560576
// Only return program, all other methods are not implemented
561577
getProgram: () => program,
@@ -565,6 +581,7 @@ namespace ts {
565581
getSourceFiles: notImplemented,
566582
getOptionsDiagnostics: notImplemented,
567583
getGlobalDiagnostics: notImplemented,
584+
getConfigFileParsingDiagnostics: notImplemented,
568585
getSyntacticDiagnostics: notImplemented,
569586
getSemanticDiagnostics: notImplemented,
570587
emit: notImplemented,

src/compiler/program.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ namespace ts {
198198

199199
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] {
200200
const diagnostics = [
201+
...program.getConfigFileParsingDiagnostics(),
201202
...program.getOptionsDiagnostics(cancellationToken),
202203
...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
203204
...program.getGlobalDiagnostics(cancellationToken),
@@ -454,6 +455,12 @@ namespace ts {
454455
}
455456
}
456457

458+
export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray<Diagnostic> {
459+
return configFileParseResult.options.configFile ?
460+
configFileParseResult.options.configFile.parseDiagnostics.concat(configFileParseResult.errors) :
461+
configFileParseResult.errors;
462+
}
463+
457464
/**
458465
* Determined if source file needs to be re-created even if its text hasn't changed
459466
*/
@@ -485,9 +492,10 @@ namespace ts {
485492
* @param options - The compiler options which should be used.
486493
* @param host - The host interacts with the underlying file system.
487494
* @param oldProgram - Reuses an old program structure.
495+
* @param configFileParsingDiagnostics - error during config file parsing
488496
* @returns A 'Program' object.
489497
*/
490-
export function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program {
498+
export function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program {
491499
let program: Program;
492500
let files: SourceFile[] = [];
493501
let commonSourceDirectory: string;
@@ -665,7 +673,8 @@ namespace ts {
665673
getSourceFileFromReference,
666674
sourceFileToPackageName,
667675
redirectTargetsSet,
668-
isEmittedFile
676+
isEmittedFile,
677+
getConfigFileParsingDiagnostics
669678
};
670679

671680
verifyCompilerOptions();
@@ -1568,6 +1577,10 @@ namespace ts {
15681577
return sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice());
15691578
}
15701579

1580+
function getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic> {
1581+
return configFileParsingDiagnostics || emptyArray;
1582+
}
1583+
15711584
function processRootFile(fileName: string, isDefaultLib: boolean) {
15721585
processSourceFile(normalizePath(fileName), isDefaultLib, /*packageId*/ undefined);
15731586
}

src/compiler/tsc.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ namespace ts {
117117
createWatchOfConfigFile(configParseResult, commandLineOptions);
118118
}
119119
else {
120-
performCompilation(configParseResult.fileNames, configParseResult.options);
120+
performCompilation(configParseResult.fileNames, configParseResult.options, getConfigFileParsingDiagnostics(configParseResult));
121121
}
122122
}
123123
else {
@@ -139,11 +139,11 @@ namespace ts {
139139
}
140140
}
141141

142-
function performCompilation(rootFileNames: string[], compilerOptions: CompilerOptions) {
142+
function performCompilation(rootFileNames: string[], compilerOptions: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
143143
const compilerHost = createCompilerHost(compilerOptions);
144144
enableStatistics(compilerOptions);
145145

146-
const program = createProgram(rootFileNames, compilerOptions, compilerHost);
146+
const program = createProgram(rootFileNames, compilerOptions, compilerHost, /*oldProgram*/ undefined, configFileParsingDiagnostics);
147147
const exitStatus = emitFilesAndReportErrors(program, reportDiagnostic, s => sys.write(s + sys.newLine));
148148
reportStatistics(program);
149149
return sys.exit(exitStatus);
@@ -169,10 +169,7 @@ namespace ts {
169169
function createWatchOfConfigFile(configParseResult: ParsedCommandLine, optionsToExtend: CompilerOptions) {
170170
const watchCompilerHost = createWatchCompilerHostOfConfigFile(configParseResult.options.configFilePath, optionsToExtend, sys, /*createProgram*/ undefined, reportDiagnostic, createWatchStatusReporter(configParseResult.options));
171171
updateWatchCompilationHost(watchCompilerHost);
172-
watchCompilerHost.rootFiles = configParseResult.fileNames;
173-
watchCompilerHost.options = configParseResult.options;
174-
watchCompilerHost.configFileSpecs = configParseResult.configFileSpecs;
175-
watchCompilerHost.configFileWildCardDirectories = configParseResult.wildcardDirectories;
172+
watchCompilerHost.configFileParsingResult = configParseResult;
176173
createWatchProgram(watchCompilerHost);
177174
}
178175

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2671,6 +2671,7 @@ namespace ts {
26712671
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
26722672
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
26732673
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
2674+
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
26742675

26752676
/**
26762677
* Gets a type checker that can be used to semantically analyze source files in the program.

0 commit comments

Comments
 (0)