fix(ivy): ngcc should process undecorated base classes (#30821)
Currently undecorated classes are intentionally not processed with ngcc. This is causing unexpected behavior because decorator handlers such as `base_def.ts` are specifically interested in class definitions without top-level decorators, so that the base definition can be generated if there are Angular-specific class members. In order to ensure that undecorated base-classes work as expected with Ivy, we need to run the decorator handlers for all top-level class declarations (not only for those with decorators). This is similar to when `ngtsc` runs decorator handlers when analyzing source-files. Resolves FW-1355. Fixes https://github.com/angular/components/issues/16178 PR Close #30821
This commit is contained in:

committed by
Igor Minar

parent
271d2b51a9
commit
2b4d5c7548
@ -14,10 +14,10 @@ import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy,
|
||||
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, LocalMetadataRegistry} from '../../../src/ngtsc/metadata';
|
||||
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
||||
import {AbsoluteFsPath, LogicalFileSystem} from '../../../src/ngtsc/path';
|
||||
import {ClassDeclaration, ClassSymbol, Decorator} from '../../../src/ngtsc/reflection';
|
||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../../src/ngtsc/scope';
|
||||
import {CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../../src/ngtsc/transform';
|
||||
import {FileSystem} from '../file_system/file_system';
|
||||
import {DecoratedClass} from '../host/decorated_class';
|
||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||
import {isDefined} from '../utils';
|
||||
|
||||
@ -26,7 +26,10 @@ export interface AnalyzedFile {
|
||||
analyzedClasses: AnalyzedClass[];
|
||||
}
|
||||
|
||||
export interface AnalyzedClass extends DecoratedClass {
|
||||
export interface AnalyzedClass {
|
||||
name: string;
|
||||
decorators: Decorator[]|null;
|
||||
declaration: ClassDeclaration;
|
||||
diagnostics?: ts.Diagnostic[];
|
||||
matches: {handler: DecoratorHandler<any, any>; analysis: any;}[];
|
||||
}
|
||||
@ -133,19 +136,18 @@ export class DecorationAnalyzer {
|
||||
}
|
||||
|
||||
protected analyzeFile(sourceFile: ts.SourceFile): AnalyzedFile|undefined {
|
||||
const decoratedClasses = this.reflectionHost.findDecoratedClasses(sourceFile);
|
||||
return decoratedClasses.length ? {
|
||||
sourceFile,
|
||||
analyzedClasses: decoratedClasses.map(clazz => this.analyzeClass(clazz)).filter(isDefined)
|
||||
} :
|
||||
undefined;
|
||||
const analyzedClasses = this.reflectionHost.findClassSymbols(sourceFile)
|
||||
.map(symbol => this.analyzeClass(symbol))
|
||||
.filter(isDefined);
|
||||
return analyzedClasses.length ? {sourceFile, analyzedClasses} : undefined;
|
||||
}
|
||||
|
||||
protected analyzeClass(clazz: DecoratedClass): AnalyzedClass|null {
|
||||
protected analyzeClass(symbol: ClassSymbol): AnalyzedClass|null {
|
||||
const declaration = symbol.valueDeclaration;
|
||||
const decorators = this.reflectionHost.getDecoratorsOfSymbol(symbol);
|
||||
const matchingHandlers = this.handlers
|
||||
.map(handler => {
|
||||
const detected =
|
||||
handler.detect(clazz.declaration, clazz.decorators);
|
||||
const detected = handler.detect(declaration, decorators);
|
||||
return {handler, detected};
|
||||
})
|
||||
.filter(isMatchingHandler);
|
||||
@ -183,13 +185,19 @@ export class DecorationAnalyzer {
|
||||
const matches: {handler: DecoratorHandler<any, any>, analysis: any}[] = [];
|
||||
const allDiagnostics: ts.Diagnostic[] = [];
|
||||
for (const {handler, detected} of detections) {
|
||||
const {analysis, diagnostics} = handler.analyze(clazz.declaration, detected.metadata);
|
||||
const {analysis, diagnostics} = handler.analyze(declaration, detected.metadata);
|
||||
if (diagnostics !== undefined) {
|
||||
allDiagnostics.push(...diagnostics);
|
||||
}
|
||||
matches.push({handler, analysis});
|
||||
}
|
||||
return {...clazz, matches, diagnostics: allDiagnostics.length > 0 ? allDiagnostics : undefined};
|
||||
return {
|
||||
name: symbol.name,
|
||||
declaration,
|
||||
decorators,
|
||||
matches,
|
||||
diagnostics: allDiagnostics.length > 0 ? allDiagnostics : undefined
|
||||
};
|
||||
}
|
||||
|
||||
protected compileFile(analyzedFile: AnalyzedFile): CompiledFile {
|
||||
|
Reference in New Issue
Block a user