refactor(ivy): add new attribute interpolation instructions (#30503)

PR Close #30503
This commit is contained in:
Ben Lesh
2019-05-15 19:53:13 -07:00
committed by Jason Aden
parent 38d7acee4d
commit 7555a46e23
8 changed files with 939 additions and 6 deletions

View File

@ -496,6 +496,51 @@ describe('compiler compliance: bindings', () => {
expectEmit(result.source, template, 'Incorrect handling of interpolated properties');
});
it('should generate the proper update instructions for interpolated attributes', () => {
const files: MockDirectory = getAppFiles(`
<div attr.title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j"></div>
<div attr.title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i"></div>
<div attr.title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h"></div>
<div attr.title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g"></div>
<div attr.title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f"></div>
<div attr.title="a{{one}}b{{two}}c{{three}}d{{four}}e"></div>
<div attr.title="a{{one}}b{{two}}c{{three}}d"></div>
<div attr.title="a{{one}}b{{two}}c"></div>
<div attr.title="a{{one}}b"></div>
<div attr.title="{{one}}"></div>
`);
const template = `
if (rf & 2) {
i0.Δselect(0);
i0.ΔattributeInterpolateV("title", ["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]);
i0.Δselect(1);
i0.ΔattributeInterpolate8("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i");
i0.Δselect(2);
i0.ΔattributeInterpolate7("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h");
i0.Δselect(3);
i0.ΔattributeInterpolate6("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g");
i0.Δselect(4);
i0.ΔattributeInterpolate5("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f");
i0.Δselect(5);
i0.ΔattributeInterpolate4("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e");
i0.Δselect(6);
i0.ΔattributeInterpolate3("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d");
i0.Δselect(7);
i0.ΔattributeInterpolate2("title", "a", ctx.one, "b", ctx.two, "c");
i0.Δselect(8);
i0.ΔattributeInterpolate1("title", "a", ctx.one, "b");
i0.Δselect(9);
i0.ΔattributeInterpolate("title", ctx.one);
}
`;
const result = compile(files, angularFiles);
expectEmit(result.source, template, 'Incorrect handling of interpolated properties');
});
it('should keep local ref for host element', () => {
const files: MockDirectory = getAppFiles(`
<b ngNonBindable #myRef id="my-id">

View File

@ -43,6 +43,27 @@ export class Identifiers {
static attribute: o.ExternalReference = {name: 'ɵɵattribute', moduleName: CORE};
static attributeInterpolate:
o.ExternalReference = {name: 'ɵɵattributeInterpolate', moduleName: CORE};
static attributeInterpolate1:
o.ExternalReference = {name: 'ɵɵattributeInterpolate1', moduleName: CORE};
static attributeInterpolate2:
o.ExternalReference = {name: 'ɵɵattributeInterpolate2', moduleName: CORE};
static attributeInterpolate3:
o.ExternalReference = {name: 'ɵɵattributeInterpolate3', moduleName: CORE};
static attributeInterpolate4:
o.ExternalReference = {name: 'ɵɵattributeInterpolate4', moduleName: CORE};
static attributeInterpolate5:
o.ExternalReference = {name: 'ɵɵattributeInterpolate5', moduleName: CORE};
static attributeInterpolate6:
o.ExternalReference = {name: 'ɵɵattributeInterpolate6', moduleName: CORE};
static attributeInterpolate7:
o.ExternalReference = {name: 'ɵɵattributeInterpolate7', moduleName: CORE};
static attributeInterpolate8:
o.ExternalReference = {name: 'ɵɵattributeInterpolate8', moduleName: CORE};
static attributeInterpolateV:
o.ExternalReference = {name: 'ɵɵattributeInterpolateV', moduleName: CORE};
static classProp: o.ExternalReference = {name: 'ɵɵclassProp', moduleName: CORE};
static elementContainerStart:

View File

@ -772,12 +772,12 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
} else if (inputType === BindingType.Attribute) {
if (value instanceof Interpolation) {
// attr.name="{{value}}" and friends
this.updateInstruction(elementIndex, input.sourceSpan, R3.elementAttribute, () => {
return [
o.literal(elementIndex), o.literal(attrName),
this.convertPropertyBinding(implicit, value), ...params
];
});
this.updateInstruction(
elementIndex, input.sourceSpan, getAttributeInterpolationExpression(value),
() =>
[o.literal(attrName),
...this.getUpdateInstructionArguments(o.variable(CONTEXT_NAME), value),
...params]);
} else {
// [attr.name]="value"
this.updateInstruction(elementIndex, input.sourceSpan, R3.attribute, () => {
@ -1695,6 +1695,35 @@ function getPropertyInterpolationExpression(interpolation: Interpolation) {
}
}
/**
* Gets the instruction to generate for an interpolated attribute
* @param interpolation An Interpolation AST
*/
function getAttributeInterpolationExpression(interpolation: Interpolation) {
switch (getInterpolationArgsLength(interpolation)) {
case 1:
return R3.attributeInterpolate;
case 3:
return R3.attributeInterpolate1;
case 5:
return R3.attributeInterpolate2;
case 7:
return R3.attributeInterpolate3;
case 9:
return R3.attributeInterpolate4;
case 11:
return R3.attributeInterpolate5;
case 13:
return R3.attributeInterpolate6;
case 15:
return R3.attributeInterpolate7;
case 17:
return R3.attributeInterpolate8;
default:
return R3.attributeInterpolateV;
}
}
/**
* Gets the number of arguments expected to be passed to a generated instruction in the case of
* interpolation instructions.

View File

@ -9,6 +9,16 @@
// clang-format off
export {
ɵɵattribute,
ɵɵattributeInterpolate,
ɵɵattributeInterpolate1,
ɵɵattributeInterpolate2,
ɵɵattributeInterpolate3,
ɵɵattributeInterpolate4,
ɵɵattributeInterpolate5,
ɵɵattributeInterpolate6,
ɵɵattributeInterpolate7,
ɵɵattributeInterpolate8,
ɵɵattributeInterpolateV,
ɵɵdefineBase,
ɵɵdefineComponent,
ɵɵdefineDirective,

View File

@ -23,7 +23,19 @@ export {
tick,
ɵɵallocHostVars,
ɵɵattribute,
ɵɵattributeInterpolate,
ɵɵattributeInterpolate1,
ɵɵattributeInterpolate2,
ɵɵattributeInterpolate3,
ɵɵattributeInterpolate4,
ɵɵattributeInterpolate5,
ɵɵattributeInterpolate6,
ɵɵattributeInterpolate7,
ɵɵattributeInterpolate8,
ɵɵattributeInterpolateV,
ɵɵbind,
ɵɵclassMap,
ɵɵclassProp,

View File

@ -27,6 +27,7 @@
*/
export * from './alloc_host_vars';
export * from './attribute';
export * from './attribute_interpolation';
export * from './change_detection';
export * from './container';
export * from './storage';

View File

@ -0,0 +1,413 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {SanitizerFn} from '../interfaces/sanitization';
import {getSelectedIndex} from '../state';
import {ΔelementAttribute} from './element';
import {Δinterpolation1, Δinterpolation2, Δinterpolation3, Δinterpolation4, Δinterpolation5, Δinterpolation6, Δinterpolation7, Δinterpolation8, ΔinterpolationV} from './property_interpolation';
import {TsickleIssue1009} from './shared';
/**
*
* Update an interpolated attribute on an element with a lone bound value
*
* Used when the value passed to a property has 1 interpolated value in it, an no additional text
* surrounds that interpolated value:
*
* ```html
* <div attr.title="{{v0}}"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate('title', v0);
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate(
attrName: string, v0: any, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
ΔattributeInterpolate1(attrName, '', v0, '', sanitizer);
return ΔattributeInterpolate;
}
/**
*
* Update an interpolated attribute on an element with single bound value surrounded by text.
*
* Used when the value passed to a property has 1 interpolated value in it:
*
* ```html
* <div attr.title="prefix{{v0}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate1('title', 'prefix', v0, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate1(
attrName: string, prefix: string, v0: any, suffix: string, sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue = Δinterpolation1(prefix, v0, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate1;
}
/**
*
* Update an interpolated attribute on an element with 2 bound values surrounded by text.
*
* Used when the value passed to a property has 2 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate2(
attrName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string,
sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue = Δinterpolation2(prefix, v0, i0, v1, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate2;
}
/**
*
* Update an interpolated attribute on an element with 3 bound values surrounded by text.
*
* Used when the value passed to a property has 3 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate3(
* 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param i1 Static value used for concatenation only.
* @param v2 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate3(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue = Δinterpolation3(prefix, v0, i0, v1, i1, v2, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate3;
}
/**
*
* Update an interpolated attribute on an element with 4 bound values surrounded by text.
*
* Used when the value passed to a property has 4 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate4(
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param i1 Static value used for concatenation only.
* @param v2 Value checked for change.
* @param i2 Static value used for concatenation only.
* @param v3 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate4(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue = Δinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate4;
}
/**
*
* Update an interpolated attribute on an element with 5 bound values surrounded by text.
*
* Used when the value passed to a property has 5 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate5(
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param i1 Static value used for concatenation only.
* @param v2 Value checked for change.
* @param i2 Static value used for concatenation only.
* @param v3 Value checked for change.
* @param i3 Static value used for concatenation only.
* @param v4 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate5(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, suffix: string, sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue = Δinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate5;
}
/**
*
* Update an interpolated attribute on an element with 6 bound values surrounded by text.
*
* Used when the value passed to a property has 6 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate6(
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param i1 Static value used for concatenation only.
* @param v2 Value checked for change.
* @param i2 Static value used for concatenation only.
* @param v3 Value checked for change.
* @param i3 Static value used for concatenation only.
* @param v4 Value checked for change.
* @param i4 Static value used for concatenation only.
* @param v5 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate6(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string, sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue =
Δinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate6;
}
/**
*
* Update an interpolated attribute on an element with 7 bound values surrounded by text.
*
* Used when the value passed to a property has 7 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate7(
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param i1 Static value used for concatenation only.
* @param v2 Value checked for change.
* @param i2 Static value used for concatenation only.
* @param v3 Value checked for change.
* @param i3 Static value used for concatenation only.
* @param v4 Value checked for change.
* @param i4 Static value used for concatenation only.
* @param v5 Value checked for change.
* @param i5 Static value used for concatenation only.
* @param v6 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate7(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string,
sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue =
Δinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate7;
}
/**
*
* Update an interpolated attribute on an element with 8 bound values surrounded by text.
*
* Used when the value passed to a property has 8 interpolated values in it:
*
* ```html
* <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolate8(
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
* ```
*
* @param attrName The name of the attribute to update
* @param prefix Static value used for concatenation only.
* @param v0 Value checked for change.
* @param i0 Static value used for concatenation only.
* @param v1 Value checked for change.
* @param i1 Static value used for concatenation only.
* @param v2 Value checked for change.
* @param i2 Static value used for concatenation only.
* @param v3 Value checked for change.
* @param i3 Static value used for concatenation only.
* @param v4 Value checked for change.
* @param i4 Static value used for concatenation only.
* @param v5 Value checked for change.
* @param i5 Static value used for concatenation only.
* @param v6 Value checked for change.
* @param i6 Static value used for concatenation only.
* @param v7 Value checked for change.
* @param suffix Static value used for concatenation only.
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolate8(
attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
const interpolatedValue =
Δinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
ΔelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace);
return ΔattributeInterpolate8;
}
/**
* Update an interpolated attribute on an element with 8 or more bound values surrounded by text.
*
* Used when the number of interpolated values exceeds 7.
*
* ```html
* <div
* title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
* ```
*
* Its compiled representation is::
*
* ```ts
* ΔattributeInterpolateV(
* 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
* 'suffix']);
* ```
*
* @param attrName The name of the attribute to update.
* @param values The a collection of values and the strings in-between those values, beginning with
* a string prefix and ending with a string suffix.
* (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
* @param sanitizer An optional sanitizer function
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ΔattributeInterpolateV(
attrName: string, values: any[], sanitizer?: SanitizerFn,
namespace?: string): TsickleIssue1009 {
const index = getSelectedIndex();
ΔelementAttribute(index, attrName, ΔinterpolationV(values), sanitizer, namespace);
return ΔattributeInterpolateV;
}