feat(ivy): render flags support in host bindings function (FW-649) (#27204)

PR Close #27204
This commit is contained in:
Andrew Kushnir
2018-11-20 15:20:19 -08:00
committed by Misko Hevery
parent bf71b107b3
commit dc300c5c41
21 changed files with 334 additions and 248 deletions

View File

@ -49,11 +49,6 @@ 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 {
@ -208,22 +203,10 @@ 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)],

View File

@ -101,7 +101,6 @@ 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,

View File

@ -43,7 +43,6 @@ 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});

View File

@ -55,7 +55,6 @@ function baseDirectiveFields(
type: meta.type,
deps: meta.deps,
injectFn: R3.directiveInject,
extraStatementFn: createFactoryExtraStatementsFn(meta, bindingParser)
});
definitionMap.set('factory', result.factory);
@ -67,8 +66,8 @@ function baseDirectiveFields(
let hostVars = Object.keys(meta.host.properties).length;
const elVarExp = o.variable('elIndex');
const dirVarExp = o.variable('dirIndex');
const styleBuilder = new StylingBuilder(elVarExp, dirVarExp);
const contextVarExp = o.variable(CONTEXT_NAME);
const styleBuilder = new StylingBuilder(elVarExp, contextVarExp);
const allOtherAttributes: any = {};
const attrNames = Object.getOwnPropertyNames(meta.host.attributes);
@ -93,15 +92,15 @@ function baseDirectiveFields(
// e.g. `attributes: ['role', 'listbox']`
definitionMap.set('attributes', createHostAttributesArray(allOtherAttributes));
// e.g. `hostBindings: (dirIndex, elIndex) => { ... }
// e.g. `hostBindings: (rf, ctx, elIndex) => { ... }
definitionMap.set(
'hostBindings',
createHostBindingsFunction(
meta, elVarExp, dirVarExp, styleBuilder, bindingParser, constantPool, (slots: number) => {
const originalSlots = hostVars;
hostVars += slots;
return originalSlots;
}));
'hostBindings', createHostBindingsFunction(
meta, elVarExp, contextVarExp, styleBuilder, bindingParser, constantPool,
(slots: number) => {
const originalSlots = hostVars;
hostVars += slots;
return originalSlots;
}));
if (hostVars) {
// e.g. `hostVars: 2
@ -643,18 +642,26 @@ function createViewQueriesFunction(
// Return a host binding function or null if one is not necessary.
function createHostBindingsFunction(
meta: R3DirectiveMetadata, elVarExp: o.ReadVarExpr, dirVarExp: o.ReadVarExpr,
meta: R3DirectiveMetadata, elVarExp: o.ReadVarExpr, bindingContext: o.ReadVarExpr,
styleBuilder: StylingBuilder, bindingParser: BindingParser, constantPool: ConstantPool,
allocatePureFunctionSlots: (slots: number) => number): o.Expression|null {
const statements: o.Statement[] = [];
const createStatements: o.Statement[] = [];
const updateStatements: o.Statement[] = [];
const hostBindingSourceSpan = meta.typeSourceSpan;
const directiveSummary = metadataAsSummary(meta);
// Calculate host event bindings
const eventBindings =
bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan);
if (eventBindings && eventBindings.length) {
const listeners = createHostListeners(bindingContext, eventBindings, meta);
createStatements.push(...listeners);
}
// Calculate the host property bindings
const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan);
const bindingContext = o.importExpr(R3.load).callFn([dirVarExp]);
const bindingFn = (implicit: any, value: AST) => {
return convertPropertyBinding(
@ -683,14 +690,14 @@ function createHostBindingsFunction(
const {bindingName, instruction} = getBindingNameAndInstruction(name);
statements.push(...bindingExpr.stmts);
statements.push(o.importExpr(instruction)
.callFn([
elVarExp,
o.literal(bindingName),
o.importExpr(R3.bind).callFn([bindingExpr.currValExpr]),
])
.toStmt());
updateStatements.push(...bindingExpr.stmts);
updateStatements.push(o.importExpr(instruction)
.callFn([
elVarExp,
o.literal(bindingName),
o.importExpr(R3.bind).callFn([bindingExpr.currValExpr]),
])
.toStmt());
}
}
@ -698,24 +705,31 @@ function createHostBindingsFunction(
const createInstruction = styleBuilder.buildCreateLevelInstruction(null, constantPool);
if (createInstruction) {
const createStmt = createStylingStmt(createInstruction, bindingContext, bindingFn);
statements.push(createStmt);
createStatements.push(createStmt);
}
styleBuilder.buildUpdateLevelInstructions(valueConverter).forEach(instruction => {
const updateStmt = createStylingStmt(instruction, bindingContext, bindingFn);
statements.push(updateStmt);
updateStatements.push(updateStmt);
});
}
}
if (statements.length > 0) {
const typeName = meta.name;
if (createStatements.length > 0 || updateStatements.length > 0) {
const hostBindingsFnName = meta.name ? `${meta.name}_HostBindings` : null;
const statements: o.Statement[] = [];
if (createStatements.length > 0) {
statements.push(renderFlagCheckIfStmt(core.RenderFlags.Create, createStatements));
}
if (updateStatements.length > 0) {
statements.push(renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements));
}
return o.fn(
[
new o.FnParam(dirVarExp.name !, o.NUMBER_TYPE),
new o.FnParam(elVarExp.name !, o.NUMBER_TYPE),
new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null),
new o.FnParam(elVarExp.name !, o.NUMBER_TYPE)
],
statements, o.INFERRED_TYPE, null, typeName ? `${typeName}_HostBindings` : null);
statements, o.INFERRED_TYPE, null, hostBindingsFnName);
}
return null;
@ -745,15 +759,6 @@ function getBindingNameAndInstruction(bindingName: string):
return {bindingName, instruction};
}
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[] {

View File

@ -80,8 +80,7 @@ export class StylingBuilder {
private _useDefaultSanitizer = false;
private _applyFnRequired = false;
constructor(
private _elementIndexExpr: o.Expression, private _directiveIndexExpr: o.Expression|null) {}
constructor(private _elementIndexExpr: o.Expression, private _directiveExpr: o.Expression|null) {}
registerBoundInput(input: t.BoundAttribute): boolean {
// [attr.style] or [attr.class] are skipped in the code below,
@ -217,15 +216,15 @@ export class StylingBuilder {
// can be processed during runtime. These initial styles values are bound to
// a constant because the inital style values do not change (since they're static).
params.push(constantPool.getConstLiteral(initialStyles, true));
} else if (useSanitizer || this._directiveIndexExpr) {
} else if (useSanitizer || this._directiveExpr) {
// no point in having an extra `null` value unless there are follow-up params
params.push(o.NULL_EXPR);
}
if (useSanitizer || this._directiveIndexExpr) {
if (useSanitizer || this._directiveExpr) {
params.push(useSanitizer ? o.importExpr(R3.defaultStyleSanitizer) : o.NULL_EXPR);
if (this._directiveIndexExpr) {
params.push(this._directiveIndexExpr);
if (this._directiveExpr) {
params.push(this._directiveExpr);
}
}
@ -260,12 +259,12 @@ export class StylingBuilder {
if (mapBasedStyleValue) {
params.push(convertFn(mapBasedStyleValue));
} else if (this._directiveIndexExpr) {
} else if (this._directiveExpr) {
params.push(o.NULL_EXPR);
}
if (this._directiveIndexExpr) {
params.push(this._directiveIndexExpr);
if (this._directiveExpr) {
params.push(this._directiveExpr);
}
return params;
@ -289,13 +288,13 @@ export class StylingBuilder {
if (allowUnits) {
if (input.unit) {
params.push(o.literal(input.unit));
} else if (this._directiveIndexExpr) {
} else if (this._directiveExpr) {
params.push(o.NULL_EXPR);
}
}
if (this._directiveIndexExpr) {
params.push(this._directiveIndexExpr);
if (this._directiveExpr) {
params.push(this._directiveExpr);
}
return params;
}
@ -325,8 +324,8 @@ export class StylingBuilder {
reference: R3.elementStylingApply,
buildParams: () => {
const params: o.Expression[] = [this._elementIndexExpr];
if (this._directiveIndexExpr) {
params.push(this._directiveIndexExpr);
if (this._directiveExpr) {
params.push(this._directiveExpr);
}
return params;
}