Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 3b768fb

Browse files
committed
fix($interpolate): use the first end symbol that forms a valid expression
When an interpolation string has multiple end symbol choices, pick the occurrence that forms a valid expression Closes #8642
1 parent 8ac9035 commit 3b768fb

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

src/ng/interpolate.js

+42-2
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,57 @@ function $InterpolateProvider() {
193193
textLength = text.length,
194194
exp,
195195
concat = [],
196-
expressionPositions = [];
196+
expressionPositions = [],
197+
state = 0,
198+
brackets = {"(": 0, ")": 0, "{": 0, "}": 0, "[": 0, "]": 0},
199+
bracketChars = "(){}[]",
200+
ch,
201+
i;
197202

198203
while(index < textLength) {
199204
if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
200205
((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
201206
if (index !== startIndex) {
202207
concat.push(unescapeText(text.substring(index, startIndex)));
203208
}
209+
index = startIndex + startSymbolLength;
210+
while (index !== endIndex || state !== 0 || brackets['('] !== brackets[')'] ||
211+
brackets['['] !== brackets[']'] || brackets['{'] !== brackets['}']) {
212+
if (index === endIndex) {
213+
endIndex = text.indexOf(endSymbol, endIndex + 1);
214+
if (endIndex === -1) {
215+
break;
216+
}
217+
}
218+
ch = text[index];
219+
switch (state) {
220+
case 0:
221+
if (ch === "'") state = 1;
222+
if (ch === '"') state = 3;
223+
if ((i = bracketChars.indexOf(ch)) != -1) {
224+
brackets[ch]++;
225+
}
226+
break;
227+
case 1:
228+
if (ch === '\\') state = 2;
229+
if (ch === "'") state = 0;
230+
break;
231+
case 2:
232+
state = 1;
233+
break;
234+
case 3:
235+
if (ch === '\\') state = 4;
236+
if (ch === '"') state = 0;
237+
break;
238+
case 4:
239+
state = 3;
240+
break;
241+
}
242+
index++;
243+
}
204244
exp = text.substring(startIndex + startSymbolLength, endIndex);
205-
expressions.push(exp);
206245
parseFns.push($parse(exp, parseStringifyInterceptor));
246+
expressions.push(exp);
207247
index = endIndex + endSymbolLength;
208248
expressionPositions.push(concat.length);
209249
concat.push('');

test/ng/interpolateSpec.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('$interpolate', function() {
105105
expect(function() {
106106
$interpolate('{{\\{\\{foo\\}\\}}}')(obj);
107107
}).toThrowMinErr('$parse', 'lexerr',
108-
'Lexer Error: Unexpected next character at columns 0-0 [\\] in expression [\\{\\{foo\\}\\]');
108+
'Lexer Error: Unexpected next character at columns 0-0 [\\] in expression [\\{\\{foo\\}\\}]');
109109
}));
110110

111111

@@ -116,6 +116,14 @@ describe('$interpolate', function() {
116116
it('should evaluate expressions between escaped start/end symbols', inject(function($interpolate) {
117117
expect($interpolate('\\{\\{Hello, {{bar}}!\\}\\}')(obj)).toBe('{{Hello, World!}}');
118118
}));
119+
120+
it('should pick the first end symbol location that forms a valid expression', inject(function($interpolate) {
121+
expect($interpolate('{{{}}}')(obj)).toBe('{}');
122+
expect($interpolate('{{"{{ }}"}}')(obj)).toBe('{{ }}');
123+
expect($interpolate('{{{foo: "bar"}}}')(obj)).toBe('{"foo":"bar"}');
124+
expect($interpolate('{{{foo: {"bar": "baz"}}}}')(obj)).toBe('{"foo":{"bar":"baz"}}');
125+
expect($interpolate('{{[{foo: {"bar": "baz"}}]}}')(obj)).toBe('[{"foo":{"bar":"baz"}}]');
126+
}));
119127
});
120128

121129

0 commit comments

Comments
 (0)