mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(compiler): handle braces in block parameters (#51143)
Fixes that using braces in the block parameters would result in incorrect tokens being produced. Currently we don't have any blocks that allow object literal parameters, but it may come up in the future. PR Close #51143
This commit is contained in:
parent
27d43a4a7f
commit
92ebfd1ca7
2 changed files with 41 additions and 7 deletions
|
|
@ -263,11 +263,11 @@ class _Tokenizer {
|
|||
this._beginToken(TokenType.BLOCK_PARAMETER);
|
||||
const start = this._cursor.clone();
|
||||
let inQuote: number|null = null;
|
||||
let openBraces = 0;
|
||||
|
||||
// Consume the parameter until the next semicolon or brace.
|
||||
// Note that we skip over semicolons/braces inside of strings.
|
||||
while ((this._cursor.peek() !== chars.$SEMICOLON && this._cursor.peek() !== chars.$RBRACE &&
|
||||
this._cursor.peek() !== chars.$EOF) ||
|
||||
while ((this._cursor.peek() !== chars.$SEMICOLON && this._cursor.peek() !== chars.$EOF) ||
|
||||
inQuote !== null) {
|
||||
const char = this._cursor.peek();
|
||||
|
||||
|
|
@ -278,6 +278,14 @@ class _Tokenizer {
|
|||
inQuote = null;
|
||||
} else if (inQuote === null && chars.isQuote(char)) {
|
||||
inQuote = char;
|
||||
} else if (char === chars.$LBRACE && inQuote === null) {
|
||||
openBraces++;
|
||||
} else if (char === chars.$RBRACE && inQuote === null) {
|
||||
if (openBraces === 0) {
|
||||
break;
|
||||
} else if (openBraces > 0) {
|
||||
openBraces--;
|
||||
}
|
||||
}
|
||||
|
||||
this._cursor.advance();
|
||||
|
|
|
|||
|
|
@ -1817,8 +1817,10 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u
|
|||
|
||||
describe('blocks', () => {
|
||||
// TODO(crisbeto): temporary utility while blocks are disabled by default.
|
||||
function tokenizeBlock(input: string, options: TokenizeOptions = {}): any[] {
|
||||
return tokenizeAndHumanizeParts(input, {tokenizeBlocks: true, ...options});
|
||||
const options: Readonly<TokenizeOptions> = {tokenizeBlocks: true};
|
||||
|
||||
function tokenizeBlock(input: string, additionalOptions: TokenizeOptions = {}): any[] {
|
||||
return tokenizeAndHumanizeParts(input, {...options, ...additionalOptions});
|
||||
}
|
||||
|
||||
it('should parse a block group', () => {
|
||||
|
|
@ -1887,10 +1889,11 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u
|
|||
});
|
||||
|
||||
it('should handle semicolons and braces used in a block group parameter', () => {
|
||||
expect(tokenizeBlock(`{#foo a === ";"; b === '}'}hello{/foo}`)).toEqual([
|
||||
expect(tokenizeBlock(`{#foo a === ";"; b === '}'; c === "{"}hello{/foo}`)).toEqual([
|
||||
[TokenType.BLOCK_GROUP_OPEN_START, 'foo'],
|
||||
[TokenType.BLOCK_PARAMETER, `a === ";"`],
|
||||
[TokenType.BLOCK_PARAMETER, `b === '}'`],
|
||||
[TokenType.BLOCK_PARAMETER, `c === "{"`],
|
||||
[TokenType.BLOCK_GROUP_OPEN_END],
|
||||
[TokenType.TEXT, 'hello'],
|
||||
[TokenType.BLOCK_GROUP_CLOSE, 'foo'],
|
||||
|
|
@ -1898,9 +1901,20 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u
|
|||
]);
|
||||
});
|
||||
|
||||
it('should throw for invalid quotes in a parameter', () => {
|
||||
const options = {tokenizeBlocks: true};
|
||||
it('should handle object literals in block group parameters', () => {
|
||||
expect(tokenizeBlock(`{#foo on a({a: 1, b: 2}, false, {c: 3}); when b({d: 4})}hello{/foo}`))
|
||||
.toEqual([
|
||||
[TokenType.BLOCK_GROUP_OPEN_START, 'foo'],
|
||||
[TokenType.BLOCK_PARAMETER, 'on a({a: 1, b: 2}, false, {c: 3})'],
|
||||
[TokenType.BLOCK_PARAMETER, 'when b({d: 4})'],
|
||||
[TokenType.BLOCK_GROUP_OPEN_END],
|
||||
[TokenType.TEXT, 'hello'],
|
||||
[TokenType.BLOCK_GROUP_CLOSE, 'foo'],
|
||||
[TokenType.EOF],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should report invalid quotes in a parameter', () => {
|
||||
expect(tokenizeAndHumanizeErrors(`{#foo a === "}hello{/foo}`, options)).toEqual([
|
||||
[TokenType.BLOCK_PARAMETER, 'Unexpected character "EOF"', '0:25']
|
||||
]);
|
||||
|
|
@ -1910,6 +1924,18 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u
|
|||
]);
|
||||
});
|
||||
|
||||
it('should report unclosed block open tag containing an objet literal', () => {
|
||||
expect(tokenizeAndHumanizeErrors(`{#foo {invalid: true}hello{/foo}`, options)).toEqual([
|
||||
[TokenType.BLOCK_GROUP_OPEN_END, 'Unexpected character "EOF"', '0:32'],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should report unclosed object literal in block open tag', () => {
|
||||
expect(tokenizeAndHumanizeErrors(`{#foo {hello{/foo}`, options)).toEqual([
|
||||
[TokenType.BLOCK_GROUP_OPEN_END, 'Unexpected character "EOF"', '0:18'],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle a semicolon used in a nested string inside a block group parameter', () => {
|
||||
expect(tokenizeBlock(`{#if condition === "';'"}hello{/if}`)).toEqual([
|
||||
[TokenType.BLOCK_GROUP_OPEN_START, 'if'],
|
||||
|
|
|
|||
Loading…
Reference in a new issue