feat(compiler-cli): improve error messages produced during structural errors (#20459)

The errors produced when error were encountered while interpreting the
content of a directive was often incomprehencible. With this change
these kind of error messages should be easier to understand and diagnose.

PR Close #20459
This commit is contained in:
Chuck Jazdzewski
2017-11-14 17:49:47 -08:00
committed by Miško Hevery
parent 1366762d12
commit 8ecda94899
25 changed files with 1247 additions and 308 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {isSyntaxError, syntaxError} from '@angular/compiler';
import {Position, isSyntaxError, syntaxError} from '@angular/compiler';
import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
@ -29,30 +29,76 @@ const defaultFormatHost: ts.FormatDiagnosticsHost = {
getNewLine: () => ts.sys.newLine
};
function displayFileName(fileName: string, host: ts.FormatDiagnosticsHost): string {
return path.relative(host.getCurrentDirectory(), host.getCanonicalFileName(fileName));
}
export function formatDiagnosticPosition(
position: Position, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
return `${displayFileName(position.fileName, host)}(${position.line + 1},${position.column+1})`;
}
export function flattenDiagnosticMessageChain(
chain: api.DiagnosticMessageChain, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
let result = chain.messageText;
let indent = 1;
let current = chain.next;
const newLine = host.getNewLine();
while (current) {
result += newLine;
for (let i = 0; i < indent; i++) {
result += ' ';
}
result += current.messageText;
const position = current.position;
if (position) {
result += ` at ${formatDiagnosticPosition(position, host)}`;
}
current = current.next;
indent++;
}
return result;
}
export function formatDiagnostic(
diagnostic: api.Diagnostic, host: ts.FormatDiagnosticsHost = defaultFormatHost) {
let result = '';
const newLine = host.getNewLine();
const span = diagnostic.span;
if (span) {
result += `${formatDiagnosticPosition({
fileName: span.start.file.url,
line: span.start.line,
column: span.start.col
}, host)}: `;
} else if (diagnostic.position) {
result += `${formatDiagnosticPosition(diagnostic.position, host)}: `;
}
if (diagnostic.span && diagnostic.span.details) {
result += `: ${diagnostic.span.details}, ${diagnostic.messageText}${newLine}`;
} else if (diagnostic.chain) {
result += `${flattenDiagnosticMessageChain(diagnostic.chain, host)}.${newLine}`;
} else {
result += `: ${diagnostic.messageText}${newLine}`;
}
return result;
}
export function formatDiagnostics(
diags: Diagnostics, tsFormatHost: ts.FormatDiagnosticsHost = defaultFormatHost): string {
diags: Diagnostics, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
if (diags && diags.length) {
return diags
.map(d => {
if (api.isTsDiagnostic(d)) {
return ts.formatDiagnostics([d], tsFormatHost);
.map(diagnostic => {
if (api.isTsDiagnostic(diagnostic)) {
return ts.formatDiagnostics([diagnostic], host);
} else {
let res = ts.DiagnosticCategory[d.category];
if (d.span) {
res +=
` at ${d.span.start.file.url}(${d.span.start.line + 1},${d.span.start.col + 1})`;
}
if (d.span && d.span.details) {
res += `: ${d.span.details}, ${d.messageText}\n`;
} else {
res += `: ${d.messageText}\n`;
}
return res;
return formatDiagnostic(diagnostic, host);
}
})
.join('');
} else
} else {
return '';
}
}
export interface ParsedConfiguration {