mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Report all project errors on incremental compile
This commit is contained in:
parent
5696384a9f
commit
b8f33f6a35
@ -394,9 +394,9 @@ namespace ts {
|
||||
let globalDependencyGraph: DependencyGraph | undefined;
|
||||
|
||||
// Watch state
|
||||
// TODO(shkamat): this should be really be diagnostics but thats for later time
|
||||
const diagnostics = createFileMap<number>(toPath);
|
||||
const diagnostics = createFileMap<ReadonlyArray<Diagnostic>>(toPath);
|
||||
const projectPendingBuild = createFileMap<ConfigFileProgramReloadLevel>(toPath);
|
||||
const projectErrorsReported = createFileMap<true>(toPath);
|
||||
const invalidatedProjectQueue = [] as ResolvedConfigFileName[];
|
||||
let nextProjectToBuild = 0;
|
||||
let timerToBuildInvalidatedProject: any;
|
||||
@ -438,6 +438,7 @@ namespace ts {
|
||||
|
||||
diagnostics.clear();
|
||||
projectPendingBuild.clear();
|
||||
projectErrorsReported.clear();
|
||||
invalidatedProjectQueue.length = 0;
|
||||
nextProjectToBuild = 0;
|
||||
if (timerToBuildInvalidatedProject) {
|
||||
@ -472,18 +473,6 @@ namespace ts {
|
||||
host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args));
|
||||
}
|
||||
|
||||
function storeErrors(proj: ResolvedConfigFileName, diagnostics: ReadonlyArray<Diagnostic>) {
|
||||
if (options.watch) {
|
||||
storeErrorSummary(proj, diagnostics.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length);
|
||||
}
|
||||
}
|
||||
|
||||
function storeErrorSummary(proj: ResolvedConfigFileName, errorCount: number) {
|
||||
if (options.watch) {
|
||||
diagnostics.setValue(proj, errorCount);
|
||||
}
|
||||
}
|
||||
|
||||
function reportWatchStatus(message: DiagnosticMessage, ...args: (string | number | undefined)[]) {
|
||||
if (hostWithWatch.onWatchStatusChange) {
|
||||
hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), host.getNewLine(), { preserveWatchOutput: options.preserveWatchOutput });
|
||||
@ -509,7 +498,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function watchConfigFile(resolved: ResolvedConfigFileName) {
|
||||
if (!allWatchedConfigFiles.hasKey(resolved)) {
|
||||
if (options.watch && !allWatchedConfigFiles.hasKey(resolved)) {
|
||||
allWatchedConfigFiles.setValue(resolved, hostWithWatch.watchFile(resolved, () => {
|
||||
invalidateProjectAndScheduleBuilds(resolved, ConfigFileProgramReloadLevel.Full);
|
||||
}));
|
||||
@ -517,6 +506,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function watchWildCardDirectories(resolved: ResolvedConfigFileName, parsed: ParsedCommandLine) {
|
||||
if (!options.watch) return;
|
||||
updateWatchingWildcardDirectories(
|
||||
getOrCreateValueMapFromConfigFileMap(allWatchedWildcardDirectories, resolved),
|
||||
createMapFromTemplate(parsed.configFileSpecs!.wildcardDirectories),
|
||||
@ -540,6 +530,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function watchInputFiles(resolved: ResolvedConfigFileName, parsed: ParsedCommandLine) {
|
||||
if (!options.watch) return;
|
||||
mutateMap(
|
||||
getOrCreateValueMapFromConfigFileMap(allWatchedInputFiles, resolved),
|
||||
arrayToMap(parsed.fileNames, toPath),
|
||||
@ -848,6 +839,7 @@ namespace ts {
|
||||
timerToBuildInvalidatedProject = undefined;
|
||||
if (reportFileChangeDetected) {
|
||||
reportFileChangeDetected = false;
|
||||
projectErrorsReported.clear();
|
||||
reportWatchStatus(Diagnostics.File_change_detected_Starting_incremental_compilation);
|
||||
}
|
||||
const buildProject = getNextInvalidatedProject();
|
||||
@ -866,15 +858,19 @@ namespace ts {
|
||||
|
||||
function reportErrorSummary() {
|
||||
if (options.watch) {
|
||||
// Report errors from the other projects
|
||||
getGlobalDependencyGraph().buildQueue.forEach(project => {
|
||||
if (!projectErrorsReported.hasKey(project)) {
|
||||
reportErrors(diagnostics.getValue(project) || emptyArray);
|
||||
}
|
||||
});
|
||||
let totalErrors = 0;
|
||||
diagnostics.forEach(singleProjectErrors => totalErrors += singleProjectErrors);
|
||||
diagnostics.forEach(singleProjectErrors => totalErrors += singleProjectErrors.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length);
|
||||
reportWatchStatus(totalErrors === 1 ? Diagnostics.Found_1_error_Watching_for_file_changes : Diagnostics.Found_0_errors_Watching_for_file_changes, totalErrors);
|
||||
}
|
||||
}
|
||||
|
||||
function buildSingleInvalidatedProject(resolved: ResolvedConfigFileName, reloadLevel: ConfigFileProgramReloadLevel) {
|
||||
// TODO:: handle this in better way later
|
||||
|
||||
const proj = parseConfigFile(resolved);
|
||||
if (!proj) {
|
||||
reportParseConfigFileDiagnostic(resolved);
|
||||
@ -968,10 +964,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function reportParseConfigFileDiagnostic(proj: ResolvedConfigFileName) {
|
||||
host.reportDiagnostic(configFileCache.getValue(proj) as Diagnostic);
|
||||
storeErrorSummary(proj, 1);
|
||||
}
|
||||
|
||||
function buildSingleProject(proj: ResolvedConfigFileName): BuildResultFlags {
|
||||
if (options.dry) {
|
||||
@ -1013,7 +1005,7 @@ namespace ts {
|
||||
...program.getSyntacticDiagnostics()];
|
||||
if (syntaxDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.SyntaxErrors;
|
||||
reportErrors(proj, syntaxDiagnostics);
|
||||
reportAndStoreErrors(proj, syntaxDiagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Syntactic errors" });
|
||||
return resultFlags;
|
||||
}
|
||||
@ -1023,7 +1015,7 @@ namespace ts {
|
||||
const declDiagnostics = program.getDeclarationDiagnostics();
|
||||
if (declDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.DeclarationEmitErrors;
|
||||
reportErrors(proj, declDiagnostics);
|
||||
reportAndStoreErrors(proj, declDiagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Declaration file errors" });
|
||||
return resultFlags;
|
||||
}
|
||||
@ -1033,7 +1025,7 @@ namespace ts {
|
||||
const semanticDiagnostics = program.getSemanticDiagnostics();
|
||||
if (semanticDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.TypeErrors;
|
||||
reportErrors(proj, semanticDiagnostics);
|
||||
reportAndStoreErrors(proj, semanticDiagnostics);
|
||||
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Semantic errors" });
|
||||
return resultFlags;
|
||||
}
|
||||
@ -1154,7 +1146,7 @@ namespace ts {
|
||||
|
||||
const projName = proj.options.configFilePath!;
|
||||
if (status.type === UpToDateStatusType.UpToDate && !options.force) {
|
||||
reportErrors(next, errors);
|
||||
reportAndStoreErrors(next, errors);
|
||||
// Up to date, skip
|
||||
if (defaultOptions.dry) {
|
||||
// In a dry build, inform the user of this fact
|
||||
@ -1164,20 +1156,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes && !options.force) {
|
||||
reportErrors(next, errors);
|
||||
reportAndStoreErrors(next, errors);
|
||||
// Fake build
|
||||
updateOutputTimestamps(proj);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status.type === UpToDateStatusType.UpstreamBlocked) {
|
||||
reportErrors(next, errors);
|
||||
reportAndStoreErrors(next, errors);
|
||||
if (options.verbose) reportStatus(Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, projName, status.upstreamProjectName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status.type === UpToDateStatusType.ContainerOnly) {
|
||||
reportErrors(next, errors);
|
||||
reportAndStoreErrors(next, errors);
|
||||
// Do nothing
|
||||
continue;
|
||||
}
|
||||
@ -1189,9 +1181,20 @@ namespace ts {
|
||||
return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success;
|
||||
}
|
||||
|
||||
function reportErrors(proj: ResolvedConfigFileName, errors: ReadonlyArray<Diagnostic>) {
|
||||
function reportParseConfigFileDiagnostic(proj: ResolvedConfigFileName) {
|
||||
reportAndStoreErrors(proj, [configFileCache.getValue(proj) as Diagnostic]);
|
||||
}
|
||||
|
||||
function reportAndStoreErrors(proj: ResolvedConfigFileName, errors: ReadonlyArray<Diagnostic>) {
|
||||
reportErrors(errors);
|
||||
if (options.watch) {
|
||||
projectErrorsReported.setValue(proj, true);
|
||||
diagnostics.setValue(proj, errors);
|
||||
}
|
||||
}
|
||||
|
||||
function reportErrors(errors: ReadonlyArray<Diagnostic>) {
|
||||
errors.forEach(err => host.reportDiagnostic(err));
|
||||
storeErrors(proj, errors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -351,6 +351,33 @@ function myFunc() { return 100; }`);
|
||||
}
|
||||
});
|
||||
|
||||
it("reports errors in all projects on incremental compile", () => {
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
let y: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, outputFileStamps, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
]);
|
||||
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
let x: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, changedLogic, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`,
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
]);
|
||||
});
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ namespace ts.tscWatch {
|
||||
logsBeforeWatchDiagnostic: string[] | undefined,
|
||||
preErrorsWatchDiagnostic: Diagnostic,
|
||||
logsBeforeErrors: string[] | undefined,
|
||||
errors: ReadonlyArray<Diagnostic>,
|
||||
errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>,
|
||||
disableConsoleClears?: boolean | undefined,
|
||||
...postErrorsWatchDiagnostics: Diagnostic[]
|
||||
) {
|
||||
@ -96,8 +96,12 @@ namespace ts.tscWatch {
|
||||
assert.equal(host.screenClears.length, screenClears, "Expected number of screen clears");
|
||||
host.clearOutput();
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = formatDiagnostic(diagnostic, host);
|
||||
function isDiagnostic(diagnostic: Diagnostic | string): diagnostic is Diagnostic {
|
||||
return !!(diagnostic as Diagnostic).messageText;
|
||||
}
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic | string) {
|
||||
const expected = isDiagnostic(diagnostic) ? formatDiagnostic(diagnostic, host) : diagnostic;
|
||||
assert.equal(outputs[index], expected, getOutputAtFailedMessage("Diagnostic", expected));
|
||||
index++;
|
||||
}
|
||||
@ -130,13 +134,13 @@ namespace ts.tscWatch {
|
||||
}
|
||||
}
|
||||
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic>) {
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>) {
|
||||
return errors.length === 1
|
||||
? createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes)
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
@ -147,7 +151,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
@ -158,7 +162,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user