Skip to content

Commit 3e102f0

Browse files
JeanMechethePunderWoman
authored andcommitted
fix(compiler): lexer support for template literals in object literals (angular#61601)
This commit fixes a shortcoming of the lexer with template literals fixes angular#61572 PR Close angular#61601
1 parent 3e70d64 commit 3e102f0

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

packages/compiler/src/expression_parser/lexer.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,7 @@ class _Scanner {
212212
private readonly length: number;
213213
private peek = 0;
214214
private index = -1;
215-
private literalInterpolationDepth = 0;
216-
private braceDepth = 0;
215+
private braceStack: ('interpolation' | 'expression')[] = [];
217216

218217
constructor(private readonly input: string) {
219218
this.length = input.length;
@@ -341,21 +340,20 @@ class _Scanner {
341340
}
342341

343342
private scanOpenBrace(start: number, code: number): Token {
344-
this.braceDepth++;
343+
this.braceStack.push('expression');
345344
this.advance();
346345
return newCharacterToken(start, this.index, code);
347346
}
348347

349348
private scanCloseBrace(start: number, code: number): Token {
350349
this.advance();
351350

352-
if (this.braceDepth === 0 && this.literalInterpolationDepth > 0) {
353-
this.literalInterpolationDepth--;
351+
const currentBrace = this.braceStack.pop();
352+
if (currentBrace === 'interpolation') {
354353
this.tokens.push(newOperatorToken(start, this.index, '}'));
355354
return this.scanTemplateLiteralPart(this.index);
356355
}
357356

358-
this.braceDepth--;
359357
return newCharacterToken(start, this.index, code);
360358
}
361359

@@ -512,7 +510,7 @@ class _Scanner {
512510

513511
// @ts-expect-error
514512
if (this.peek === chars.$LBRACE) {
515-
this.literalInterpolationDepth++;
513+
this.braceStack.push('interpolation');
516514
this.tokens.push(
517515
new StringToken(
518516
start,

packages/compiler/test/expression_parser/lexer_spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,20 @@ describe('lexer', () => {
588588
expectStringToken(tokens[8], 29, 33, '!!!', StringTokenKind.TemplateLiteralEnd);
589589
});
590590

591+
it('should tokenize a template literal in an literal object value', () => {
592+
const tokens: Token[] = lex('{foo: `${name}`}');
593+
expect(tokens.length).toBe(9);
594+
expectCharacterToken(tokens[0], 0, 1, '{');
595+
expectIdentifierToken(tokens[1], 1, 4, 'foo');
596+
expectCharacterToken(tokens[2], 4, 5, ':');
597+
expectStringToken(tokens[3], 6, 7, '', StringTokenKind.TemplateLiteralPart);
598+
expectOperatorToken(tokens[4], 7, 9, '${');
599+
expectIdentifierToken(tokens[5], 9, 13, 'name');
600+
expectOperatorToken(tokens[6], 13, 14, '}');
601+
expectStringToken(tokens[7], 14, 15, '', StringTokenKind.TemplateLiteralEnd);
602+
expectCharacterToken(tokens[8], 15, 16, '}');
603+
});
604+
591605
it('should produce an error if a template literal is not terminated', () => {
592606
expectErrorToken(
593607
lex('`hello')[0],

packages/compiler/test/expression_parser/parser_spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,13 @@ describe('parser', () => {
453453
checkBinding('`hello ${(name | capitalize)}!!!`', '`hello ${((name | capitalize))}!!!`');
454454
});
455455

456+
it('should parse template literals in objects literals', () => {
457+
checkBinding('{"a": `${name}`}');
458+
checkBinding('{"a": `hello ${name}!`}');
459+
checkBinding('{"a": `hello ${`hello ${`hello`}`}!`}');
460+
checkBinding('{"a": `hello ${{"b": `hello`}}`}');
461+
});
462+
456463
it('should report error if interpolation is empty', () => {
457464
expectBindingError(
458465
'`hello ${}`',

0 commit comments

Comments
 (0)