fix(compiler): support more than 9 interpolations (#12710)
Fixes #10253
This commit is contained in:
parent
d8f23f4b7f
commit
22c021c57f
|
@ -275,7 +275,12 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||||
args.push(this.visit(ast.expressions[i], _Mode.Expression));
|
args.push(this.visit(ast.expressions[i], _Mode.Expression));
|
||||||
}
|
}
|
||||||
args.push(o.literal(ast.strings[ast.strings.length - 1]));
|
args.push(o.literal(ast.strings[ast.strings.length - 1]));
|
||||||
return o.importExpr(resolveIdentifier(Identifiers.interpolate)).callFn(args);
|
|
||||||
|
return ast.expressions.length <= 9 ?
|
||||||
|
o.importExpr(resolveIdentifier(Identifiers.inlineInterpolate)).callFn(args) :
|
||||||
|
o.importExpr(resolveIdentifier(Identifiers.interpolate)).callFn([
|
||||||
|
args[0], o.literalArr(args.slice(1))
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any {
|
visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any {
|
||||||
|
|
|
@ -174,6 +174,11 @@ export class Identifiers {
|
||||||
};
|
};
|
||||||
static devModeEqual:
|
static devModeEqual:
|
||||||
IdentifierSpec = {name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: devModeEqual};
|
IdentifierSpec = {name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: devModeEqual};
|
||||||
|
static inlineInterpolate: IdentifierSpec = {
|
||||||
|
name: 'inlineInterpolate',
|
||||||
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
runtime: view_utils.inlineInterpolate
|
||||||
|
};
|
||||||
static interpolate: IdentifierSpec = {
|
static interpolate: IdentifierSpec = {
|
||||||
name: 'interpolate',
|
name: 'interpolate',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
|
|
|
@ -104,11 +104,6 @@ export class BindingParser {
|
||||||
const ast = this._exprParser.parseInterpolation(value, sourceInfo, this._interpolationConfig);
|
const ast = this._exprParser.parseInterpolation(value, sourceInfo, this._interpolationConfig);
|
||||||
if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
||||||
this._checkPipes(ast, sourceSpan);
|
this._checkPipes(ast, sourceSpan);
|
||||||
if (ast &&
|
|
||||||
(<Interpolation>ast.ast).expressions.length > view_utils.MAX_INTERPOLATION_VALUES) {
|
|
||||||
throw new Error(
|
|
||||||
`Only support at most ${view_utils.MAX_INTERPOLATION_VALUES} interpolation values!`);
|
|
||||||
}
|
|
||||||
return ast;
|
return ast;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
|
|
|
@ -45,9 +45,15 @@ export function addToArray(e: any, array: any[]) {
|
||||||
array.push(e);
|
array.push(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MAX_INTERPOLATION_VALUES = 9;
|
export function interpolate(valueCount: number, constAndInterp: string[]): string {
|
||||||
|
let result = '';
|
||||||
|
for (let i = 0; i < valueCount * 2; i = i + 2) {
|
||||||
|
result = result + constAndInterp[i] + _toStringWithNull(constAndInterp[i + 1]);
|
||||||
|
}
|
||||||
|
return result + constAndInterp[valueCount * 2];
|
||||||
|
}
|
||||||
|
|
||||||
export function interpolate(
|
export function inlineInterpolate(
|
||||||
valueCount: number, c0: string, a1: any, c1: string, a2?: any, c2?: string, a3?: any,
|
valueCount: number, c0: string, a1: any, c1: string, a2?: any, c2?: string, a3?: any,
|
||||||
c3?: string, a4?: any, c4?: string, a5?: any, c5?: string, a6?: any, c6?: string, a7?: any,
|
c3?: string, a4?: any, c4?: string, a5?: any, c5?: string, a6?: any, c6?: string, a7?: any,
|
||||||
c7?: string, a8?: any, c8?: string, a9?: any, c9?: string): string {
|
c7?: string, a8?: any, c8?: string, a9?: any, c9?: string): string {
|
||||||
|
|
|
@ -70,6 +70,29 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||||
expect(fixture.nativeElement).toHaveText('true|false');
|
expect(fixture.nativeElement).toHaveText('true|false');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support an arbitrary number of interpolations in an element', () => {
|
||||||
|
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||||
|
const template =
|
||||||
|
`<div>before{{'0'}}a{{'1'}}b{{'2'}}c{{'3'}}d{{'4'}}e{{'5'}}f{{'6'}}g{{'7'}}h{{'8'}}i{{'9'}}j{{'10'}}after</div>`;
|
||||||
|
const fixture =
|
||||||
|
TestBed.overrideComponent(MyComp, {set: {template}}).createComponent(MyComp);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('before0a1b2c3d4e5f6g7h8i9j10after');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use a blank string when interpolation evaluates to null or undefined with an arbitrary number of interpolations',
|
||||||
|
() => {
|
||||||
|
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||||
|
const template =
|
||||||
|
`<div>0{{null}}a{{undefined}}b{{null}}c{{undefined}}d{{null}}e{{undefined}}f{{null}}g{{undefined}}h{{null}}i{{undefined}}j{{null}}1</div>`;
|
||||||
|
const fixture =
|
||||||
|
TestBed.overrideComponent(MyComp, {set: {template}}).createComponent(MyComp);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('0abcdefghij1');
|
||||||
|
});
|
||||||
|
|
||||||
it('should consume element binding changes', () => {
|
it('should consume element binding changes', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||||
const template = '<div [id]="ctxProp"></div>';
|
const template = '<div [id]="ctxProp"></div>';
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class _View_TreeComponent0 implements FtlView<import3.TreeComponent> {
|
||||||
this._el_0.style.backgroundColor = currVal_0;
|
this._el_0.style.backgroundColor = currVal_0;
|
||||||
this._expr_0 = currVal_0;
|
this._expr_0 = currVal_0;
|
||||||
}
|
}
|
||||||
const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' ');
|
const currVal_1: any = import4.inlineInterpolate(1, ' ', this.context.data.value, ' ');
|
||||||
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
|
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
|
||||||
this._text_1.nodeValue = currVal_1;
|
this._text_1.nodeValue = currVal_1;
|
||||||
this._expr_1 = currVal_1;
|
this._expr_1 = currVal_1;
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class View_TreeTreeComponent {
|
||||||
this._el_0.style.backgroundColor = currVal_0;
|
this._el_0.style.backgroundColor = currVal_0;
|
||||||
this._expr_0 = currVal_0;
|
this._expr_0 = currVal_0;
|
||||||
}
|
}
|
||||||
const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' ');
|
const currVal_1: any = import4.inlineInterpolate(1, ' ', this.context.data.value, ' ');
|
||||||
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
|
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
|
||||||
this._text_1.nodeValue = currVal_1;
|
this._text_1.nodeValue = currVal_1;
|
||||||
this._expr_1 = currVal_1;
|
this._expr_1 = currVal_1;
|
||||||
|
|
|
@ -47,7 +47,7 @@ export class View_TreeLeafComponent {
|
||||||
this._el_0.style.backgroundColor = currVal_0;
|
this._el_0.style.backgroundColor = currVal_0;
|
||||||
this._expr_0 = currVal_0;
|
this._expr_0 = currVal_0;
|
||||||
}
|
}
|
||||||
const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' ');
|
const currVal_1: any = import4.inlineInterpolate(1, ' ', this.context.data.value, ' ');
|
||||||
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
|
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
|
||||||
this._text_1.nodeValue = currVal_1;
|
this._text_1.nodeValue = currVal_1;
|
||||||
this._expr_1 = currVal_1;
|
this._expr_1 = currVal_1;
|
||||||
|
|
Loading…
Reference in New Issue