fix(ivy): host bindings and listeners not being inherited from undecorated classes (#30158)
Fixes `HostBinding` and `HostListener` declarations not being inherited from base classes that don't have an Angular decorator. This PR resolves FW-1275. PR Close #30158
This commit is contained in:

committed by
Andrew Kushnir

parent
164d160b22
commit
68ff2cc323
@ -6,13 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ConstantPool, R3BaseRefMetaData, compileBaseDefFromMetadata} from '@angular/compiler';
|
||||
import {ConstantPool, R3BaseRefMetaData, compileBaseDefFromMetadata, makeBindingParser} from '@angular/compiler';
|
||||
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {ClassDeclaration, ClassMember, Decorator, ReflectionHost} from '../../reflection';
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform';
|
||||
|
||||
import {queriesFromFields} from './directive';
|
||||
import {extractHostBindings, queriesFromFields} from './directive';
|
||||
import {isAngularDecorator} from './util';
|
||||
|
||||
function containsNgTopLevelDecorator(decorators: Decorator[] | null, isCore: boolean): boolean {
|
||||
@ -69,6 +69,12 @@ export class BaseDefDecoratorHandler implements
|
||||
result = result || {};
|
||||
const queries = result.queries = result.queries || [];
|
||||
queries.push({member: property, decorators});
|
||||
} else if (
|
||||
isAngularDecorator(decorator, 'HostBinding', this.isCore) ||
|
||||
isAngularDecorator(decorator, 'HostListener', this.isCore)) {
|
||||
result = result || {};
|
||||
const host = result.host = result.host || [];
|
||||
host.push(property);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -85,7 +91,8 @@ export class BaseDefDecoratorHandler implements
|
||||
|
||||
analyze(node: ClassDeclaration, metadata: R3BaseRefDecoratorDetection):
|
||||
AnalysisOutput<R3BaseRefMetaData> {
|
||||
const analysis: R3BaseRefMetaData = {};
|
||||
const analysis: R3BaseRefMetaData = {name: node.name.text, typeSourceSpan: null !};
|
||||
|
||||
if (metadata.inputs) {
|
||||
const inputs = analysis.inputs = {} as{[key: string]: string | [string, string]};
|
||||
metadata.inputs.forEach(({decorator, property}) => {
|
||||
@ -133,12 +140,17 @@ export class BaseDefDecoratorHandler implements
|
||||
analysis.queries = queriesFromFields(metadata.queries, this.reflector, this.evaluator);
|
||||
}
|
||||
|
||||
if (metadata.host) {
|
||||
analysis.host = extractHostBindings(
|
||||
metadata.host, this.evaluator, this.isCore ? undefined : '@angular/core');
|
||||
}
|
||||
|
||||
return {analysis};
|
||||
}
|
||||
|
||||
compile(node: ClassDeclaration, analysis: R3BaseRefMetaData, pool: ConstantPool):
|
||||
CompileResult[]|CompileResult {
|
||||
const {expression, type} = compileBaseDefFromMetadata(analysis, pool);
|
||||
const {expression, type} = compileBaseDefFromMetadata(analysis, pool, makeBindingParser());
|
||||
|
||||
return {
|
||||
name: 'ngBaseDef',
|
||||
@ -149,8 +161,9 @@ export class BaseDefDecoratorHandler implements
|
||||
}
|
||||
|
||||
export interface R3BaseRefDecoratorDetection {
|
||||
inputs?: Array<{property: ClassMember, decorator: Decorator}>;
|
||||
outputs?: Array<{property: ClassMember, decorator: Decorator}>;
|
||||
inputs?: {property: ClassMember, decorator: Decorator}[];
|
||||
outputs?: {property: ClassMember, decorator: Decorator}[];
|
||||
viewQueries?: {member: ClassMember, decorators: Decorator[]}[];
|
||||
queries?: {member: ClassMember, decorators: Decorator[]}[];
|
||||
host?: ClassMember[];
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ export function extractDirectiveMetadata(
|
||||
throw new Error(`Directive ${clazz.name.text} has no selector, please add it!`);
|
||||
}
|
||||
|
||||
const host = extractHostBindings(directive, decoratedElements, evaluator, coreModule);
|
||||
const host = extractHostBindings(decoratedElements, evaluator, coreModule, directive);
|
||||
|
||||
const providers: Expression|null =
|
||||
directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null;
|
||||
@ -460,11 +460,11 @@ type StringMap<T> = {
|
||||
[key: string]: T;
|
||||
};
|
||||
|
||||
function extractHostBindings(
|
||||
metadata: Map<string, ts.Expression>, members: ClassMember[], evaluator: PartialEvaluator,
|
||||
coreModule: string | undefined): ParsedHostBindings {
|
||||
export function extractHostBindings(
|
||||
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string | undefined,
|
||||
metadata?: Map<string, ts.Expression>): ParsedHostBindings {
|
||||
let hostMetadata: StringMap<string|Expression> = {};
|
||||
if (metadata.has('host')) {
|
||||
if (metadata && metadata.has('host')) {
|
||||
const expr = metadata.get('host') !;
|
||||
const hostMetaMap = evaluator.evaluate(expr);
|
||||
if (!(hostMetaMap instanceof Map)) {
|
||||
@ -501,7 +501,7 @@ function extractHostBindings(
|
||||
throw new FatalDiagnosticError(
|
||||
// TODO: provide more granular diagnostic and output specific host expression that triggered
|
||||
// an error instead of the whole host object
|
||||
ErrorCode.HOST_BINDING_PARSE_ERROR, metadata.get('host') !,
|
||||
ErrorCode.HOST_BINDING_PARSE_ERROR, metadata !.get('host') !,
|
||||
errors.map((error: ParseError) => error.msg).join('\n'));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user