fix(ivy): move HostListeners generation to factory function (#26480)
PR Close #26480
This commit is contained in:

committed by
Matias Niemelä

parent
c0bf222a05
commit
2a869271f6
@ -42,6 +42,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef {
|
||||
type: meta.type,
|
||||
deps: meta.ctorDeps,
|
||||
injectFn: Identifiers.inject,
|
||||
extraStatementFn: null,
|
||||
};
|
||||
|
||||
if (meta.useClass !== undefined) {
|
||||
|
@ -49,6 +49,11 @@ export interface R3ConstructorFactoryMetadata {
|
||||
* function could be different, and other options control how it will be invoked.
|
||||
*/
|
||||
injectFn: o.ExternalReference;
|
||||
|
||||
/**
|
||||
* Function that allows extra statements to be inserted into factory function.
|
||||
*/
|
||||
extraStatementFn: ((instance: o.Expression) => o.Statement[])|null;
|
||||
}
|
||||
|
||||
export enum R3FactoryDelegateType {
|
||||
@ -189,8 +194,7 @@ export function compileFactoryFunction(meta: R3FactoryMetadata):
|
||||
]);
|
||||
|
||||
statements.push(delegateFactoryStmt);
|
||||
const r = makeConditionalFactory(delegateFactory.callFn([]));
|
||||
retExpr = r;
|
||||
retExpr = makeConditionalFactory(delegateFactory.callFn([]));
|
||||
} else if (isDelegatedMetadata(meta)) {
|
||||
// This type is created with a delegated factory. If a type parameter is not specified, call
|
||||
// the factory instead.
|
||||
@ -204,10 +208,22 @@ export function compileFactoryFunction(meta: R3FactoryMetadata):
|
||||
} else if (isExpressionFactoryMetadata(meta)) {
|
||||
// TODO(alxhub): decide whether to lower the value here or in the caller
|
||||
retExpr = makeConditionalFactory(meta.expression);
|
||||
} else if (meta.extraStatementFn) {
|
||||
// if extraStatementsFn is specified and the 'makeConditionalFactory' function
|
||||
// was not invoked, we need to create a reference to the instance, so we can
|
||||
// pass it as an argument to the 'extraStatementFn' function while calling it
|
||||
const variable = o.variable('f');
|
||||
body.push(variable.set(ctorExpr).toDeclStmt());
|
||||
retExpr = variable;
|
||||
} else {
|
||||
retExpr = ctorExpr;
|
||||
}
|
||||
|
||||
if (meta.extraStatementFn) {
|
||||
const extraStmts = meta.extraStatementFn(retExpr);
|
||||
body.push(...extraStmts);
|
||||
}
|
||||
|
||||
return {
|
||||
factory: o.fn(
|
||||
[new o.FnParam('t', o.DYNAMIC_TYPE)], [...body, new o.ReturnStatement(retExpr)],
|
||||
|
@ -102,6 +102,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef {
|
||||
type: meta.type,
|
||||
deps: meta.deps,
|
||||
injectFn: R3.inject,
|
||||
extraStatementFn: null,
|
||||
});
|
||||
const expression = o.importExpr(R3.defineInjector).callFn([mapToMapExpression({
|
||||
factory: result.factory,
|
||||
@ -152,4 +153,4 @@ function accessExportScope(module: o.Expression): o.Expression {
|
||||
function tupleTypeOf(exp: R3Reference[]): o.Type {
|
||||
const types = exp.map(ref => o.typeofExpr(ref.type));
|
||||
return exp.length > 0 ? o.expressionType(o.literalArr(types)) : o.NONE_TYPE;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) {
|
||||
type: metadata.type,
|
||||
deps: metadata.deps,
|
||||
injectFn: R3.directiveInject,
|
||||
extraStatementFn: null,
|
||||
});
|
||||
definitionMapValues.push({key: 'factory', value: templateFactory.factory, quoted: false});
|
||||
|
||||
|
@ -12,6 +12,7 @@ import {CompileReflector} from '../../compile_reflector';
|
||||
import {BindingForm, convertActionBinding, convertPropertyBinding} from '../../compiler_util/expression_converter';
|
||||
import {ConstantPool, DefinitionKind} from '../../constant_pool';
|
||||
import * as core from '../../core';
|
||||
import {ParsedEvent} from '../../expression_parser/ast';
|
||||
import {LifecycleHooks} from '../../lifecycle_reflector';
|
||||
import * as o from '../../output/output_ast';
|
||||
import {typeSourceSpan} from '../../parse_util';
|
||||
@ -49,6 +50,7 @@ function baseDirectiveFields(
|
||||
type: meta.type,
|
||||
deps: meta.deps,
|
||||
injectFn: R3.directiveInject,
|
||||
extraStatementFn: createFactoryExtraStatementsFn(meta, bindingParser)
|
||||
});
|
||||
definitionMap.set('factory', result.factory);
|
||||
|
||||
@ -634,26 +636,6 @@ function createHostBindingsFunction(
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate host event bindings
|
||||
const eventBindings =
|
||||
bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
|
||||
if (eventBindings) {
|
||||
for (const binding of eventBindings) {
|
||||
const bindingExpr = convertActionBinding(
|
||||
null, bindingContext, binding.handler, 'b', () => error('Unexpected interpolation'));
|
||||
const bindingName = binding.name && sanitizeIdentifier(binding.name);
|
||||
const typeName = meta.name;
|
||||
const functionName =
|
||||
typeName && bindingName ? `${typeName}_${bindingName}_HostBindingHandler` : null;
|
||||
const handler = o.fn(
|
||||
[new o.FnParam('$event', o.DYNAMIC_TYPE)],
|
||||
[...bindingExpr.stmts, new o.ReturnStatement(bindingExpr.allowDefault)], o.INFERRED_TYPE,
|
||||
null, functionName);
|
||||
statements.push(
|
||||
o.importExpr(R3.listener).callFn([o.literal(binding.name), handler]).toStmt());
|
||||
}
|
||||
}
|
||||
|
||||
if (statements.length > 0) {
|
||||
const typeName = meta.name;
|
||||
return o.fn(
|
||||
@ -667,6 +649,32 @@ function createHostBindingsFunction(
|
||||
return null;
|
||||
}
|
||||
|
||||
function createFactoryExtraStatementsFn(meta: R3DirectiveMetadata, bindingParser: BindingParser):
|
||||
((instance: o.Expression) => o.Statement[])|null {
|
||||
const eventBindings =
|
||||
bindingParser.createDirectiveHostEventAsts(metadataAsSummary(meta), meta.typeSourceSpan);
|
||||
return eventBindings && eventBindings.length ?
|
||||
(instance: o.Expression) => createHostListeners(instance, eventBindings, meta) :
|
||||
null;
|
||||
}
|
||||
|
||||
function createHostListeners(
|
||||
bindingContext: o.Expression, eventBindings: ParsedEvent[],
|
||||
meta: R3DirectiveMetadata): o.Statement[] {
|
||||
return eventBindings.map(binding => {
|
||||
const bindingExpr = convertActionBinding(
|
||||
null, bindingContext, binding.handler, 'b', () => error('Unexpected interpolation'));
|
||||
const bindingName = binding.name && sanitizeIdentifier(binding.name);
|
||||
const typeName = meta.name;
|
||||
const functionName =
|
||||
typeName && bindingName ? `${typeName}_${bindingName}_HostBindingHandler` : null;
|
||||
const handler = o.fn(
|
||||
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...bindingExpr.render3Stmts], o.INFERRED_TYPE,
|
||||
null, functionName);
|
||||
return o.importExpr(R3.listener).callFn([o.literal(binding.name), handler]).toStmt();
|
||||
});
|
||||
}
|
||||
|
||||
function metadataAsSummary(meta: R3DirectiveMetadata): CompileDirectiveSummary {
|
||||
// clang-format off
|
||||
return {
|
||||
|
Reference in New Issue
Block a user