diff --git a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts
index 58ee02eecd..a20e13174b 100644
--- a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts
+++ b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts
@@ -168,7 +168,7 @@ describe('Renderer', () => {
ɵngcc0.ɵɵtext(0);
} if (rf & 2) {
ɵngcc0.ɵɵselect(0);
- ɵngcc0.ɵɵtextBinding(0, ɵngcc0.ɵɵinterpolation1("", ctx.person.name, ""));
+ ɵngcc0.ɵɵtextInterpolate(ctx.person.name);
} }, encapsulation: 2 });
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
type: Component,
diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
index 998a42e2b1..705b619340 100644
--- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
@@ -810,7 +810,7 @@ describe('compiler compliance', () => {
const $myComp$ = $r3$.ɵɵnextContext();
const $foo$ = $r3$.ɵɵreference(1);
$r3$.ɵɵselect(1);
- $r3$.ɵɵtextBinding(1, $r3$.ɵɵinterpolation2("", $myComp$.salutation, " ", $foo$, ""));
+ $r3$.ɵɵtextInterpolate2("", $myComp$.salutation, " ", $foo$, "");
}
}
…
@@ -2074,9 +2074,9 @@ describe('compiler compliance', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(0);
- $r3$.ɵɵtextBinding(0, $r3$.ɵɵinterpolation1("", $r3$.ɵɵpipeBind2(1, 3, $r3$.ɵɵpipeBind2(2, 6, ctx.name, ctx.size), ctx.size), ""));
+ $r3$.ɵɵtextInterpolate($r3$.ɵɵpipeBind2(1, 3, $r3$.ɵɵpipeBind2(2, 6, ctx.name, ctx.size), ctx.size));
$r3$.ɵɵselect(4);
- $r3$.ɵɵtextBinding(4, $r3$.ɵɵinterpolation2("", $r3$.ɵɵpipeBindV(5, 9, $r3$.ɵɵpureFunction1(18, $c0$, ctx.name)), " ", ctx.name ? 1 : $r3$.ɵɵpipeBind1(6, 16, 2), ""));
+ $r3$.ɵɵtextInterpolate2("", $r3$.ɵɵpipeBindV(5, 9, $r3$.ɵɵpureFunction1(18, $c0$, ctx.name)), " ", ctx.name ? 1 : $r3$.ɵɵpipeBind1(6, 16, 2), "");
}
},
pipes: [MyPurePipe, MyPipe],
@@ -2139,14 +2139,14 @@ describe('compiler compliance', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(0);
- $r3$.ɵɵtextBinding(0, $r3$.ɵɵinterpolation5(
+ $r3$.ɵɵtextInterpolate5(
"0:", i0.ɵɵpipeBind1(1, 5, ctx.name),
"1:", i0.ɵɵpipeBind2(2, 7, ctx.name, 1),
"2:", i0.ɵɵpipeBind3(3, 10, ctx.name, 1, 2),
"3:", i0.ɵɵpipeBind4(4, 14, ctx.name, 1, 2, 3),
"4:", i0.ɵɵpipeBindV(5, 19, $r3$.ɵɵpureFunction1(25, $c0$, ctx.name)),
""
- ));
+ );
}
},
pipes: [MyPipe],
@@ -2192,7 +2192,7 @@ describe('compiler compliance', () => {
if (rf & 2) {
const $user$ = $r3$.ɵɵreference(1);
$r3$.ɵɵselect(2);
- $r3$.ɵɵtextBinding(2, $r3$.ɵɵinterpolation1("Hello ", $user$.value, "!"));
+ $r3$.ɵɵtextInterpolate1("Hello ", $user$.value, "!");
}
},
encapsulation: 2
@@ -2255,7 +2255,7 @@ describe('compiler compliance', () => {
const $foo$ = $r3$.ɵɵreference(1);
const $baz$ = $r3$.ɵɵreference(5);
$r3$.ɵɵselect(1);
- $r3$.ɵɵtextBinding(1, $r3$.ɵɵinterpolation3("", $foo$, "-", $bar$, "-", $baz$, ""));
+ $r3$.ɵɵtextInterpolate3("", $foo$, "-", $bar$, "-", $baz$, "");
}
}
function MyComponent_div_3_Template(rf, ctx) {
@@ -2271,7 +2271,7 @@ describe('compiler compliance', () => {
$r3$.ɵɵnextContext();
const $foo$ = $r3$.ɵɵreference(1);
$r3$.ɵɵselect(1);
- $r3$.ɵɵtextBinding(1, $r3$.ɵɵinterpolation2(" ", $foo$, "-", $bar$, " "));
+ $r3$.ɵɵtextInterpolate2(" ", $foo$, "-", $bar$, " ");
}
}
…
@@ -2291,7 +2291,7 @@ describe('compiler compliance', () => {
if (rf & 2) {
const $foo$ = $r3$.ɵɵreference(1);
$r3$.ɵɵselect(2);
- $r3$.ɵɵtextBinding(2, $r3$.ɵɵinterpolation1(" ", $foo$, " "));
+ $r3$.ɵɵtextInterpolate1(" ", $foo$, " ");
}
},
directives:[IfDirective],
@@ -2300,9 +2300,7 @@ describe('compiler compliance', () => {
const result = compile(files, angularFiles);
const source = result.source;
-
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
-
});
it('should support local refs mixed with context assignments', () => {
@@ -2344,7 +2342,7 @@ describe('compiler compliance', () => {
const $item$ = $i0$.ɵɵnextContext().$implicit;
const $foo$ = $i0$.ɵɵreference(2);
$r3$.ɵɵselect(1);
- $i0$.ɵɵtextBinding(1, $i0$.ɵɵinterpolation2(" ", $foo$, " - ", $item$, " "));
+ $i0$.ɵɵtextInterpolate2(" ", $foo$, " - ", $item$, " ");
}
}
@@ -2648,7 +2646,7 @@ describe('compiler compliance', () => {
if (rf & 2) {
const $item$ = ctx.$implicit;
$r3$.ɵɵselect(1);
- $r3$.ɵɵtextBinding(1, $r3$.ɵɵinterpolation1("", $item$.name, ""));
+ $r3$.ɵɵtextInterpolate($item$.name);
}
}
…
@@ -2731,7 +2729,7 @@ describe('compiler compliance', () => {
const $info$ = ctx.$implicit;
const $item$ = $r3$.ɵɵnextContext().$implicit;
$r3$.ɵɵselect(1);
- $r3$.ɵɵtextBinding(1, $r3$.ɵɵinterpolation2(" ", $item$.name, ": ", $info$.description, " "));
+ $r3$.ɵɵtextInterpolate2(" ", $item$.name, ": ", $info$.description, " ");
}
}
@@ -2749,7 +2747,7 @@ describe('compiler compliance', () => {
if (rf & 2) {
const $item$ = ctx.$implicit;
$r3$.ɵɵselect(2);
- $r3$.ɵɵtextBinding(2, $r3$.ɵɵinterpolation1("", IDENT.name, ""));
+ $r3$.ɵɵtextInterpolate(IDENT.name);
$r3$.ɵɵselect(4);
$r3$.ɵɵproperty("forOf", IDENT.infos);
}
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 93a4a36e0c..025eaada28 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
@@ -45,7 +45,7 @@ describe('compiler compliance: bindings', () => {
}
if (rf & 2) {
$r3$.ɵɵselect(1);
- $i0$.ɵɵtextBinding(1, $i0$.ɵɵinterpolation1("Hello ", $ctx$.name, ""));
+ $i0$.ɵɵtextInterpolate1("Hello ", $ctx$.name, "");
}
}`;
const result = compile(files, angularFiles);
@@ -567,7 +567,7 @@ describe('compiler compliance: bindings', () => {
if (rf & 2) {
const $_r0$ = $i0$.ɵɵreference(1);
$r3$.ɵɵselect(4);
- $i0$.ɵɵtextBinding(4, $i0$.ɵɵinterpolation1(" ", $_r0$.id, " "));
+ $i0$.ɵɵtextInterpolate1(" ", $_r0$.id, " ");
}
}
`;
diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts
index 10dbc48055..57b0e0b71e 100644
--- a/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts
@@ -93,7 +93,7 @@ describe('r3_view_compiler', () => {
describe('interpolations', () => {
// Regression #21927
- it('should generate a correct call to bV with more than 8 interpolations', () => {
+ it('should generate a correct call to textInterpolateV with more than 8 interpolations', () => {
const files: MockDirectory = {
app: {
'example.ts': `
@@ -112,10 +112,19 @@ describe('r3_view_compiler', () => {
}
};
- const bV_call =
- `$r3$.ɵɵinterpolationV([" ",ctx.list[0]," ",ctx.list[1]," ",ctx.list[2]," ",ctx.list[3],
- " ",ctx.list[4]," ",ctx.list[5]," ",ctx.list[6]," ",ctx.list[7]," ",ctx.list[8],
- " "])`;
+ const bV_call = `
+ …
+ function MyApp_Template(rf, ctx) {
+ if (rf & 1) {
+ $i0$.ɵɵtext(0);
+ }
+ if (rf & 2) {
+ $i0$.ɵɵselect(0);
+ $i0$.ɵɵtextInterpolateV([" ", ctx.list[0], " ", ctx.list[1], " ", ctx.list[2], " ", ctx.list[3], " ", ctx.list[4], " ", ctx.list[5], " ", ctx.list[6], " ", ctx.list[7], " ", ctx.list[8], " "]);
+ }
+ }
+ …
+ `;
const result = compile(files, angularFiles);
expectEmit(result.source, bV_call, 'Incorrect bV call');
});
diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts
index 29691ad60f..4a9580256c 100644
--- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts
@@ -999,7 +999,7 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵclassProp(0, $r3$.ɵɵpipeBind2(4, 10, $ctx$.fooExp, 2000));
$r3$.ɵɵstylingApply();
$r3$.ɵɵselect(5);
- $r3$.ɵɵtextBinding(5, $r3$.ɵɵinterpolation1(" ", $ctx$.item, ""));
+ $r3$.ɵɵtextInterpolate1(" ", $ctx$.item, "");
}
}
`;
diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts
index 0ab46c841b..0f54733b7f 100644
--- a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts
@@ -78,7 +78,7 @@ describe('compiler compliance: template', () => {
$i0$.ɵɵselect(0);
$i0$.ɵɵproperty("title", $myComp1$.format($outer1$, $middle1$, $inner1$, $myComp1$.component));
$r3$.ɵɵselect(1);
- $i0$.ɵɵtextBinding(1, $i0$.ɵɵinterpolation1(" ", $myComp1$.format($outer1$, $middle1$, $inner1$, $myComp1$.component), " "));
+ $i0$.ɵɵtextInterpolate1(" ", $myComp1$.format($outer1$, $middle1$, $inner1$, $myComp1$.component), " ");
}
}
@@ -215,7 +215,7 @@ describe('compiler compliance: template', () => {
const $item$ = ctx.$implicit;
const $i$ = ctx.index;
$r3$.ɵɵselect(1);
- $i0$.ɵɵtextBinding(1, $i0$.ɵɵinterpolation2(" ", $i$, " - ", $item$, " "));
+ $i0$.ɵɵtextInterpolate2(" ", $i$, " - ", $item$, " ");
}
}
// ...
@@ -272,7 +272,7 @@ describe('compiler compliance: template', () => {
const $i$ = $div$.index;
const $item$ = $div$.$implicit;
$r3$.ɵɵselect(1);
- $i0$.ɵɵtextBinding(1, $i0$.ɵɵinterpolation2(" ", $i$, " - ", $item$, " "));
+ $i0$.ɵɵtextInterpolate2(" ", $i$, " - ", $item$, " ");
}
}
@@ -343,7 +343,7 @@ describe('compiler compliance: template', () => {
const $middle$ = $i0$.ɵɵnextContext().$implicit;
const $myComp$ = $i0$.ɵɵnextContext(2);
$r3$.ɵɵselect(1);
- $i0$.ɵɵtextBinding(1, $i0$.ɵɵinterpolation2(" ", $middle$.value, " - ", $myComp$.name, " "));
+ $i0$.ɵɵtextInterpolate2(" ", $middle$.value, " - ", $myComp$.name, " ");
}
}
diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
index 1bbcc200f6..a8046c9539 100644
--- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
@@ -1961,7 +1961,7 @@ describe('ngtsc behavioral tests', () => {
env.driveMain();
const jsContents = env.getContents('test.js');
- expect(jsContents).toContain('interpolation1("", ctx.text, "")');
+ expect(jsContents).toContain('ɵɵtextInterpolate(ctx.text)');
});
it('should handle `encapsulation` field', () => {
diff --git a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts
index 135311857d..f8899c36da 100644
--- a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts
@@ -44,7 +44,7 @@ describe('template source-mapping', () => {
{source: '
', generated: 'i0.ɵɵelementStart(0, "h3")', sourceUrl: '../test.ts'});
expect(mappings).toContain({
source: 'Hello {{ name }}',
- generated: 'i0.ɵɵtextBinding(1, i0.ɵɵinterpolation1("Hello ", ctx.name, ""))',
+ generated: 'i0.ɵɵtextInterpolate1("Hello ", ctx.name, "")',
sourceUrl: '../test.ts'
});
expect(mappings).toContain(
@@ -57,8 +57,7 @@ describe('template source-mapping', () => {
{source: '', generated: 'i0.ɵɵelementStart(0, "h2")', sourceUrl: '../test.ts'});
expect(mappings).toContain({
source: '{{ greeting + " " + name }}',
- generated:
- 'i0.ɵɵtextBinding(1, i0.ɵɵinterpolation1("", ctx.greeting + " " + ctx.name, ""))',
+ generated: 'i0.ɵɵtextInterpolate(ctx.greeting + " " + ctx.name)',
sourceUrl: '../test.ts'
});
expect(mappings).toContain(
@@ -85,8 +84,7 @@ describe('template source-mapping', () => {
{source: '
', generated: 'i0.ɵɵelementStart(0, "div")', sourceUrl: '../test.ts'});
expect(mappings).toContain({
source: '{{200.3 | percent : 2 }}',
- generated:
- 'i0.ɵɵtextBinding(1, i0.ɵɵinterpolation1("", i0.ɵɵpipeBind2(2, 1, 200.3, 2), ""))',
+ generated: 'i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(2, 1, 200.3, 2))',
sourceUrl: '../test.ts'
});
expect(mappings).toContain(
@@ -270,7 +268,7 @@ describe('template source-mapping', () => {
// expect(mappings).toContain({
// source: '{{ name }}',
- // generated: 'i0.ɵɵtextBinding(1, i0.ɵɵinterpolation1("", ctx_r0.name, ""))',
+ // generated: 'i0.ɵɵtextInterpolate(ctx_r0.name)',
// sourceUrl: '../test.ts'
// });
});
@@ -294,7 +292,7 @@ describe('template source-mapping', () => {
// expect(mappings).toContain({
// source: '{{ name }}',
- // generated: 'i0.ɵɵtextBinding(1, i0.ɵɵinterpolation1("", ctx_r0.name, ""))',
+ // generated: 'i0.ɵɵtextInterpolate(ctx_r0.name)',
// sourceUrl: '../test.ts'
// });
});
@@ -370,7 +368,7 @@ describe('template source-mapping', () => {
// Update mode
expect(mappings).toContain({
- generated: 'i0.ɵɵtextBinding(3, i0.ɵɵinterpolation1("", 1 + 2, ""))',
+ generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}',
sourceUrl: '../test.ts'
});
@@ -396,9 +394,10 @@ describe('template source-mapping', () => {
expect(mappings).toContain(
{generated: 'i0.ɵɵelementEnd()', source: '
', sourceUrl: '../test.ts'});
+ // TODO(benlesh): We need to circle back and prevent the extra parens from being generated.
// Update mode
expect(mappings).toContain({
- generated: 'i0.ɵɵtextBinding(3, i0.ɵɵinterpolation1("", 1 + 2, ""))',
+ generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}',
sourceUrl: '../test.ts'
});
@@ -452,7 +451,7 @@ describe('template source-mapping', () => {
// Update mode
expect(mappings).toContain({
- generated: 'i0.ɵɵtextBinding(3, i0.ɵɵinterpolation1("", 1 + 2, ""))',
+ generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}',
sourceUrl: '../dir/test.html'
});
@@ -496,7 +495,7 @@ describe('template source-mapping', () => {
// Update mode
expect(mappings).toContain({
- generated: 'i0.ɵɵtextBinding(3, i0.ɵɵinterpolation1("", 1 + 2, ""))',
+ generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}',
sourceUrl: '../extraRootDir/test.html'
});
diff --git a/packages/compiler/src/output/output_jit.ts b/packages/compiler/src/output/output_jit.ts
index 1d3d2670b0..e446a1351b 100644
--- a/packages/compiler/src/output/output_jit.ts
+++ b/packages/compiler/src/output/output_jit.ts
@@ -56,7 +56,7 @@ export class JitEvaluator {
evaluateCode(
sourceUrl: string, ctx: EmitterVisitorContext, vars: {[key: string]: any},
createSourceMap: boolean): any {
- let fnBody = `${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
+ let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
const fnArgNames: string[] = [];
const fnArgValues: any[] = [];
for (const argName in vars) {
diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts
index 2c8e1547f3..7c8b0a061d 100644
--- a/packages/compiler/src/render3/r3_identifiers.ts
+++ b/packages/compiler/src/render3/r3_identifiers.ts
@@ -102,6 +102,17 @@ export class Identifiers {
static getCurrentView: o.ExternalReference = {name: 'ɵɵgetCurrentView', moduleName: CORE};
+ static textInterpolate: o.ExternalReference = {name: 'ɵɵtextInterpolate', moduleName: CORE};
+ static textInterpolate1: o.ExternalReference = {name: 'ɵɵtextInterpolate1', moduleName: CORE};
+ static textInterpolate2: o.ExternalReference = {name: 'ɵɵtextInterpolate2', moduleName: CORE};
+ static textInterpolate3: o.ExternalReference = {name: 'ɵɵtextInterpolate3', moduleName: CORE};
+ static textInterpolate4: o.ExternalReference = {name: 'ɵɵtextInterpolate4', moduleName: CORE};
+ static textInterpolate5: o.ExternalReference = {name: 'ɵɵtextInterpolate5', moduleName: CORE};
+ static textInterpolate6: o.ExternalReference = {name: 'ɵɵtextInterpolate6', moduleName: CORE};
+ static textInterpolate7: o.ExternalReference = {name: 'ɵɵtextInterpolate7', moduleName: CORE};
+ static textInterpolate8: o.ExternalReference = {name: 'ɵɵtextInterpolate8', moduleName: CORE};
+ static textInterpolateV: o.ExternalReference = {name: 'ɵɵtextInterpolateV', moduleName: CORE};
+
static restoreView: o.ExternalReference = {name: 'ɵɵrestoreView', moduleName: CORE};
static interpolation1: o.ExternalReference = {name: 'ɵɵinterpolation1', moduleName: CORE};
diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts
index 5714c819fa..783ac4ab65 100644
--- a/packages/compiler/src/render3/view/template.ts
+++ b/packages/compiler/src/render3/view/template.ts
@@ -941,9 +941,17 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver
const value = text.value.visit(this._valueConverter);
this.allocateBindingSlots(value);
- this.updateInstruction(
- nodeIndex, text.sourceSpan, R3.textBinding,
- () => [o.literal(nodeIndex), this.convertPropertyBinding(o.variable(CONTEXT_NAME), value)]);
+
+ if (value instanceof Interpolation) {
+ this.updateInstruction(
+ nodeIndex, text.sourceSpan, getTextInterpolationExpression(value),
+ () => this.getUpdateInstructionArguments(o.variable(CONTEXT_NAME), value));
+ } else {
+ this.updateInstruction(
+ nodeIndex, text.sourceSpan, R3.textBinding,
+ () =>
+ [o.literal(nodeIndex), this.convertPropertyBinding(o.variable(CONTEXT_NAME), value)]);
+ }
}
visitText(text: t.Text) {
@@ -1736,6 +1744,35 @@ function getAttributeInterpolationExpression(interpolation: Interpolation) {
}
}
+/**
+ * Gets the instruction to generate for interpolated text.
+ * @param interpolation An Interpolation AST
+ */
+function getTextInterpolationExpression(interpolation: Interpolation): o.ExternalReference {
+ switch (getInterpolationArgsLength(interpolation)) {
+ case 1:
+ return R3.textInterpolate;
+ case 3:
+ return R3.textInterpolate1;
+ case 5:
+ return R3.textInterpolate2;
+ case 7:
+ return R3.textInterpolate3;
+ case 9:
+ return R3.textInterpolate4;
+ case 11:
+ return R3.textInterpolate5;
+ case 13:
+ return R3.textInterpolate6;
+ case 15:
+ return R3.textInterpolate7;
+ case 17:
+ return R3.textInterpolate8;
+ default:
+ return R3.textInterpolateV;
+ }
+}
+
/**
* Gets the number of arguments expected to be passed to a generated instruction in the case of
* interpolation instructions.
diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts
index 324ea277be..6a9e57fb18 100644
--- a/packages/core/src/core_render3_private_export.ts
+++ b/packages/core/src/core_render3_private_export.ts
@@ -57,6 +57,16 @@ export {
ɵɵelement,
ɵɵlistener,
ɵɵtext,
+ ɵɵtextInterpolate,
+ ɵɵtextInterpolate1,
+ ɵɵtextInterpolate2,
+ ɵɵtextInterpolate3,
+ ɵɵtextInterpolate4,
+ ɵɵtextInterpolate5,
+ ɵɵtextInterpolate6,
+ ɵɵtextInterpolate7,
+ ɵɵtextInterpolate8,
+ ɵɵtextInterpolateV,
ɵɵembeddedViewStart,
ɵɵprojection,
ɵɵbind,
diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts
index cc6f99edfb..61c5c0daf7 100644
--- a/packages/core/src/render3/index.ts
+++ b/packages/core/src/render3/index.ts
@@ -107,7 +107,18 @@ export {
ɵɵtemplate,
ɵɵtext,
- ɵɵtextBinding} from './instructions/all';
+ ɵɵtextBinding,
+ ɵɵtextInterpolate,
+ ɵɵtextInterpolate1,
+ ɵɵtextInterpolate2,
+ ɵɵtextInterpolate3,
+ ɵɵtextInterpolate4,
+ ɵɵtextInterpolate5,
+ ɵɵtextInterpolate6,
+ ɵɵtextInterpolate7,
+ ɵɵtextInterpolate8,
+ ɵɵtextInterpolateV,
+} from './instructions/all';
export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection';
diff --git a/packages/core/src/render3/instructions/all.ts b/packages/core/src/render3/instructions/all.ts
index 4ae084f172..b876f4980c 100644
--- a/packages/core/src/render3/instructions/all.ts
+++ b/packages/core/src/render3/instructions/all.ts
@@ -36,6 +36,7 @@ export * from './element';
export * from './element_container';
export * from './embedded_view';
export * from './get_current_view';
+export * from './interpolation';
export * from './listener';
export * from './namespace';
export * from './next_context';
@@ -45,3 +46,4 @@ export * from './property_interpolation';
export * from './select';
export * from './styling';
export * from './text';
+export * from './text_interpolation';
diff --git a/packages/core/src/render3/instructions/attribute_interpolation.ts b/packages/core/src/render3/instructions/attribute_interpolation.ts
index 5214208994..c0505532e9 100644
--- a/packages/core/src/render3/instructions/attribute_interpolation.ts
+++ b/packages/core/src/render3/instructions/attribute_interpolation.ts
@@ -8,7 +8,7 @@
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 {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation';
import {TsickleIssue1009} from './shared';
diff --git a/packages/core/src/render3/instructions/interpolation.ts b/packages/core/src/render3/instructions/interpolation.ts
new file mode 100644
index 0000000000..284bb5c143
--- /dev/null
+++ b/packages/core/src/render3/instructions/interpolation.ts
@@ -0,0 +1,289 @@
+/**
+ * @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 {assertEqual, assertLessThan} from '../../util/assert';
+import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
+import {BINDING_INDEX, TVIEW} from '../interfaces/view';
+import {getLView} from '../state';
+import {NO_CHANGE} from '../tokens';
+import {renderStringify} from '../util/misc_utils';
+
+import {storeBindingMetadata} from './shared';
+
+
+
+/**
+ * Create interpolation bindings with a variable number of expressions.
+ *
+ * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead.
+ * Those are faster because there is no need to create an array of expressions and iterate over it.
+ *
+ * `values`:
+ * - has static text at even indexes,
+ * - has evaluated expressions at odd indexes.
+ *
+ * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolationV(values: any[]): string|NO_CHANGE {
+ ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
+ ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
+ let isBindingUpdated = false;
+ const lView = getLView();
+ const tData = lView[TVIEW].data;
+ let bindingIndex = lView[BINDING_INDEX];
+
+ if (tData[bindingIndex] == null) {
+ // 2 is the index of the first static interstitial value (ie. not prefix)
+ for (let i = 2; i < values.length; i += 2) {
+ tData[bindingIndex++] = values[i];
+ }
+ bindingIndex = lView[BINDING_INDEX];
+ }
+
+ for (let i = 1; i < values.length; i += 2) {
+ // Check if bindings (odd indexes) have changed
+ isBindingUpdated = bindingUpdated(lView, bindingIndex++, values[i]) || isBindingUpdated;
+ }
+ lView[BINDING_INDEX] = bindingIndex;
+ storeBindingMetadata(lView, values[0], values[values.length - 1]);
+
+ if (!isBindingUpdated) {
+ return NO_CHANGE;
+ }
+
+ // Build the updated content
+ let content = values[0];
+ for (let i = 1; i < values.length; i += 2) {
+ content += renderStringify(values[i]) + values[i + 1];
+ }
+
+ return content;
+}
+
+/**
+ * Creates an interpolation binding with 1 expression.
+ *
+ * @param prefix static value used for concatenation only.
+ * @param v0 value checked for change.
+ * @param suffix static value used for concatenation only.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE {
+ const lView = getLView();
+ const different = bindingUpdated(lView, lView[BINDING_INDEX]++, v0);
+ storeBindingMetadata(lView, prefix, suffix);
+ return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE;
+}
+
+/**
+ * Creates an interpolation binding with 2 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation2(
+ prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ const different = bindingUpdated2(lView, bindingIndex, v0, v1);
+ lView[BINDING_INDEX] += 2;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ lView[TVIEW].data[bindingIndex] = i0;
+ }
+
+ return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE;
+}
+
+/**
+ * Creates an interpolation binding with 3 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation3(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string|
+ NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2);
+ lView[BINDING_INDEX] += 3;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ const tData = lView[TVIEW].data;
+ tData[bindingIndex] = i0;
+ tData[bindingIndex + 1] = i1;
+ }
+
+ return different ?
+ prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix :
+ NO_CHANGE;
+}
+
+/**
+ * Create an interpolation binding with 4 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation4(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ suffix: string): string|NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
+ lView[BINDING_INDEX] += 4;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ const tData = lView[TVIEW].data;
+ tData[bindingIndex] = i0;
+ tData[bindingIndex + 1] = i1;
+ tData[bindingIndex + 2] = i2;
+ }
+
+ return different ?
+ prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
+ renderStringify(v3) + suffix :
+ NO_CHANGE;
+}
+
+/**
+ * Creates an interpolation binding with 5 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation5(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ i3: string, v4: any, suffix: string): string|NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
+ different = bindingUpdated(lView, bindingIndex + 4, v4) || different;
+ lView[BINDING_INDEX] += 5;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ const tData = lView[TVIEW].data;
+ tData[bindingIndex] = i0;
+ tData[bindingIndex + 1] = i1;
+ tData[bindingIndex + 2] = i2;
+ tData[bindingIndex + 3] = i3;
+ }
+
+ return different ?
+ prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
+ renderStringify(v3) + i3 + renderStringify(v4) + suffix :
+ NO_CHANGE;
+}
+
+/**
+ * Creates an interpolation binding with 6 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation6(
+ 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): string|NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
+ different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different;
+ lView[BINDING_INDEX] += 6;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ const tData = lView[TVIEW].data;
+ tData[bindingIndex] = i0;
+ tData[bindingIndex + 1] = i1;
+ tData[bindingIndex + 2] = i2;
+ tData[bindingIndex + 3] = i3;
+ tData[bindingIndex + 4] = i4;
+ }
+
+ return different ?
+ prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
+ renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix :
+ NO_CHANGE;
+}
+
+/**
+ * Creates an interpolation binding with 7 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation7(
+ 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): string|
+ NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
+ different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different;
+ lView[BINDING_INDEX] += 7;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ const tData = lView[TVIEW].data;
+ tData[bindingIndex] = i0;
+ tData[bindingIndex + 1] = i1;
+ tData[bindingIndex + 2] = i2;
+ tData[bindingIndex + 3] = i3;
+ tData[bindingIndex + 4] = i4;
+ tData[bindingIndex + 5] = i5;
+ }
+
+ return different ?
+ prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
+ renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 +
+ renderStringify(v6) + suffix :
+ NO_CHANGE;
+}
+
+/**
+ * Creates an interpolation binding with 8 expressions.
+ *
+ * @codeGenApi
+ */
+export function ɵɵinterpolation8(
+ 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): string|NO_CHANGE {
+ const lView = getLView();
+ const bindingIndex = lView[BINDING_INDEX];
+ let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
+ different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different;
+ lView[BINDING_INDEX] += 8;
+
+ // Only set static strings the first time (data will be null subsequent runs).
+ const data = storeBindingMetadata(lView, prefix, suffix);
+ if (data) {
+ const tData = lView[TVIEW].data;
+ tData[bindingIndex] = i0;
+ tData[bindingIndex + 1] = i1;
+ tData[bindingIndex + 2] = i2;
+ tData[bindingIndex + 3] = i3;
+ tData[bindingIndex + 4] = i4;
+ tData[bindingIndex + 5] = i5;
+ tData[bindingIndex + 6] = i6;
+ }
+
+ return different ?
+ prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
+ renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 +
+ renderStringify(v6) + i6 + renderStringify(v7) + suffix :
+ NO_CHANGE;
+}
diff --git a/packages/core/src/render3/instructions/property_interpolation.ts b/packages/core/src/render3/instructions/property_interpolation.ts
index 044d7d2b18..9d92cd853d 100644
--- a/packages/core/src/render3/instructions/property_interpolation.ts
+++ b/packages/core/src/render3/instructions/property_interpolation.ts
@@ -5,293 +5,14 @@
* 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 {assertEqual, assertLessThan} from '../../util/assert';
-import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
import {SanitizerFn} from '../interfaces/sanitization';
-import {BINDING_INDEX, TVIEW} from '../interfaces/view';
-import {getLView, getSelectedIndex} from '../state';
+import {getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens';
-import {renderStringify} from '../util/misc_utils';
-import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared';
+import {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation';
+import {TsickleIssue1009, elementPropertyInternal} from './shared';
-
-/**
- * Create interpolation bindings with a variable number of expressions.
- *
- * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead.
- * Those are faster because there is no need to create an array of expressions and iterate over it.
- *
- * `values`:
- * - has static text at even indexes,
- * - has evaluated expressions at odd indexes.
- *
- * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolationV(values: any[]): string|NO_CHANGE {
- ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
- ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
- let different = false;
- const lView = getLView();
- const tData = lView[TVIEW].data;
- let bindingIndex = lView[BINDING_INDEX];
-
- if (tData[bindingIndex] == null) {
- // 2 is the index of the first static interstitial value (ie. not prefix)
- for (let i = 2; i < values.length; i += 2) {
- tData[bindingIndex++] = values[i];
- }
- bindingIndex = lView[BINDING_INDEX];
- }
-
- for (let i = 1; i < values.length; i += 2) {
- // Check if bindings (odd indexes) have changed
- bindingUpdated(lView, bindingIndex++, values[i]) && (different = true);
- }
- lView[BINDING_INDEX] = bindingIndex;
- storeBindingMetadata(lView, values[0], values[values.length - 1]);
-
- if (!different) {
- return NO_CHANGE;
- }
-
- // Build the updated content
- let content = values[0];
- for (let i = 1; i < values.length; i += 2) {
- content += renderStringify(values[i]) + values[i + 1];
- }
-
- return content;
-}
-
-/**
- * Creates an interpolation binding with 1 expression.
- *
- * @param prefix static value used for concatenation only.
- * @param v0 value checked for change.
- * @param suffix static value used for concatenation only.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE {
- const lView = getLView();
- const different = bindingUpdated(lView, lView[BINDING_INDEX]++, v0);
- storeBindingMetadata(lView, prefix, suffix);
- return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE;
-}
-
-/**
- * Creates an interpolation binding with 2 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation2(
- prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- const different = bindingUpdated2(lView, bindingIndex, v0, v1);
- lView[BINDING_INDEX] += 2;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- lView[TVIEW].data[bindingIndex] = i0;
- }
-
- return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE;
-}
-
-/**
- * Creates an interpolation binding with 3 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation3(
- prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string|
- NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2);
- lView[BINDING_INDEX] += 3;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- const tData = lView[TVIEW].data;
- tData[bindingIndex] = i0;
- tData[bindingIndex + 1] = i1;
- }
-
- return different ?
- prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix :
- NO_CHANGE;
-}
-
-/**
- * Create an interpolation binding with 4 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation4(
- prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
- suffix: string): string|NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
- lView[BINDING_INDEX] += 4;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- const tData = lView[TVIEW].data;
- tData[bindingIndex] = i0;
- tData[bindingIndex + 1] = i1;
- tData[bindingIndex + 2] = i2;
- }
-
- return different ?
- prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
- renderStringify(v3) + suffix :
- NO_CHANGE;
-}
-
-/**
- * Creates an interpolation binding with 5 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation5(
- prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
- i3: string, v4: any, suffix: string): string|NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
- different = bindingUpdated(lView, bindingIndex + 4, v4) || different;
- lView[BINDING_INDEX] += 5;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- const tData = lView[TVIEW].data;
- tData[bindingIndex] = i0;
- tData[bindingIndex + 1] = i1;
- tData[bindingIndex + 2] = i2;
- tData[bindingIndex + 3] = i3;
- }
-
- return different ?
- prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
- renderStringify(v3) + i3 + renderStringify(v4) + suffix :
- NO_CHANGE;
-}
-
-/**
- * Creates an interpolation binding with 6 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation6(
- 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): string|NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
- different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different;
- lView[BINDING_INDEX] += 6;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- const tData = lView[TVIEW].data;
- tData[bindingIndex] = i0;
- tData[bindingIndex + 1] = i1;
- tData[bindingIndex + 2] = i2;
- tData[bindingIndex + 3] = i3;
- tData[bindingIndex + 4] = i4;
- }
-
- return different ?
- prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
- renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix :
- NO_CHANGE;
-}
-
-/**
- * Creates an interpolation binding with 7 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation7(
- 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): string|
- NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
- different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different;
- lView[BINDING_INDEX] += 7;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- const tData = lView[TVIEW].data;
- tData[bindingIndex] = i0;
- tData[bindingIndex + 1] = i1;
- tData[bindingIndex + 2] = i2;
- tData[bindingIndex + 3] = i3;
- tData[bindingIndex + 4] = i4;
- tData[bindingIndex + 5] = i5;
- }
-
- return different ?
- prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
- renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 +
- renderStringify(v6) + suffix :
- NO_CHANGE;
-}
-
-/**
- * Creates an interpolation binding with 8 expressions.
- *
- * @codeGenApi
- */
-export function ɵɵinterpolation8(
- 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): string|NO_CHANGE {
- const lView = getLView();
- const bindingIndex = lView[BINDING_INDEX];
- let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3);
- different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different;
- lView[BINDING_INDEX] += 8;
-
- // Only set static strings the first time (data will be null subsequent runs).
- const data = storeBindingMetadata(lView, prefix, suffix);
- if (data) {
- const tData = lView[TVIEW].data;
- tData[bindingIndex] = i0;
- tData[bindingIndex + 1] = i1;
- tData[bindingIndex + 2] = i2;
- tData[bindingIndex + 3] = i3;
- tData[bindingIndex + 4] = i4;
- tData[bindingIndex + 5] = i5;
- tData[bindingIndex + 6] = i6;
- }
-
- return different ?
- prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 +
- renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 +
- renderStringify(v6) + i6 + renderStringify(v7) + suffix :
- NO_CHANGE;
-}
-
-/////////////////////////////////////////////////////////////////////
-/// NEW INSTRUCTIONS
-/////////////////////////////////////////////////////////////////////
-
/**
*
* Update an interpolated property on an element with a lone bound value
diff --git a/packages/core/src/render3/instructions/text_interpolation.ts b/packages/core/src/render3/instructions/text_interpolation.ts
new file mode 100644
index 0000000000..827338249d
--- /dev/null
+++ b/packages/core/src/render3/instructions/text_interpolation.ts
@@ -0,0 +1,298 @@
+/**
+ * @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 {getSelectedIndex} from '../state';
+
+import {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation';
+import {TsickleIssue1009} from './shared';
+import {ɵɵtextBinding} from './text';
+
+
+
+/**
+ *
+ * Update text content with a lone bound value
+ *
+ * Used when a text node has 1 interpolated value in it, an no additional text
+ * surrounds that interpolated value:
+ *
+ * ```html
+ * {{v0}}
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate(v0);
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate(v0: any): TsickleIssue1009 {
+ ɵɵtextInterpolate1('', v0, '');
+ return ɵɵtextInterpolate;
+}
+
+
+/**
+ *
+ * Update text content with single bound value surrounded by other text.
+ *
+ * Used when a text node has 1 interpolated value in it:
+ *
+ * ```html
+ * prefix{{v0}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate1('prefix', v0, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate1(prefix: string, v0: any, suffix: string): TsickleIssue1009 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(index, ɵɵinterpolation1(prefix, v0, suffix));
+ return ɵɵtextInterpolate1;
+}
+
+/**
+ *
+ * Update text content with 2 bound values surrounded by other text.
+ *
+ * Used when a text node has 2 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate2('prefix', v0, '-', v1, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate2(
+ prefix: string, v0: any, i0: string, v1: any, suffix: string): TsickleIssue1009 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(index, ɵɵinterpolation2(prefix, v0, i0, v1, suffix));
+ return ɵɵtextInterpolate2;
+}
+
+/**
+ *
+ * Update text content with 3 bound values surrounded by other text.
+ *
+ * Used when a text node has 3 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate3(
+ * 'prefix', v0, '-', v1, '-', v2, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate3(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ suffix: string): TsickleIssue1009 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(index, ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix));
+ return ɵɵtextInterpolate3;
+}
+
+/**
+ *
+ * Update text content with 4 bound values surrounded by other text.
+ *
+ * Used when a text node has 4 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate4(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see ɵɵtextInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate4(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ suffix: string): TsickleIssue1009 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(index, ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix));
+ return ɵɵtextInterpolate4;
+}
+
+/**
+ *
+ * Update text content with 5 bound values surrounded by other text.
+ *
+ * Used when a text node has 5 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate5(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate5(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ i3: string, v4: any, suffix: string): TsickleIssue1009 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(index, ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix));
+ return ɵɵtextInterpolate5;
+}
+
+/**
+ *
+ * Update text content with 6 bound values surrounded by other text.
+ *
+ * Used when a text node has 6 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate6(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
+ * ```
+ *
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change. @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate6(
+ 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 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(
+ index, ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix));
+ return ɵɵtextInterpolate6;
+}
+
+/**
+ *
+ * Update text content with 7 bound values surrounded by other text.
+ *
+ * Used when a text node has 7 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate7(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate7(
+ 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 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(
+ index, ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix));
+ return ɵɵtextInterpolate7;
+}
+
+/**
+ *
+ * Update text content with 8 bound values surrounded by other text.
+ *
+ * Used when a text node has 8 interpolated values in it:
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolate8(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
+ * ```
+ * @returns itself, so that it may be chained.
+ * @see textInterpolateV
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolate8(
+ 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 {
+ const index = getSelectedIndex();
+ ɵɵtextBinding(
+ index,
+ ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix));
+ return ɵɵtextInterpolate8;
+}
+
+/**
+ * Update text content with 9 or more bound values other surrounded by text.
+ *
+ * Used when the number of interpolated values exceeds 8.
+ *
+ * ```html
+ * prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵtextInterpolateV(
+ * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
+ * 'suffix']);
+ * ```
+ *.
+ * @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']`)
+ *
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵtextInterpolateV(values: any[]): TsickleIssue1009 {
+ const index = getSelectedIndex();
+
+ ɵɵtextBinding(index, ɵɵinterpolationV(values));
+ return ɵɵtextInterpolateV;
+}
diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts
index 1f1f1eb018..b40dff1843 100644
--- a/packages/core/src/render3/jit/environment.ts
+++ b/packages/core/src/render3/jit/environment.ts
@@ -127,6 +127,16 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵtemplate': r3.ɵɵtemplate,
'ɵɵtext': r3.ɵɵtext,
'ɵɵtextBinding': r3.ɵɵtextBinding,
+ 'ɵɵtextInterpolate': r3.ɵɵtextInterpolate,
+ 'ɵɵtextInterpolate1': r3.ɵɵtextInterpolate1,
+ 'ɵɵtextInterpolate2': r3.ɵɵtextInterpolate2,
+ 'ɵɵtextInterpolate3': r3.ɵɵtextInterpolate3,
+ 'ɵɵtextInterpolate4': r3.ɵɵtextInterpolate4,
+ 'ɵɵtextInterpolate5': r3.ɵɵtextInterpolate5,
+ 'ɵɵtextInterpolate6': r3.ɵɵtextInterpolate6,
+ 'ɵɵtextInterpolate7': r3.ɵɵtextInterpolate7,
+ 'ɵɵtextInterpolate8': r3.ɵɵtextInterpolate8,
+ 'ɵɵtextInterpolateV': r3.ɵɵtextInterpolateV,
'ɵɵembeddedViewStart': r3.ɵɵembeddedViewStart,
'ɵɵembeddedViewEnd': r3.ɵɵembeddedViewEnd,
'ɵɵi18n': r3.ɵɵi18n,
diff --git a/packages/core/test/acceptance/text_spec.ts b/packages/core/test/acceptance/text_spec.ts
new file mode 100644
index 0000000000..3f3e665f06
--- /dev/null
+++ b/packages/core/test/acceptance/text_spec.ts
@@ -0,0 +1,115 @@
+/**
+ * @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 {Component} from '@angular/core';
+import {TestBed} from '@angular/core/testing';
+import {of } from 'rxjs';
+
+describe('text instructions', () => {
+ it('should handle all flavors of interpolated text', () => {
+ @Component({
+ template: `
+ a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j
+ a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i
+ a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h
+ a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g
+ a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f
+ a{{one}}b{{two}}c{{three}}d{{four}}e
+ a{{one}}b{{two}}c{{three}}d
+ a{{one}}b{{two}}c
+ a{{one}}b
+ {{one}}
+ `
+ })
+ class App {
+ one = 1;
+ two = 2;
+ three = 3;
+ four = 4;
+ five = 5;
+ six = 6;
+ seven = 7;
+ eight = 8;
+ nine = 9;
+ }
+
+ TestBed.configureTestingModule({declarations: [App]});
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+
+ const allTextContent = Array.from(fixture.nativeElement.querySelectorAll('div'))
+ .map((div: HTMLDivElement) => div.textContent);
+
+ expect(allTextContent).toEqual([
+ 'a1b2c3d4e5f6g7h8i9j',
+ 'a1b2c3d4e5f6g7h8i',
+ 'a1b2c3d4e5f6g7h',
+ 'a1b2c3d4e5f6g',
+ 'a1b2c3d4e5f',
+ 'a1b2c3d4e',
+ 'a1b2c3d',
+ 'a1b2c',
+ 'a1b',
+ '1',
+ ]);
+ });
+
+ it('should handle piped values in interpolated text', () => {
+ @Component({
+ template: `
+ {{who | async}} sells {{(item | async)?.what}} down by the {{(item | async)?.where}}.
+ `
+ })
+ class App {
+ who = of ('Sally');
+ item = of ({
+ what: 'seashells',
+ where: 'seashore',
+ });
+ }
+
+ TestBed.configureTestingModule({declarations: [App]});
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+
+ const p = fixture.nativeElement.querySelector('p') as HTMLDivElement;
+ expect(p.textContent).toBe('Sally sells seashells down by the seashore.');
+ });
+
+ it('should not sanitize urls in interpolated text', () => {
+ @Component({
+ template: '{{thisisfine}}
',
+ })
+ class App {
+ thisisfine = 'javascript:alert("image_of_dog_with_coffee_in_burning_building.gif")';
+ }
+
+ TestBed.configureTestingModule({declarations: [App]});
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const p = fixture.nativeElement.querySelector('p');
+
+ expect(p.textContent)
+ .toBe('javascript:alert("image_of_dog_with_coffee_in_burning_building.gif")');
+ });
+
+ it('should not allow writing HTML in interpolated text', () => {
+ @Component({
+ template: '{{test}}
',
+ })
+ class App {
+ test = 'LOL, big text
';
+ }
+
+ TestBed.configureTestingModule({declarations: [App]});
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const div = fixture.nativeElement.querySelector('div');
+
+ expect(div.innerHTML).toBe('<h1>LOL, big text</h1>');
+ });
+});
diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json
index d804c23fa1..216119ff48 100644
--- a/packages/core/test/bundling/todo/bundle.golden_symbols.json
+++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json
@@ -1603,5 +1603,11 @@
},
{
"name": "ɵɵtextBinding"
+ },
+ {
+ "name": "ɵɵtextInterpolate"
+ },
+ {
+ "name": "ɵɵtextInterpolate1"
}
]
\ No newline at end of file
diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts
index fa1423a027..d72f29d65e 100644
--- a/tools/public_api_guard/core/core.d.ts
+++ b/tools/public_api_guard/core/core.d.ts
@@ -1057,6 +1057,26 @@ export declare function ɵɵtext(index: number, value?: any): void;
export declare function ɵɵtextBinding(index: number, value: T | NO_CHANGE): void;
+export declare function ɵɵtextInterpolate(v0: any): TsickleIssue1009;
+
+export declare function ɵɵtextInterpolate1(prefix: string, v0: any, suffix: string): TsickleIssue1009;
+
+export declare function ɵɵtextInterpolate2(prefix: string, v0: any, i0: string, v1: any, suffix: string): TsickleIssue1009;
+
+export declare function ɵɵtextInterpolate3(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): TsickleIssue1009;
+
+export declare function ɵɵtextInterpolate4(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): TsickleIssue1009;
+
+export declare function ɵɵtextInterpolate5(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 ɵɵtextInterpolate6(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 ɵɵtextInterpolate7(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 ɵɵtextInterpolate8(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 ɵɵtextInterpolateV(values: any[]): TsickleIssue1009;
+
export declare function ɵɵviewQuery(predicate: Type | string[], descend: boolean, read: any): QueryList;
export declare const PACKAGE_ROOT_URL: InjectionToken;