From 0bcb2320baf5b854a32342c925e95bce5fd829c4 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Sat, 20 Apr 2019 18:05:46 -0700 Subject: [PATCH] =?UTF-8?q?feat(ivy):=20generate=20=C9=B5=C9=B5propertyInt?= =?UTF-8?q?erpolateX=20instructions=20(#30008)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Compiler now generates `ɵɵpropertyInterpolateX` instructions. PR Close #30008 --- .../r3_view_compiler_binding_spec.ts | 46 +++++++++++- .../test/ngtsc/template_mapping_spec.ts | 2 +- .../compiler/src/render3/r3_identifiers.ts | 21 ++++++ .../compiler/src/render3/view/template.ts | 72 ++++++++++++++++--- .../core/src/core_render3_private_export.ts | 10 +++ packages/core/src/render3/index.ts | 10 +++ .../instructions/property_interpolation.ts | 10 +++ packages/core/src/render3/jit/environment.ts | 10 +++ tools/public_api_guard/core/core.d.ts | 20 ++++++ 9 files changed, 188 insertions(+), 13 deletions(-) diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts index 5d44e679e3..d4bc7e0eb7 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts @@ -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(` +
+
+
+
+
+
+
+
+
+
+ `); + + 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(` diff --git a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts index 1e24656b78..ed1d6cee85 100644 --- a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts @@ -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' }); }); diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index e79dbef840..9f4e612e14 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -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}; diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 6329fb2565..aa8a4a63f3 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -746,20 +746,37 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } this.allocateBindingSlots(value); - if (inputType === BindingType.Property && !(value instanceof Interpolation)) { - // Bound, un-interpolated properties - this.updateInstruction(elementIndex, input.sourceSpan, R3.property, () => { - return [ - o.literal(attrName), this.convertPropertyBinding(implicit, value, true), ...params - ]; - }); + 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()`. */ diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 634120cfa0..fad9dd161f 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -90,6 +90,16 @@ export { ɵɵelementEnd, ɵɵelementProperty, ɵɵproperty, + ɵɵpropertyInterpolate, + ɵɵpropertyInterpolate1, + ɵɵpropertyInterpolate2, + ɵɵpropertyInterpolate3, + ɵɵpropertyInterpolate4, + ɵɵpropertyInterpolate5, + ɵɵpropertyInterpolate6, + ɵɵpropertyInterpolate7, + ɵɵpropertyInterpolate8, + ɵɵpropertyInterpolateV, ɵɵcomponentHostSyntheticProperty, ɵɵcomponentHostSyntheticListener, ɵɵprojectionDef, diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 408f786824..8b7ca59962 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -81,6 +81,16 @@ export { ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, + ɵɵpropertyInterpolate, + ɵɵpropertyInterpolate1, + ɵɵpropertyInterpolate2, + ɵɵpropertyInterpolate3, + ɵɵpropertyInterpolate4, + ɵɵpropertyInterpolate5, + ɵɵpropertyInterpolate6, + ɵɵpropertyInterpolate7, + ɵɵpropertyInterpolate8, + ɵɵpropertyInterpolateV, ɵɵreference, diff --git a/packages/core/src/render3/instructions/property_interpolation.ts b/packages/core/src/render3/instructions/property_interpolation.ts index 959245925a..8204a9c8b4 100644 --- a/packages/core/src/render3/instructions/property_interpolation.ts +++ b/packages/core/src/render3/instructions/property_interpolation.ts @@ -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(); diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 2488ef1991..86454a0514 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -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, diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index ea05de210d..843a68282d 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -939,6 +939,26 @@ export declare function ɵɵprojectionDef(selectors?: CssSelectorList[]): void; export declare function ɵɵproperty(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(providers: Provider[], viewProviders?: Provider[]): (definition: DirectiveDef) => void; export declare function ɵɵpureFunction0(slotOffset: number, pureFn: () => T, thisArg?: any): T;