refactor(compiler): Host attribute bindings should always be extracted into hostAttrs (#53574)

Host attribute literal bindings should not result in an `attribute` update instruction.

PR Close #53574
This commit is contained in:
Dylan Hunn
2023-12-14 15:43:18 -08:00
committed by Jessica Janiuk
parent 3fa2b10be7
commit bf21792ca1
4 changed files with 11 additions and 16 deletions
@@ -362,7 +362,6 @@
"files": [
{
"expected": "host_with_ts_expression_node_template.js",
"templatePipelineExpected": "host_with_ts_expression_node_template.pipeline.js",
"generated": "host_with_ts_expression_node.js"
}
]
@@ -1,5 +0,0 @@
function MyComponent_HostBindings(rf, ctx) {
if (rf & 2) {
i0.ɵɵattribute("foo", BAR_CONST);
}
}
@@ -78,7 +78,7 @@ export function ingestHostBinding(
.calcPossibleSecurityContexts(
input.componentSelector, property.name, bindingKind === ir.BindingKind.Attribute)
.filter(context => context !== SecurityContext.NONE);
ingestHostProperty(job, property, bindingKind, false, securityContexts);
ingestHostProperty(job, property, bindingKind, securityContexts);
}
for (const [name, expr] of Object.entries(input.attributes) ?? []) {
const securityContexts =
@@ -96,7 +96,7 @@ export function ingestHostBinding(
// with ordinary components. This would allow us to share a lot more ingestion code.
export function ingestHostProperty(
job: HostBindingCompilationJob, property: e.ParsedProperty, bindingKind: ir.BindingKind,
isTextAttribute: boolean, securityContexts: SecurityContext[]): void {
securityContexts: SecurityContext[]): void {
let expression: o.Expression|ir.Interpolation;
const ast = property.expression.ast;
if (ast instanceof e.Interpolation) {
@@ -106,19 +106,20 @@ export function ingestHostProperty(
expression = convertAst(ast, job, property.sourceSpan);
}
job.root.update.push(ir.createBindingOp(
job.root.xref, bindingKind, property.name, expression, null, securityContexts,
isTextAttribute, false, null, /* TODO: How do Host bindings handle i18n attrs? */ null,
property.sourceSpan));
job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false,
null, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
}
export function ingestHostAttribute(
job: HostBindingCompilationJob, name: string, value: o.Expression,
securityContexts: SecurityContext[]): void {
const attrBinding = ir.createBindingOp(
job.root.xref, ir.BindingKind.Attribute, name, value, null, securityContexts, true, false,
null,
job.root.xref, ir.BindingKind.Attribute, name, value, null, securityContexts,
/* Host attributes should always be extracted to const hostAttrs, even if they are not
*strictly* text literals */
true, false, null,
/* TODO */ null,
/* TODO: host attribute source spans */ null!);
/** TODO: May be null? */ value.sourceSpan!);
job.root.update.push(attrBinding);
}
@@ -106,10 +106,10 @@ function extractAttributeOp(
return;
}
let extractable = op.expression.isConstant();
let extractable = op.isTextAttribute || op.expression.isConstant();
if (unit.job.compatibility === ir.CompatibilityMode.TemplateDefinitionBuilder) {
// TemplateDefinitionBuilder only extracted attributes that were string literals.
extractable = ir.isStringLiteral(op.expression);
extractable = op.isTextAttribute || ir.isStringLiteral(op.expression);
if (op.name === 'style' || op.name === 'class') {
// For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
// text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a