mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
fix(compiler): lexer support for template literals in object literals (#61601)
This commit fixes a shortcoming of the lexer with template literals fixes #61572 PR Close #61601
This commit is contained in:
parent
3e70d64b20
commit
3e102f0b84
3 changed files with 26 additions and 7 deletions
|
|
@ -212,8 +212,7 @@ class _Scanner {
|
|||
private readonly length: number;
|
||||
private peek = 0;
|
||||
private index = -1;
|
||||
private literalInterpolationDepth = 0;
|
||||
private braceDepth = 0;
|
||||
private braceStack: ('interpolation' | 'expression')[] = [];
|
||||
|
||||
constructor(private readonly input: string) {
|
||||
this.length = input.length;
|
||||
|
|
@ -341,7 +340,7 @@ class _Scanner {
|
|||
}
|
||||
|
||||
private scanOpenBrace(start: number, code: number): Token {
|
||||
this.braceDepth++;
|
||||
this.braceStack.push('expression');
|
||||
this.advance();
|
||||
return newCharacterToken(start, this.index, code);
|
||||
}
|
||||
|
|
@ -349,13 +348,12 @@ class _Scanner {
|
|||
private scanCloseBrace(start: number, code: number): Token {
|
||||
this.advance();
|
||||
|
||||
if (this.braceDepth === 0 && this.literalInterpolationDepth > 0) {
|
||||
this.literalInterpolationDepth--;
|
||||
const currentBrace = this.braceStack.pop();
|
||||
if (currentBrace === 'interpolation') {
|
||||
this.tokens.push(newOperatorToken(start, this.index, '}'));
|
||||
return this.scanTemplateLiteralPart(this.index);
|
||||
}
|
||||
|
||||
this.braceDepth--;
|
||||
return newCharacterToken(start, this.index, code);
|
||||
}
|
||||
|
||||
|
|
@ -512,7 +510,7 @@ class _Scanner {
|
|||
|
||||
// @ts-expect-error
|
||||
if (this.peek === chars.$LBRACE) {
|
||||
this.literalInterpolationDepth++;
|
||||
this.braceStack.push('interpolation');
|
||||
this.tokens.push(
|
||||
new StringToken(
|
||||
start,
|
||||
|
|
|
|||
|
|
@ -588,6 +588,20 @@ describe('lexer', () => {
|
|||
expectStringToken(tokens[8], 29, 33, '!!!', StringTokenKind.TemplateLiteralEnd);
|
||||
});
|
||||
|
||||
it('should tokenize a template literal in an literal object value', () => {
|
||||
const tokens: Token[] = lex('{foo: `${name}`}');
|
||||
expect(tokens.length).toBe(9);
|
||||
expectCharacterToken(tokens[0], 0, 1, '{');
|
||||
expectIdentifierToken(tokens[1], 1, 4, 'foo');
|
||||
expectCharacterToken(tokens[2], 4, 5, ':');
|
||||
expectStringToken(tokens[3], 6, 7, '', StringTokenKind.TemplateLiteralPart);
|
||||
expectOperatorToken(tokens[4], 7, 9, '${');
|
||||
expectIdentifierToken(tokens[5], 9, 13, 'name');
|
||||
expectOperatorToken(tokens[6], 13, 14, '}');
|
||||
expectStringToken(tokens[7], 14, 15, '', StringTokenKind.TemplateLiteralEnd);
|
||||
expectCharacterToken(tokens[8], 15, 16, '}');
|
||||
});
|
||||
|
||||
it('should produce an error if a template literal is not terminated', () => {
|
||||
expectErrorToken(
|
||||
lex('`hello')[0],
|
||||
|
|
|
|||
|
|
@ -453,6 +453,13 @@ describe('parser', () => {
|
|||
checkBinding('`hello ${(name | capitalize)}!!!`', '`hello ${((name | capitalize))}!!!`');
|
||||
});
|
||||
|
||||
it('should parse template literals in objects literals', () => {
|
||||
checkBinding('{"a": `${name}`}');
|
||||
checkBinding('{"a": `hello ${name}!`}');
|
||||
checkBinding('{"a": `hello ${`hello ${`hello`}`}!`}');
|
||||
checkBinding('{"a": `hello ${{"b": `hello`}}`}');
|
||||
});
|
||||
|
||||
it('should report error if interpolation is empty', () => {
|
||||
expectBindingError(
|
||||
'`hello ${}`',
|
||||
|
|
|
|||
Loading…
Reference in a new issue