diff --git a/packages/compiler/src/i18n/extractor_merger.ts b/packages/compiler/src/i18n/extractor_merger.ts index 7bb07f9b7b..b0da1c372b 100644 --- a/packages/compiler/src/i18n/extractor_merger.ts +++ b/packages/compiler/src/i18n/extractor_merger.ts @@ -396,12 +396,12 @@ class _Visitor implements html.Visitor { if (nodes.length == 0) { translatedAttributes.push(new html.Attribute( attr.name, '', attr.sourceSpan, undefined /* keySpan */, undefined /* valueSpan */, - undefined /* valueTokens */, undefined /* i18n */)); + undefined /* i18n */)); } else if (nodes[0] instanceof html.Text) { const value = (nodes[0] as html.Text).value; translatedAttributes.push(new html.Attribute( attr.name, value, attr.sourceSpan, undefined /* keySpan */, - undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)); + undefined /* valueSpan */, undefined /* i18n */)); } else { this._reportError( el, diff --git a/packages/compiler/src/ml_parser/ast.ts b/packages/compiler/src/ml_parser/ast.ts index a8abcc80a6..7b71ffe9af 100644 --- a/packages/compiler/src/ml_parser/ast.ts +++ b/packages/compiler/src/ml_parser/ast.ts @@ -9,7 +9,6 @@ import {AstPath} from '../ast_path'; import {I18nMeta} from '../i18n/i18n_ast'; import {ParseSourceSpan} from '../parse_util'; -import {Token} from './lexer'; interface BaseNode { sourceSpan: ParseSourceSpan; @@ -24,8 +23,7 @@ export abstract class NodeWithI18n implements BaseNode { } export class Text extends NodeWithI18n { - constructor( - public value: string, sourceSpan: ParseSourceSpan, public tokens: Token[], i18n?: I18nMeta) { + constructor(public value: string, sourceSpan: ParseSourceSpan, i18n?: I18nMeta) { super(sourceSpan, i18n); } override visit(visitor: Visitor, context: any): any { @@ -57,8 +55,8 @@ export class ExpansionCase implements BaseNode { export class Attribute extends NodeWithI18n { constructor( public name: string, public value: string, sourceSpan: ParseSourceSpan, - readonly keySpan: ParseSourceSpan|undefined, public valueSpan: ParseSourceSpan|undefined, - public valueTokens: Token[]|undefined, i18n: I18nMeta|undefined) { + readonly keySpan: ParseSourceSpan|undefined, public valueSpan?: ParseSourceSpan, + i18n?: I18nMeta) { super(sourceSpan, i18n); } override visit(visitor: Visitor, context: any): any { diff --git a/packages/compiler/src/ml_parser/html_whitespaces.ts b/packages/compiler/src/ml_parser/html_whitespaces.ts index 57045ee8dc..f416523476 100644 --- a/packages/compiler/src/ml_parser/html_whitespaces.ts +++ b/packages/compiler/src/ml_parser/html_whitespaces.ts @@ -8,7 +8,6 @@ import * as html from './ast'; import {NGSP_UNICODE} from './entities'; -import {Token, TokenType} from './lexer'; import {ParseTreeResult} from './parser'; export const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces'; @@ -75,13 +74,8 @@ export class WhitespaceVisitor implements html.Visitor { (context.prev instanceof html.Expansion || context.next instanceof html.Expansion); if (isNotBlank || hasExpansionSibling) { - // Process the whitespace in the tokens of this Text node - const tokens = text.tokens.map( - token => token.type === TokenType.TEXT ? createTextTokenAfterWhitespaceProcessing(token) : - token); - // Process the whitespace of the value of this Text node - const value = processWhitespace(text.value); - return new html.Text(value, text.sourceSpan, tokens, text.i18n); + return new html.Text( + replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan, text.i18n); } return null; @@ -100,14 +94,6 @@ export class WhitespaceVisitor implements html.Visitor { } } -function createTextTokenAfterWhitespaceProcessing(token: Token): Token { - return new Token(token.type, [processWhitespace(token.parts[0])], token.sourceSpan); -} - -function processWhitespace(text: string): string { - return replaceNgsp(text).replace(WS_REPLACE_REGEXP, ' '); -} - export function removeWhitespaces(htmlAstWithErrors: ParseTreeResult): ParseTreeResult { return new ParseTreeResult( html.visitAll(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), diff --git a/packages/compiler/src/ml_parser/icu_ast_expander.ts b/packages/compiler/src/ml_parser/icu_ast_expander.ts index f52affd590..9e08c954dd 100644 --- a/packages/compiler/src/ml_parser/icu_ast_expander.ts +++ b/packages/compiler/src/ml_parser/icu_ast_expander.ts @@ -102,15 +102,14 @@ function _expandPluralForm(ast: html.Expansion, errors: ParseError[]): html.Elem errors.push(...expansionResult.errors); return new html.Element( - `ng-template`, - [new html.Attribute( - 'ngPluralCase', `${c.value}`, c.valueSourceSpan, undefined /* keySpan */, - undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)], + `ng-template`, [new html.Attribute( + 'ngPluralCase', `${c.value}`, c.valueSourceSpan, undefined /* keySpan */, + undefined /* valueSpan */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan); }); const switchAttr = new html.Attribute( '[ngPlural]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, - undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */); + undefined /* valueSpan */, undefined /* i18n */); return new html.Element( 'ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan); } @@ -124,23 +123,21 @@ function _expandDefaultForm(ast: html.Expansion, errors: ParseError[]): html.Ele if (c.value === 'other') { // other is the default case when no values match return new html.Element( - `ng-template`, - [new html.Attribute( - 'ngSwitchDefault', '', c.valueSourceSpan, undefined /* keySpan */, - undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)], + `ng-template`, [new html.Attribute( + 'ngSwitchDefault', '', c.valueSourceSpan, undefined /* keySpan */, + undefined /* valueSpan */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan); } return new html.Element( - `ng-template`, - [new html.Attribute( - 'ngSwitchCase', `${c.value}`, c.valueSourceSpan, undefined /* keySpan */, - undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */)], + `ng-template`, [new html.Attribute( + 'ngSwitchCase', `${c.value}`, c.valueSourceSpan, undefined /* keySpan */, + undefined /* valueSpan */, undefined /* i18n */)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan); }); const switchAttr = new html.Attribute( '[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan, undefined /* keySpan */, - undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */); + undefined /* valueSpan */, undefined /* i18n */); return new html.Element( 'ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan); } diff --git a/packages/compiler/src/ml_parser/parser.ts b/packages/compiler/src/ml_parser/parser.ts index d9f5d17bd3..4d5f18d440 100644 --- a/packages/compiler/src/ml_parser/parser.ts +++ b/packages/compiler/src/ml_parser/parser.ts @@ -216,7 +216,6 @@ class _TreeBuilder { } private _consumeText(token: lex.Token) { - const tokens = [token]; const startSpan = token.sourceSpan; let text = token.parts[0]; if (text.length > 0 && text[0] == '\n') { @@ -224,15 +223,14 @@ class _TreeBuilder { if (parent != null && parent.children.length == 0 && this.getTagDefinition(parent.name).ignoreFirstLf) { text = text.substring(1); - tokens[0] = {type: token.type, sourceSpan: token.sourceSpan, parts: [text]}; } } + // For now recombine text, interpolation and entity tokens while (this._peek.type === lex.TokenType.INTERPOLATION || this._peek.type === lex.TokenType.TEXT || this._peek.type === lex.TokenType.ENCODED_ENTITY) { token = this._advance(); - tokens.push(token); if (token.type === lex.TokenType.INTERPOLATION) { // For backward compatibility we decode HTML entities that appear in interpolation // expressions. This is arguably a bug, but it could be a considerable breaking change to @@ -250,8 +248,8 @@ class _TreeBuilder { const endSpan = token.sourceSpan; this._addToParent(new html.Text( text, - new ParseSourceSpan(startSpan.start, endSpan.end, startSpan.fullStart, startSpan.details), - tokens)); + new ParseSourceSpan( + startSpan.start, endSpan.end, startSpan.fullStart, startSpan.details))); } } @@ -374,17 +372,16 @@ class _TreeBuilder { // Consume the attribute value let value = ''; - const valueTokens: lex.Token[] = []; let valueStartSpan: ParseSourceSpan|undefined = undefined; let valueEnd: ParseLocation|undefined = undefined; if (this._peek.type === lex.TokenType.ATTR_VALUE_TEXT) { valueStartSpan = this._peek.sourceSpan; valueEnd = this._peek.sourceSpan.end; + // For now recombine text, interpolation and entity tokens while (this._peek.type === lex.TokenType.ATTR_VALUE_TEXT || this._peek.type === lex.TokenType.ATTR_VALUE_INTERPOLATION || this._peek.type === lex.TokenType.ENCODED_ENTITY) { - const valueToken = this._advance(); - valueTokens.push(valueToken); + let valueToken = this._advance(); if (valueToken.type === lex.TokenType.ATTR_VALUE_INTERPOLATION) { // For backward compatibility we decode HTML entities that appear in interpolation // expressions. This is arguably a bug, but it could be a considerable breaking change to @@ -411,8 +408,7 @@ class _TreeBuilder { return new html.Attribute( fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), - attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, - undefined); + attrName.sourceSpan, valueSpan); } private _getParentElement(): html.Element|null { diff --git a/packages/compiler/test/ml_parser/ast_spec_utils.ts b/packages/compiler/test/ml_parser/ast_spec_utils.ts index 818ae726ce..a6f7ca65df 100644 --- a/packages/compiler/test/ml_parser/ast_spec_utils.ts +++ b/packages/compiler/test/ml_parser/ast_spec_utils.ts @@ -52,16 +52,12 @@ class _Humanizer implements html.Visitor { } visitAttribute(attribute: html.Attribute, context: any): any { - const valueTokens = attribute.valueTokens ?? []; - const res = this._appendContext(attribute, [ - html.Attribute, attribute.name, attribute.value, ...valueTokens.map(token => token.parts) - ]); + const res = this._appendContext(attribute, [html.Attribute, attribute.name, attribute.value]); this.result.push(res); } visitText(text: html.Text, context: any): any { - const res = this._appendContext( - text, [html.Text, text.value, this.elDepth, ...text.tokens.map(token => token.parts)]); + const res = this._appendContext(text, [html.Text, text.value, this.elDepth]); this.result.push(res); } diff --git a/packages/compiler/test/ml_parser/html_parser_spec.ts b/packages/compiler/test/ml_parser/html_parser_spec.ts index 57171d5f40..4fbfa75692 100644 --- a/packages/compiler/test/ml_parser/html_parser_spec.ts +++ b/packages/compiler/test/ml_parser/html_parser_spec.ts @@ -24,31 +24,31 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn, humanizeNodes} describe('parse', () => { describe('text nodes', () => { it('should parse root level text nodes', () => { - expect(humanizeDom(parser.parse('a', 'TestComp'))).toEqual([[html.Text, 'a', 0, ['a']]]); + expect(humanizeDom(parser.parse('a', 'TestComp'))).toEqual([[html.Text, 'a', 0]]); }); it('should parse text nodes inside regular elements', () => { expect(humanizeDom(parser.parse('
before
after
1
2
foo\nbar`)).toEqual([ [html.Element, 'pre', 0], [html.Element, 'strong', 1], - [html.Text, 'foo', 2, ['foo']], - [html.Text, '\n', 1, ['\n']], + [html.Text, 'foo', 2], + [html.Text, '\n', 1], [html.Element, 'strong', 1], - [html.Text, 'bar', 2, ['bar']], + [html.Text, 'bar', 2], ]); }); it('should skip whitespace trimming in