fix(ngcc): report diagnostics from migrations (#34014)

When ngcc is analyzing synthetically inserted decorators from a
migration, it is typically not expected that any diagnostics are
produced. In the situation where a diagnostic is produced, however, the
diagnostic would not be reported at all. This commit ensures that
diagnostics in migrations are reported.

PR Close #34014
This commit is contained in:
JoostK
2019-11-23 18:54:07 +01:00
committed by Andrew Kushnir
parent 9fa2c398e7
commit 0f0fd25038
3 changed files with 106 additions and 15 deletions

View File

@ -160,7 +160,7 @@ export class DecorationAnalyzer {
protected applyMigrations(analyzedFiles: AnalyzedFile[]): void {
const migrationHost = new DefaultMigrationHost(
this.reflectionHost, this.fullMetaReader, this.evaluator, this.handlers,
this.bundle.entryPoint.path, analyzedFiles);
this.bundle.entryPoint.path, analyzedFiles, this.diagnosticHandler);
this.migrations.forEach(migration => {
analyzedFiles.forEach(analyzedFile => {

View File

@ -27,7 +27,8 @@ export class DefaultMigrationHost implements MigrationHost {
constructor(
readonly reflectionHost: NgccReflectionHost, readonly metadata: MetadataReader,
readonly evaluator: PartialEvaluator, private handlers: DecoratorHandler<any, any>[],
private entryPointPath: AbsoluteFsPath, private analyzedFiles: AnalyzedFile[]) {}
private entryPointPath: AbsoluteFsPath, private analyzedFiles: AnalyzedFile[],
private diagnosticHandler: (error: ts.Diagnostic) => void) {}
injectSyntheticDecorator(clazz: ClassDeclaration, decorator: Decorator, flags?: HandlerFlags):
void {
@ -37,6 +38,12 @@ export class DefaultMigrationHost implements MigrationHost {
return;
}
if (newAnalyzedClass.diagnostics !== undefined) {
for (const diagnostic of newAnalyzedClass.diagnostics) {
this.diagnosticHandler(createMigrationDiagnostic(diagnostic, clazz, decorator));
}
}
const analyzedFile = getOrCreateAnalyzedFile(this.analyzedFiles, clazz.getSourceFile());
const oldAnalyzedClass = analyzedFile.analyzedClasses.find(c => c.declaration === clazz);
if (oldAnalyzedClass === undefined) {
@ -102,3 +109,43 @@ function mergeAnalyzedClasses(oldClass: AnalyzedClass, newClass: AnalyzedClass)
}
}
}
/**
* Creates a diagnostic from another one, containing additional information about the synthetic
* decorator.
*/
function createMigrationDiagnostic(
diagnostic: ts.Diagnostic, source: ts.Node, decorator: Decorator): ts.Diagnostic {
const clone = {...diagnostic};
const chain: ts.DiagnosticMessageChain[] = [{
messageText: `Occurs for @${decorator.name} decorator inserted by an automatic migration`,
category: ts.DiagnosticCategory.Message,
code: 0,
}];
if (decorator.args !== null) {
const args = decorator.args.map(arg => arg.getText()).join(', ');
chain.push({
messageText: `@${decorator.name}(${args})`,
category: ts.DiagnosticCategory.Message,
code: 0,
});
}
if (typeof clone.messageText === 'string') {
clone.messageText = {
messageText: clone.messageText,
category: diagnostic.category,
code: diagnostic.code,
next: chain,
};
} else {
if (clone.messageText.next === undefined) {
clone.messageText.next = chain;
} else {
clone.messageText.next.push(...chain);
}
}
return clone;
}