feat(ivy): generate ɵɵpropertyInterpolateX instructions (#30008)

- Compiler now generates `ɵɵpropertyInterpolateX` instructions.

PR Close #30008
This commit is contained in:
Ben Lesh 2019-04-20 18:05:46 -07:00
parent 0cab43785b
commit 0bcb2320ba
9 changed files with 188 additions and 13 deletions

View File

@ -117,7 +117,7 @@ describe('compiler compliance: bindings', () => {
}
if (rf & 2) {
$i0$.ɵɵselect(0);
$i0$.ɵɵelementProperty(0, "title", $i0$.ɵɵinterpolation1("Hello ", $ctx$.name, ""));
$i0$.ɵɵpropertyInterpolate1("title", "Hello ", $ctx$.name, "");
}
}`;
const result = compile(files, angularFiles);
@ -452,6 +452,50 @@ describe('compiler compliance: bindings', () => {
}
});
it('should generate the proper update instructions for interpolated properties', () => {
const files: MockDirectory = getAppFiles(`
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f"></div>
<div title="a{{one}}b{{two}}c{{three}}d{{four}}e"></div>
<div title="a{{one}}b{{two}}c{{three}}d"></div>
<div title="a{{one}}b{{two}}c"></div>
<div title="a{{one}}b"></div>
<div title="{{one}}"></div>
`);
const template = `
if (rf & 2) {
i0.ɵɵselect(0);
i0.ɵɵpropertyInterpolateV("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.ɵɵpropertyInterpolate8("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.ɵɵpropertyInterpolate7("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.ɵɵpropertyInterpolate6("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g");
i0.ɵɵselect(4);
i0.ɵɵpropertyInterpolate5("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f");
i0.ɵɵselect(5);
i0.ɵɵpropertyInterpolate4("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e");
i0.ɵɵselect(6);
i0.ɵɵpropertyInterpolate3("title", "a", ctx.one, "b", ctx.two, "c", ctx.three, "d");
i0.ɵɵselect(7);
i0.ɵɵpropertyInterpolate2("title", "a", ctx.one, "b", ctx.two, "c");
i0.ɵɵselect(8);
i0.ɵɵpropertyInterpolate1("title", "a", ctx.one, "b");
i0.ɵɵselect(9);
i0.ɵɵpropertyInterpolate("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

@ -74,7 +74,7 @@ describe('template source-mapping', () => {
});
expect(mappings).toContain({
source: 'id="{{name}}"',
generated: 'i0.ɵɵelementProperty(0, "id", i0.ɵɵinterpolation1("", ctx.name, ""))',
generated: 'i0.ɵɵpropertyInterpolate("id", ctx.name)',
sourceUrl: '../test.ts'
});
});

View File

@ -125,6 +125,27 @@ export class Identifiers {
static property: o.ExternalReference = {name: 'ɵɵproperty', moduleName: CORE};
static propertyInterpolate:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate', moduleName: CORE};
static propertyInterpolate1:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate1', moduleName: CORE};
static propertyInterpolate2:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate2', moduleName: CORE};
static propertyInterpolate3:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate3', moduleName: CORE};
static propertyInterpolate4:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate4', moduleName: CORE};
static propertyInterpolate5:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate5', moduleName: CORE};
static propertyInterpolate6:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate6', moduleName: CORE};
static propertyInterpolate7:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate7', moduleName: CORE};
static propertyInterpolate8:
o.ExternalReference = {name: 'ɵɵpropertyInterpolate8', moduleName: CORE};
static propertyInterpolateV:
o.ExternalReference = {name: 'ɵɵpropertyInterpolateV', moduleName: CORE};
static i18n: o.ExternalReference = {name: 'ɵɵi18n', moduleName: CORE};
static i18nAttributes: o.ExternalReference = {name: 'ɵɵi18nAttributes', moduleName: CORE};
static i18nExp: o.ExternalReference = {name: 'ɵɵi18nExp', moduleName: CORE};

View File

@ -746,20 +746,37 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
this.allocateBindingSlots(value);
if (inputType === BindingType.Property && !(value instanceof Interpolation)) {
if (inputType === BindingType.Property) {
if (value instanceof Interpolation) {
// Interpolated properties
const {currValExpr} = convertPropertyBinding(
this, implicit, value, this.bindingContext(), BindingForm.TrySimple);
let args: o.Expression[] = (currValExpr as any).args;
args.shift(); // ViewEngine required a count, we don't need that.
// For interpolations like attr="{{foo}}", we don't need ["", foo, ""], just [foo].
if (args.length === 3 && isEmptyStringExpression(args[0]) &&
isEmptyStringExpression(args[2])) {
args = [args[1]];
}
this.updateInstruction(
elementIndex, input.sourceSpan, propertyInterpolate(args.length), () => {
return [o.literal(attrName), ...args, ...params];
});
} else {
// Bound, un-interpolated properties
this.updateInstruction(elementIndex, input.sourceSpan, R3.property, () => {
return [
o.literal(attrName), this.convertPropertyBinding(implicit, value, true), ...params
];
});
}
} else {
let instruction: any;
if (inputType === BindingType.Property) {
// Interpolated properties
instruction = R3.elementProperty;
} else if (inputType === BindingType.Class) {
if (inputType === BindingType.Class) {
instruction = R3.elementClassProp;
} else {
instruction = R3.elementAttribute;
@ -1627,6 +1644,39 @@ function interpolate(args: o.Expression[]): o.Expression {
return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]);
}
function isEmptyStringExpression(exp: o.Expression) {
return exp instanceof o.LiteralExpr && exp.value === '';
}
function propertyInterpolate(argsLength: number) {
if (argsLength % 2 !== 1) {
error(`Invalid propertyInterpolate argument length ${argsLength}`);
}
switch (argsLength) {
case 1:
return R3.propertyInterpolate;
case 3:
return R3.propertyInterpolate1;
case 5:
return R3.propertyInterpolate2;
case 7:
return R3.propertyInterpolate3;
case 9:
return R3.propertyInterpolate4;
case 11:
return R3.propertyInterpolate5;
case 13:
return R3.propertyInterpolate6;
case 15:
return R3.propertyInterpolate7;
case 17:
return R3.propertyInterpolate8;
default:
return R3.propertyInterpolateV;
}
}
/**
* Options that can be used to modify how a template is parsed by `parseTemplate()`.
*/

View File

@ -90,6 +90,16 @@ export {
ɵɵelementEnd,
ɵɵelementProperty,
ɵɵproperty,
ɵɵpropertyInterpolate,
ɵɵpropertyInterpolate1,
ɵɵpropertyInterpolate2,
ɵɵpropertyInterpolate3,
ɵɵpropertyInterpolate4,
ɵɵpropertyInterpolate5,
ɵɵpropertyInterpolate6,
ɵɵpropertyInterpolate7,
ɵɵpropertyInterpolate8,
ɵɵpropertyInterpolateV,
ɵɵcomponentHostSyntheticProperty,
ɵɵcomponentHostSyntheticListener,
ɵɵprojectionDef,

View File

@ -81,6 +81,16 @@ export {
ɵɵprojection,
ɵɵprojectionDef,
ɵɵproperty,
ɵɵpropertyInterpolate,
ɵɵpropertyInterpolate1,
ɵɵpropertyInterpolate2,
ɵɵpropertyInterpolate3,
ɵɵpropertyInterpolate4,
ɵɵpropertyInterpolate5,
ɵɵpropertyInterpolate6,
ɵɵpropertyInterpolate7,
ɵɵpropertyInterpolate8,
ɵɵpropertyInterpolateV,
ɵɵreference,

View File

@ -322,6 +322,7 @@ const EMPTY_STRING = '';
* @param v0 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009 {
ɵɵpropertyInterpolate1(propName, EMPTY_STRING, v0, EMPTY_STRING);
@ -354,6 +355,7 @@ export function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue
* @param v0 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate1(
propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009 {
@ -389,6 +391,7 @@ export function ɵɵpropertyInterpolate1(
* @param v1 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate2(
propName: string, prefix: string, v0: any, i0: string, v1: any,
@ -428,6 +431,7 @@ export function ɵɵpropertyInterpolate2(
* @param v2 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate3(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
@ -469,6 +473,7 @@ export function ɵɵpropertyInterpolate3(
* @param v3 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate4(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
@ -513,6 +518,7 @@ export function ɵɵpropertyInterpolate4(
* @param v4 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate5(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
@ -559,6 +565,7 @@ export function ɵɵpropertyInterpolate5(
* @param v5 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate6(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
@ -608,6 +615,7 @@ export function ɵɵpropertyInterpolate6(
* @param v6 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate7(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
@ -660,6 +668,7 @@ export function ɵɵpropertyInterpolate7(
* @param v7 Value checked for change.
* @param suffix Static value used for concatenation only.
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolate8(
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
@ -699,6 +708,7 @@ export function ɵɵpropertyInterpolate8(
* string prefix and ending with a string suffix.
* (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
* @returns itself, so that it may be chained.
* @codeGenApi
*/
export function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009 {
const index = getSelectedIndex();

View File

@ -86,6 +86,16 @@ export const angularCoreEnv: {[name: string]: Function} = {
'ɵɵpipeBindV': r3.ɵɵpipeBindV,
'ɵɵprojectionDef': r3.ɵɵprojectionDef,
'ɵɵproperty': r3.ɵɵproperty,
'ɵɵpropertyInterpolate': r3.ɵɵpropertyInterpolate,
'ɵɵpropertyInterpolate1': r3.ɵɵpropertyInterpolate1,
'ɵɵpropertyInterpolate2': r3.ɵɵpropertyInterpolate2,
'ɵɵpropertyInterpolate3': r3.ɵɵpropertyInterpolate3,
'ɵɵpropertyInterpolate4': r3.ɵɵpropertyInterpolate4,
'ɵɵpropertyInterpolate5': r3.ɵɵpropertyInterpolate5,
'ɵɵpropertyInterpolate6': r3.ɵɵpropertyInterpolate6,
'ɵɵpropertyInterpolate7': r3.ɵɵpropertyInterpolate7,
'ɵɵpropertyInterpolate8': r3.ɵɵpropertyInterpolate8,
'ɵɵpropertyInterpolateV': r3.ɵɵpropertyInterpolateV,
'ɵɵpipe': r3.ɵɵpipe,
'ɵɵqueryRefresh': r3.ɵɵqueryRefresh,
'ɵɵviewQuery': r3.ɵɵviewQuery,

View File

@ -939,6 +939,26 @@ export declare function ɵɵprojectionDef(selectors?: CssSelectorList[]): void;
export declare function ɵɵproperty<T>(propName: string, value: T, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate(propName: string, v0: any): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate1(propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate2(propName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate3(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate4(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate5(propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate6(propName: 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): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate7(propName: 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): TsickleIssue1009;
export declare function ɵɵpropertyInterpolate8(propName: 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): TsickleIssue1009;
export declare function ɵɵpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009;
export declare function ɵɵProvidersFeature<T>(providers: Provider[], viewProviders?: Provider[]): (definition: DirectiveDef<T>) => void;
export declare function ɵɵpureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?: any): T;