From 25e070dd65f3c73fbcb5216a246d32eb4d5aad12 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Wed, 22 Jun 2016 17:25:42 -0700 Subject: [PATCH] fix(HtmlParser): correctly propagate the interpolation config across layers --- modules/@angular/compiler-cli/src/codegen.ts | 6 +- .../@angular/compiler-cli/src/extract_i18n.ts | 6 +- modules/@angular/compiler/src/assertions.ts | 13 +- .../@angular/compiler/src/compile_metadata.ts | 28 ++-- .../compiler/src/directive_normalizer.ts | 10 +- .../compiler/src/expression_parser/lexer.ts | 1 - .../compiler/src/expression_parser/parser.ts | 3 +- modules/@angular/compiler/src/html_lexer.ts | 123 ++++++++++-------- modules/@angular/compiler/src/html_parser.ts | 11 +- .../compiler/src/i18n/i18n_html_parser.ts | 35 ++--- .../compiler/src/i18n/message_extractor.ts | 19 +-- .../compiler/src/i18n/xmb_serializer.ts | 11 +- .../compiler/src/interpolation_config.ts | 24 +++- .../compiler/src/metadata_resolver.ts | 21 ++- .../@angular/compiler/src/template_parser.ts | 27 +++- .../@angular/compiler/test/html_lexer_spec.ts | 32 +++-- .../compiler/test/html_parser_spec.ts | 19 ++- .../compiler/test/i18n/expander_spec.ts | 6 +- .../test/i18n/i18n_html_parser_spec.ts | 17 ++- .../test/i18n/message_extractor_spec.ts | 12 +- .../dom_element_schema_registry_spec.ts | 6 +- 21 files changed, 258 insertions(+), 172 deletions(-) diff --git a/modules/@angular/compiler-cli/src/codegen.ts b/modules/@angular/compiler-cli/src/codegen.ts index d04c3c6f1b..4f565e44ee 100644 --- a/modules/@angular/compiler-cli/src/codegen.ts +++ b/modules/@angular/compiler-cli/src/codegen.ts @@ -126,7 +126,8 @@ export class CodeGenerator { const reflectorHost = new ReflectorHost(program, compilerHost, options, reflectorHostContext); const staticReflector = new StaticReflector(reflectorHost); StaticAndDynamicReflectionCapabilities.install(staticReflector); - const htmlParser = new HtmlParser(); + const expressionParser = new Parser(new Lexer()); + const htmlParser = new HtmlParser(expressionParser); const config = new compiler.CompilerConfig({ genDebugInfo: options.debug === true, defaultEncapsulation: ViewEncapsulation.Emulated, @@ -134,9 +135,8 @@ export class CodeGenerator { useJit: false }); const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config); - const parser = new Parser(new Lexer()); const tmplParser = new TemplateParser( - parser, new DomElementSchemaRegistry(), htmlParser, + expressionParser, new DomElementSchemaRegistry(), htmlParser, /*console*/ null, []); const resolver = new CompileMetadataResolver( new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector), diff --git a/modules/@angular/compiler-cli/src/extract_i18n.ts b/modules/@angular/compiler-cli/src/extract_i18n.ts index c9ae4f86c2..5f917f628e 100644 --- a/modules/@angular/compiler-cli/src/extract_i18n.ts +++ b/modules/@angular/compiler-cli/src/extract_i18n.ts @@ -137,7 +137,8 @@ class Extractor { const reflectorHost = new ReflectorHost(program, compilerHost, options); const staticReflector = new StaticReflector(reflectorHost); StaticAndDynamicReflectionCapabilities.install(staticReflector); - const htmlParser = new HtmlParser(); + const expressionParser = new Parser(new Lexer()); + const htmlParser = new HtmlParser(expressionParser); const config = new compiler.CompilerConfig({ genDebugInfo: true, defaultEncapsulation: ViewEncapsulation.Emulated, @@ -145,13 +146,12 @@ class Extractor { useJit: false }); const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config); - const parser = new Parser(new Lexer()); const resolver = new CompileMetadataResolver( new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector), new compiler.ViewResolver(staticReflector), config, staticReflector); // TODO(vicb): handle implicit - const extractor = new MessageExtractor(htmlParser, parser, [], {}); + const extractor = new MessageExtractor(htmlParser, expressionParser, [], {}); return new Extractor( options, program, compilerHost, staticReflector, resolver, normalizer, reflectorHost, diff --git a/modules/@angular/compiler/src/assertions.ts b/modules/@angular/compiler/src/assertions.ts index da6476f0d0..f3b0010de5 100644 --- a/modules/@angular/compiler/src/assertions.ts +++ b/modules/@angular/compiler/src/assertions.ts @@ -8,19 +8,18 @@ import {isDevMode} from '@angular/core'; -import {BaseException} from '../src/facade/exceptions'; -import {isArray, isBlank, isString} from '../src/facade/lang'; +import {isArray, isBlank, isPresent, isString} from '../src/facade/lang'; export function assertArrayOfStrings(identifier: string, value: any) { if (!isDevMode() || isBlank(value)) { return; } if (!isArray(value)) { - throw new BaseException(`Expected '${identifier}' to be an array of strings.`); + throw new Error(`Expected '${identifier}' to be an array of strings.`); } for (var i = 0; i < value.length; i += 1) { if (!isString(value[i])) { - throw new BaseException(`Expected '${identifier}' to be an array of strings.`); + throw new Error(`Expected '${identifier}' to be an array of strings.`); } } } @@ -33,15 +32,15 @@ const INTERPOLATION_BLACKLIST_REGEXPS = [ ]; export function assertInterpolationSymbols(identifier: string, value: any): void { - if (isDevMode() && !isBlank(value) && (!isArray(value) || value.length != 2)) { - throw new BaseException(`Expected '${identifier}' to be an array, [start, end].`); + if (isPresent(value) && !(isArray(value) && value.length == 2)) { + throw new Error(`Expected '${identifier}' to be an array, [start, end].`); } else if (isDevMode() && !isBlank(value)) { const start = value[0] as string; const end = value[1] as string; // black list checking INTERPOLATION_BLACKLIST_REGEXPS.forEach(regexp => { if (regexp.test(start) || regexp.test(end)) { - throw new BaseException(`['${start}', '${end}'] contains unusable interpolation symbol.`); + throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`); } }); } diff --git a/modules/@angular/compiler/src/compile_metadata.ts b/modules/@angular/compiler/src/compile_metadata.ts index 45a8ee829f..993dcf15d8 100644 --- a/modules/@angular/compiler/src/compile_metadata.ts +++ b/modules/@angular/compiler/src/compile_metadata.ts @@ -768,23 +768,17 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType { } return new CompileDirectiveMetadata({ - type: type, - isComponent: normalizeBool(isComponent), - selector: selector, - exportAs: exportAs, - changeDetection: changeDetection, + type, + isComponent: normalizeBool(isComponent), selector, exportAs, changeDetection, inputs: inputsMap, - outputs: outputsMap, - hostListeners: hostListeners, - hostProperties: hostProperties, - hostAttributes: hostAttributes, + outputs: outputsMap, hostListeners, hostProperties, hostAttributes, lifecycleHooks: isPresent(lifecycleHooks) ? lifecycleHooks : [], - providers: providers, - viewProviders: viewProviders, - queries: queries, - viewQueries: viewQueries, - precompile: precompile, - template: template + providers, + viewProviders, + queries, + viewQueries, + precompile, + template, }); } type: CompileTypeMetadata; @@ -803,8 +797,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType { queries: CompileQueryMetadata[]; viewQueries: CompileQueryMetadata[]; precompile: CompileTypeMetadata[]; - template: CompileTemplateMetadata; + constructor( {type, isComponent, selector, exportAs, changeDetection, inputs, outputs, hostListeners, hostProperties, hostAttributes, lifecycleHooks, providers, viewProviders, queries, @@ -827,7 +821,7 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType { queries?: CompileQueryMetadata[], viewQueries?: CompileQueryMetadata[], precompile?: CompileTypeMetadata[], - template?: CompileTemplateMetadata + template?: CompileTemplateMetadata, } = {}) { this.type = type; this.isComponent = isComponent; diff --git a/modules/@angular/compiler/src/directive_normalizer.ts b/modules/@angular/compiler/src/directive_normalizer.ts index 5140d9ebbb..2da28d1196 100644 --- a/modules/@angular/compiler/src/directive_normalizer.ts +++ b/modules/@angular/compiler/src/directive_normalizer.ts @@ -7,12 +7,9 @@ */ import {Injectable, ViewEncapsulation} from '@angular/core'; - -import {PromiseWrapper} from '../src/facade/async'; import {MapWrapper} from '../src/facade/collection'; import {BaseException} from '../src/facade/exceptions'; import {isBlank, isPresent} from '../src/facade/lang'; - import {CompileDirectiveMetadata, CompileStylesheetMetadata, CompileTemplateMetadata, CompileTypeMetadata} from './compile_metadata'; import {CompilerConfig} from './config'; import {HtmlAstVisitor, HtmlAttrAst, HtmlCommentAst, HtmlElementAst, HtmlExpansionAst, HtmlExpansionCaseAst, HtmlTextAst, htmlVisitAll} from './html_ast'; @@ -22,6 +19,7 @@ import {PreparsedElementType, preparseElement} from './template_preparser'; import {UrlResolver} from './url_resolver'; import {SyncAsyncResult} from './util'; import {XHR} from './xhr'; +import {InterpolationConfig} from './interpolation_config'; @Injectable() export class DirectiveNormalizer { @@ -99,7 +97,9 @@ export class DirectiveNormalizer { normalizeLoadedTemplate( directiveType: CompileTypeMetadata, templateMeta: CompileTemplateMetadata, template: string, templateAbsUrl: string): CompileTemplateMetadata { - const rootNodesAndErrors = this._htmlParser.parse(template, directiveType.name); + const interpolationConfig = InterpolationConfig.fromArray(templateMeta.interpolation); + const rootNodesAndErrors = + this._htmlParser.parse(template, directiveType.name, false, interpolationConfig); if (rootNodesAndErrors.errors.length > 0) { const errorString = rootNodesAndErrors.errors.join('\n'); throw new BaseException(`Template parse errors:\n${errorString}`); @@ -127,7 +127,7 @@ export class DirectiveNormalizer { encapsulation = ViewEncapsulation.None; } return new CompileTemplateMetadata({ - encapsulation: encapsulation, + encapsulation, template: template, templateUrl: templateAbsUrl, styles: allStyles, diff --git a/modules/@angular/compiler/src/expression_parser/lexer.ts b/modules/@angular/compiler/src/expression_parser/lexer.ts index 494fea22c5..6dfa49e017 100644 --- a/modules/@angular/compiler/src/expression_parser/lexer.ts +++ b/modules/@angular/compiler/src/expression_parser/lexer.ts @@ -8,7 +8,6 @@ import {Injectable} from '@angular/core'; import * as chars from '../chars'; -import {SetWrapper} from '../facade/collection'; import {BaseException} from '../facade/exceptions'; import {NumberWrapper, StringJoiner, StringWrapper, isPresent} from '../facade/lang'; diff --git a/modules/@angular/compiler/src/expression_parser/parser.ts b/modules/@angular/compiler/src/expression_parser/parser.ts index d5c17dbd78..812cbbcffc 100644 --- a/modules/@angular/compiler/src/expression_parser/parser.ts +++ b/modules/@angular/compiler/src/expression_parser/parser.ts @@ -37,8 +37,7 @@ function _createInterpolateRegExp(config: InterpolationConfig): RegExp { export class Parser { private errors: ParserError[] = []; - constructor(/** @internal */ - public _lexer: Lexer) {} + constructor(private _lexer: Lexer) {} parseAction( input: string, location: any, diff --git a/modules/@angular/compiler/src/html_lexer.ts b/modules/@angular/compiler/src/html_lexer.ts index edcbc5ad6e..0c6ca027a0 100644 --- a/modules/@angular/compiler/src/html_lexer.ts +++ b/modules/@angular/compiler/src/html_lexer.ts @@ -7,6 +7,7 @@ */ import * as chars from './chars'; +import {Parser as ExpressionParser} from './expression_parser/parser'; import {NumberWrapper, StringWrapper, isBlank, isPresent} from './facade/lang'; import {HtmlTagContentType, NAMED_ENTITIES, getHtmlTagDefinition} from './html_tags'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './interpolation_config'; @@ -32,6 +33,7 @@ export enum HtmlTokenType { EXPANSION_CASE_EXP_START, EXPANSION_CASE_EXP_END, EXPANSION_FORM_END, + INTERPOLATION, EOF } @@ -51,26 +53,27 @@ export class HtmlTokenizeResult { } export function tokenizeHtml( - sourceContent: string, sourceUrl: string, tokenizeExpansionForms: boolean = false, + sourceContent: string, sourceUrl: string, parser: ExpressionParser, + tokenizeExpansionForms: boolean = false, interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): HtmlTokenizeResult { return new _HtmlTokenizer( - new ParseSourceFile(sourceContent, sourceUrl), tokenizeExpansionForms, + new ParseSourceFile(sourceContent, sourceUrl), tokenizeExpansionForms, parser, interpolationConfig) .tokenize(); } -var CR_OR_CRLF_REGEXP = /\r\n?/g; +const _CR_OR_CRLF_REGEXP = /\r\n?/g; -function unexpectedCharacterErrorMsg(charCode: number): string { +function _unexpectedCharacterErrorMsg(charCode: number): string { var char = charCode === chars.$EOF ? 'EOF' : StringWrapper.fromCharCode(charCode); return `Unexpected character "${char}"`; } -function unknownEntityErrorMsg(entitySrc: string): string { +function _unknownEntityErrorMsg(entitySrc: string): string { return `Unknown entity "${entitySrc}" - use the "&#;" or "&#x;" syntax`; } -class ControlFlowError { +class _ControlFlowError { constructor(public error: HtmlTokenError) {} } @@ -92,11 +95,18 @@ class _HtmlTokenizer { tokens: HtmlToken[] = []; errors: HtmlTokenError[] = []; + /** + * @param _file The html source + * @param _tokenizeIcu Whether to tokenize ICU messages (considered as text nodes when false) + * @param _expressionParser Used to check syntax of interpolations + * @param _interpolationConfig + */ constructor( - private file: ParseSourceFile, private tokenizeExpansionForms: boolean, - private interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { - this._input = file.content; - this._length = file.content.length; + private _file: ParseSourceFile, private _tokenizeIcu: boolean, + private _expressionParser: ExpressionParser, + private _interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { + this._input = _file.content; + this._length = _file.content.length; this._advance(); } @@ -105,7 +115,7 @@ class _HtmlTokenizer { // In order to keep the original position in the source, we can not // pre-process it. // Instead CRs are processed right before instantiating the tokens. - return StringWrapper.replaceAll(content, CR_OR_CRLF_REGEXP, '\n'); + return StringWrapper.replaceAll(content, _CR_OR_CRLF_REGEXP, '\n'); } tokenize(): HtmlTokenizeResult { @@ -126,31 +136,11 @@ class _HtmlTokenizer { } else { this._consumeTagOpen(start); } - } else if ( - isExpansionFormStart(this._input, this._index, this.interpolationConfig.start) && - this.tokenizeExpansionForms) { - this._consumeExpansionFormStart(); - - } else if ( - isExpansionCaseStart(this._peek) && this._isInExpansionForm() && - this.tokenizeExpansionForms) { - this._consumeExpansionCaseStart(); - - } else if ( - this._peek === chars.$RBRACE && this._isInExpansionCase() && - this.tokenizeExpansionForms) { - this._consumeExpansionCaseEnd(); - - } else if ( - this._peek === chars.$RBRACE && this._isInExpansionForm() && - this.tokenizeExpansionForms) { - this._consumeExpansionFormEnd(); - - } else { + } else if (!this._tokenizeIcu || !this._tokenizeExpansionForm()) { this._consumeText(); } } catch (e) { - if (e instanceof ControlFlowError) { + if (e instanceof _ControlFlowError) { this.errors.push(e.error); } else { throw e; @@ -162,8 +152,38 @@ class _HtmlTokenizer { return new HtmlTokenizeResult(mergeTextTokens(this.tokens), this.errors); } + /** + * @returns {boolean} whether an ICU token has been created + * @internal + */ + private _tokenizeExpansionForm(): boolean { + if (isExpansionFormStart(this._input, this._index, this._interpolationConfig.start)) { + this._consumeExpansionFormStart(); + return true; + } + + if (isExpansionCaseStart(this._peek) && this._isInExpansionForm()) { + this._consumeExpansionCaseStart(); + return true; + } + + if (this._peek === chars.$RBRACE) { + if (this._isInExpansionCase()) { + this._consumeExpansionCaseEnd(); + return true; + } + + if (this._isInExpansionForm()) { + this._consumeExpansionFormEnd(); + return true; + } + } + + return false; + } + private _getLocation(): ParseLocation { - return new ParseLocation(this.file, this._index, this._line, this._column); + return new ParseLocation(this._file, this._index, this._line, this._column); } private _getSpan(start?: ParseLocation, end?: ParseLocation): ParseSourceSpan { @@ -196,16 +216,16 @@ class _HtmlTokenizer { return token; } - private _createError(msg: string, span: ParseSourceSpan): ControlFlowError { + private _createError(msg: string, span: ParseSourceSpan): _ControlFlowError { var error = new HtmlTokenError(msg, this._currentTokenType, span); this._currentTokenStart = null; this._currentTokenType = null; - return new ControlFlowError(error); + return new _ControlFlowError(error); } private _advance() { if (this._index >= this._length) { - throw this._createError(unexpectedCharacterErrorMsg(chars.$EOF), this._getSpan()); + throw this._createError(_unexpectedCharacterErrorMsg(chars.$EOF), this._getSpan()); } if (this._peek === chars.$LF) { this._line++; @@ -241,7 +261,7 @@ class _HtmlTokenizer { var location = this._getLocation(); if (!this._attemptCharCode(charCode)) { throw this._createError( - unexpectedCharacterErrorMsg(this._peek), this._getSpan(location, location)); + _unexpectedCharacterErrorMsg(this._peek), this._getSpan(location, location)); } } @@ -274,7 +294,7 @@ class _HtmlTokenizer { private _requireStr(chars: string) { var location = this._getLocation(); if (!this._attemptStr(chars)) { - throw this._createError(unexpectedCharacterErrorMsg(this._peek), this._getSpan(location)); + throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan(location)); } } @@ -288,7 +308,8 @@ class _HtmlTokenizer { var start = this._getLocation(); this._attemptCharCodeUntilFn(predicate); if (this._index - start.offset < len) { - throw this._createError(unexpectedCharacterErrorMsg(this._peek), this._getSpan(start, start)); + throw this._createError( + _unexpectedCharacterErrorMsg(this._peek), this._getSpan(start, start)); } } @@ -316,7 +337,7 @@ class _HtmlTokenizer { let numberStart = this._getLocation().offset; this._attemptCharCodeUntilFn(isDigitEntityEnd); if (this._peek != chars.$SEMICOLON) { - throw this._createError(unexpectedCharacterErrorMsg(this._peek), this._getSpan()); + throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan()); } this._advance(); let strNum = this._input.substring(numberStart, this._index - 1); @@ -325,7 +346,7 @@ class _HtmlTokenizer { return StringWrapper.fromCharCode(charCode); } catch (e) { let entity = this._input.substring(start.offset + 1, this._index - 1); - throw this._createError(unknownEntityErrorMsg(entity), this._getSpan(start)); + throw this._createError(_unknownEntityErrorMsg(entity), this._getSpan(start)); } } else { let startPosition = this._savePosition(); @@ -338,7 +359,7 @@ class _HtmlTokenizer { let name = this._input.substring(start.offset + 1, this._index - 1); let char = (NAMED_ENTITIES as any)[name]; if (isBlank(char)) { - throw this._createError(unknownEntityErrorMsg(name), this._getSpan(start)); + throw this._createError(_unknownEntityErrorMsg(name), this._getSpan(start)); } return char; } @@ -416,7 +437,7 @@ class _HtmlTokenizer { let lowercaseTagName: string; try { if (!chars.isAsciiLetter(this._peek)) { - throw this._createError(unexpectedCharacterErrorMsg(this._peek), this._getSpan()); + throw this._createError(_unexpectedCharacterErrorMsg(this._peek), this._getSpan()); } var nameStart = this._index; this._consumeTagOpenStart(start); @@ -433,7 +454,7 @@ class _HtmlTokenizer { } this._consumeTagOpenEnd(); } catch (e) { - if (e instanceof ControlFlowError) { + if (e instanceof _ControlFlowError) { // When the start tag is invalid, assume we want a "<" this._restorePosition(savedPos); // Back to back text tokens are merged at the end @@ -573,11 +594,11 @@ class _HtmlTokenizer { var parts: string[] = []; do { - if (this._attemptStr(this.interpolationConfig.start)) { - parts.push(this.interpolationConfig.start); + if (this._attemptStr(this._interpolationConfig.start)) { + parts.push(this._interpolationConfig.start); this._inInterpolation = true; - } else if (this._attemptStr(this.interpolationConfig.end) && this._inInterpolation) { - parts.push(this.interpolationConfig.end); + } else if (this._attemptStr(this._interpolationConfig.end) && this._inInterpolation) { + parts.push(this._interpolationConfig.end); this._inInterpolation = false; } else { parts.push(this._readChar(true)); @@ -592,8 +613,8 @@ class _HtmlTokenizer { return true; } - if (this.tokenizeExpansionForms) { - if (isExpansionFormStart(this._input, this._index, this.interpolationConfig.start)) { + if (this._tokenizeIcu) { + if (isExpansionFormStart(this._input, this._index, this._interpolationConfig.start)) { // start of an expansion form return true; } diff --git a/modules/@angular/compiler/src/html_parser.ts b/modules/@angular/compiler/src/html_parser.ts index 3a4eff1085..8746b7c82d 100644 --- a/modules/@angular/compiler/src/html_parser.ts +++ b/modules/@angular/compiler/src/html_parser.ts @@ -13,6 +13,8 @@ import {HtmlAst, HtmlAttrAst, HtmlTextAst, HtmlCommentAst, HtmlElementAst, HtmlE import {HtmlToken, HtmlTokenType, tokenizeHtml} from './html_lexer'; import {ParseError, ParseSourceSpan} from './parse_util'; import {getHtmlTagDefinition, getNsPrefix, mergeNsAndName} from './html_tags'; +import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './interpolation_config'; +import {Parser as ExpressionParser} from './expression_parser/parser'; export class HtmlTreeError extends ParseError { static create(elementName: string, span: ParseSourceSpan, msg: string): HtmlTreeError { @@ -28,9 +30,14 @@ export class HtmlParseTreeResult { @Injectable() export class HtmlParser { - parse(sourceContent: string, sourceUrl: string, parseExpansionForms: boolean = false): + constructor(public _expressionParser: ExpressionParser) {} + + parse( + sourceContent: string, sourceUrl: string, parseExpansionForms: boolean = false, + interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): HtmlParseTreeResult { - var tokensAndErrors = tokenizeHtml(sourceContent, sourceUrl, parseExpansionForms); + var tokensAndErrors = tokenizeHtml( + sourceContent, sourceUrl, this._expressionParser, parseExpansionForms, interpolationConfig); var treeAndErrors = new TreeBuilder(tokensAndErrors.tokens).build(); return new HtmlParseTreeResult( treeAndErrors.rootNodes, diff --git a/modules/@angular/compiler/src/i18n/i18n_html_parser.ts b/modules/@angular/compiler/src/i18n/i18n_html_parser.ts index 3b54c53d82..e1254776cd 100644 --- a/modules/@angular/compiler/src/i18n/i18n_html_parser.ts +++ b/modules/@angular/compiler/src/i18n/i18n_html_parser.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Parser} from '../expression_parser/parser'; +import {Parser as ExpressionParser} from '../expression_parser/parser'; import {ListWrapper, StringMapWrapper} from '../facade/collection'; import {BaseException} from '../facade/exceptions'; import {NumberWrapper, RegExpWrapper, isPresent} from '../facade/lang'; @@ -55,9 +55,9 @@ export class I18nHtmlParser implements HtmlParser { private _interpolationConfig: InterpolationConfig; constructor( - private _htmlParser: HtmlParser, private _parser: Parser, private _messagesContent: string, - private _messages: {[key: string]: HtmlAst[]}, private _implicitTags: string[], - private _implicitAttrs: {[k: string]: string[]}) {} + private _htmlParser: HtmlParser, public _expressionParser: ExpressionParser, + private _messagesContent: string, private _messages: {[key: string]: HtmlAst[]}, + private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {} parse( sourceContent: string, sourceUrl: string, parseExpansionForms: boolean = false, @@ -66,18 +66,18 @@ export class I18nHtmlParser implements HtmlParser { this.errors = []; this._interpolationConfig = interpolationConfig; - let res = this._htmlParser.parse(sourceContent, sourceUrl, true); + let res = this._htmlParser.parse(sourceContent, sourceUrl, true, interpolationConfig); if (res.errors.length > 0) { return res; - } else { - let expanded = expandNodes(res.rootNodes); - let nodes = this._recurse(expanded.nodes); - this.errors.push(...expanded.errors); - - return this.errors.length > 0 ? new HtmlParseTreeResult([], this.errors) : - new HtmlParseTreeResult(nodes, []); } + + const expanded = expandNodes(res.rootNodes); + const nodes = this._recurse(expanded.nodes); + this.errors.push(...expanded.errors); + + return this.errors.length > 0 ? new HtmlParseTreeResult([], this.errors) : + new HtmlParseTreeResult(nodes, []); } private _processI18nPart(part: Part): HtmlAst[] { @@ -94,7 +94,7 @@ export class I18nHtmlParser implements HtmlParser { } private _mergeI18Part(part: Part): HtmlAst[] { - let message = part.createMessage(this._parser, this._interpolationConfig); + let message = part.createMessage(this._expressionParser, this._interpolationConfig); let messageId = id(message); if (!StringMapWrapper.contains(this._messages, messageId)) { throw new I18nError( @@ -200,7 +200,7 @@ export class I18nHtmlParser implements HtmlParser { } private _mergeTextInterpolation(t: HtmlElementAst, originalNode: HtmlTextAst): HtmlTextAst { - let split = this._parser.splitInterpolation( + let split = this._expressionParser.splitInterpolation( originalNode.value, originalNode.sourceSpan.toString(), this._interpolationConfig); let exps = isPresent(split) ? split.expressions : []; @@ -237,9 +237,10 @@ export class I18nHtmlParser implements HtmlParser { res.push(attr); return; } - message = messageFromAttribute(this._parser, this._interpolationConfig, attr); + message = messageFromAttribute(this._expressionParser, this._interpolationConfig, attr); } else { - message = messageFromI18nAttribute(this._parser, this._interpolationConfig, el, i18ns[0]); + message = messageFromI18nAttribute( + this._expressionParser, this._interpolationConfig, el, i18ns[0]); } let messageId = id(message); @@ -258,7 +259,7 @@ export class I18nHtmlParser implements HtmlParser { } private _replaceInterpolationInAttr(attr: HtmlAttrAst, msg: HtmlAst[]): string { - let split = this._parser.splitInterpolation( + let split = this._expressionParser.splitInterpolation( attr.value, attr.sourceSpan.toString(), this._interpolationConfig); let exps = isPresent(split) ? split.expressions : []; diff --git a/modules/@angular/compiler/src/i18n/message_extractor.ts b/modules/@angular/compiler/src/i18n/message_extractor.ts index 03fbdbde58..6509199597 100644 --- a/modules/@angular/compiler/src/i18n/message_extractor.ts +++ b/modules/@angular/compiler/src/i18n/message_extractor.ts @@ -6,17 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ -import {Parser} from '../expression_parser/parser'; +import {Parser as ExpressionParser} from '../expression_parser/parser'; import {StringMapWrapper} from '../facade/collection'; import {isPresent} from '../facade/lang'; import {HtmlAst, HtmlElementAst} from '../html_ast'; import {HtmlParser} from '../html_parser'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../interpolation_config'; import {ParseError} from '../parse_util'; + import {Message, id} from './message'; import {I18N_ATTR_PREFIX, I18nError, Part, messageFromAttribute, messageFromI18nAttribute, partition} from './shared'; + /** * All messages extracted from a template. */ @@ -101,8 +103,8 @@ export class MessageExtractor { private _errors: ParseError[]; constructor( - private _htmlParser: HtmlParser, private _parser: Parser, private _implicitTags: string[], - private _implicitAttrs: {[k: string]: string[]}) {} + private _htmlParser: HtmlParser, private _expressionParser: ExpressionParser, + private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {} extract( template: string, sourceUrl: string, @@ -110,7 +112,7 @@ export class MessageExtractor { this._messages = []; this._errors = []; - const res = this._htmlParser.parse(template, sourceUrl, true); + const res = this._htmlParser.parse(template, sourceUrl, true, interpolationConfig); if (res.errors.length == 0) { this._recurse(res.rootNodes, interpolationConfig); @@ -121,7 +123,7 @@ export class MessageExtractor { private _extractMessagesFromPart(part: Part, interpolationConfig: InterpolationConfig): void { if (part.hasI18n) { - this._messages.push(part.createMessage(this._parser, interpolationConfig)); + this._messages.push(part.createMessage(this._expressionParser, interpolationConfig)); this._recurseToExtractMessagesFromAttributes(part.children, interpolationConfig); } else { this._recurse(part.children, interpolationConfig); @@ -159,7 +161,8 @@ export class MessageExtractor { p.attrs.filter(attr => attr.name.startsWith(I18N_ATTR_PREFIX)).forEach(attr => { try { explicitAttrs.push(attr.name.substring(I18N_ATTR_PREFIX.length)); - this._messages.push(messageFromI18nAttribute(this._parser, interpolationConfig, p, attr)); + this._messages.push( + messageFromI18nAttribute(this._expressionParser, interpolationConfig, p, attr)); } catch (e) { if (e instanceof I18nError) { this._errors.push(e); @@ -174,7 +177,7 @@ export class MessageExtractor { .filter(attr => explicitAttrs.indexOf(attr.name) == -1) .filter(attr => transAttrs.indexOf(attr.name) > -1) .forEach( - attr => - this._messages.push(messageFromAttribute(this._parser, interpolationConfig, attr))); + attr => this._messages.push( + messageFromAttribute(this._expressionParser, interpolationConfig, attr))); } } diff --git a/modules/@angular/compiler/src/i18n/xmb_serializer.ts b/modules/@angular/compiler/src/i18n/xmb_serializer.ts index a78c9894f6..9d96354b41 100644 --- a/modules/@angular/compiler/src/i18n/xmb_serializer.ts +++ b/modules/@angular/compiler/src/i18n/xmb_serializer.ts @@ -6,6 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; + import {RegExpWrapper, isBlank, isPresent} from '../facade/lang'; import {HtmlAst, HtmlElementAst} from '../html_ast'; import {HtmlParser} from '../html_parser'; @@ -34,9 +37,11 @@ export class XmbDeserializationError extends ParseError { } export function deserializeXmb(content: string, url: string): XmbDeserializationResult { - let parser = new HtmlParser(); - let normalizedContent = _expandPlaceholder(content.trim()); - let parsed = parser.parse(normalizedContent, url); + const expLexer = new ExpressionLexer(); + const expParser = new ExpressionParser(expLexer); + const parser = new HtmlParser(expParser); + const normalizedContent = _expandPlaceholder(content.trim()); + const parsed = parser.parse(normalizedContent, url); if (parsed.errors.length > 0) { return new XmbDeserializationResult(null, {}, parsed.errors); diff --git a/modules/@angular/compiler/src/interpolation_config.ts b/modules/@angular/compiler/src/interpolation_config.ts index 47581bf1df..20176b15f0 100644 --- a/modules/@angular/compiler/src/interpolation_config.ts +++ b/modules/@angular/compiler/src/interpolation_config.ts @@ -6,12 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -export interface InterpolationConfig { - start: string; - end: string; +import {assertInterpolationSymbols} from './assertions'; +import {isBlank} from './facade/lang'; + +export class InterpolationConfig { + static fromArray(markers: [string, string]): InterpolationConfig { + if (isBlank(markers)) { + // TODO:bad ?? + return DEFAULT_INTERPOLATION_CONFIG; + } + + assertInterpolationSymbols('interpolation', markers); + return new InterpolationConfig(markers[0], markers[1]); + } + + constructor(public start: string, public end: string){}; } -export const DEFAULT_INTERPOLATION_CONFIG: InterpolationConfig = { - start: '{{', - end: '}}' -}; +export const DEFAULT_INTERPOLATION_CONFIG: InterpolationConfig = + new InterpolationConfig('{{', '}}'); diff --git a/modules/@angular/compiler/src/metadata_resolver.ts b/modules/@angular/compiler/src/metadata_resolver.ts index 8f226ce607..3c27af76ff 100644 --- a/modules/@angular/compiler/src/metadata_resolver.ts +++ b/modules/@angular/compiler/src/metadata_resolver.ts @@ -111,8 +111,8 @@ export class CompileMetadataResolver { if (isBlank(meta)) { var dirMeta = this._directiveResolver.resolve(directiveType); var templateMeta: cpl.CompileTemplateMetadata = null; - var changeDetectionStrategy: any /** TODO #9100 */ = null; - var viewProviders: any[] /** TODO #9100 */ = []; + var changeDetectionStrategy: ChangeDetectionStrategy = null; + var viewProviders: Array = []; var moduleUrl = staticTypeModuleUrl(directiveType); var precompileTypes: cpl.CompileTypeMetadata[] = []; if (dirMeta instanceof ComponentMetadata) { @@ -147,7 +147,7 @@ export class CompileMetadataResolver { } } - var providers: any[] /** TODO #9100 */ = []; + var providers: Array = []; if (isPresent(dirMeta.providers)) { providers = this.getProvidersMetadata( verifyNonBlankProviders(directiveType, dirMeta.providers, 'providers'), @@ -492,14 +492,13 @@ export class CompileMetadataResolver { getQueriesMetadata( queries: {[key: string]: QueryMetadata}, isViewQuery: boolean, directiveType: Type): cpl.CompileQueryMetadata[] { - var compileQueries: any[] /** TODO #9100 */ = []; - StringMapWrapper.forEach( - queries, (query: any /** TODO #9100 */, propertyName: any /** TODO #9100 */) => { - if (query.isViewQuery === isViewQuery) { - compileQueries.push(this.getQueryMetadata(query, propertyName, directiveType)); - } - }); - return compileQueries; + var res: cpl.CompileQueryMetadata[] = []; + StringMapWrapper.forEach(queries, (query: QueryMetadata, propertyName: string) => { + if (query.isViewQuery === isViewQuery) { + res.push(this.getQueryMetadata(query, propertyName, directiveType)); + } + }); + return res; } getQueryMetadata(q: QueryMetadata, propertyName: string, typeOrFunc: Type|Function): diff --git a/modules/@angular/compiler/src/template_parser.ts b/modules/@angular/compiler/src/template_parser.ts index 0eec172660..c9e3066e0d 100644 --- a/modules/@angular/compiler/src/template_parser.ts +++ b/modules/@angular/compiler/src/template_parser.ts @@ -101,15 +101,23 @@ export class TemplateParser { const errorString = errors.join('\n'); throw new BaseException(`Template parse errors:\n${errorString}`); } + return result.templateAst; } tryParse( component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[], templateUrl: string): TemplateParseResult { - const htmlAstWithErrors = this._htmlParser.parse(template, templateUrl); + // TODO: bad ??? + let interpolationConfig: any; + if (component.template) { + interpolationConfig = InterpolationConfig.fromArray(component.template.interpolation); + } + const htmlAstWithErrors = + this._htmlParser.parse(template, templateUrl, false, interpolationConfig); const errors: ParseError[] = htmlAstWithErrors.errors; - let result: any[]; + let result: TemplateAst[]; + if (htmlAstWithErrors.rootNodes.length > 0) { const uniqDirectives = removeDuplicates(directives); const uniqPipes = removeDuplicates(pipes); @@ -137,10 +145,12 @@ export class TemplateParser { } /** @internal */ - _assertNoReferenceDuplicationOnTemplate(result: any[], errors: TemplateParseError[]): void { - const existingReferences: any[] /** TODO #???? */ = []; - result.filter(element => !!element.references) - .forEach(element => element.references.forEach((reference: any /** TODO #???? */) => { + _assertNoReferenceDuplicationOnTemplate(result: TemplateAst[], errors: TemplateParseError[]): + void { + const existingReferences: string[] = []; + + result.filter(element => !!(element).references) + .forEach(element => (element).references.forEach((reference: ReferenceAst) => { const name = reference.name; if (existingReferences.indexOf(name) < 0) { existingReferences.push(name); @@ -167,19 +177,24 @@ class TemplateParseVisitor implements HtmlAstVisitor { pipes: CompilePipeMetadata[], private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry) { this.selectorMatcher = new SelectorMatcher(); + const tempMeta = providerViewContext.component.template; + + // TODO if (isPresent(tempMeta) && isPresent(tempMeta.interpolation)) { this._interpolationConfig = { start: tempMeta.interpolation[0], end: tempMeta.interpolation[1] }; } + ListWrapper.forEachWithIndex( directives, (directive: CompileDirectiveMetadata, index: number) => { const selector = CssSelector.parse(directive.selector); this.selectorMatcher.addSelectables(selector, directive); this.directivesIndex.set(directive, index); }); + this.pipesByName = new Map(); pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe)); } diff --git a/modules/@angular/compiler/test/html_lexer_spec.ts b/modules/@angular/compiler/test/html_lexer_spec.ts index f6076196e6..fbb63cfde9 100644 --- a/modules/@angular/compiler/test/html_lexer_spec.ts +++ b/modules/@angular/compiler/test/html_lexer_spec.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; import {HtmlToken, HtmlTokenError, HtmlTokenType, tokenizeHtml} from '@angular/compiler/src/html_lexer'; import {InterpolationConfig} from '@angular/compiler/src/interpolation_config'; import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler/src/parse_util'; import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; -import {BaseException} from '../src/facade/exceptions'; - export function main() { describe('HtmlLexer', () => { describe('line/column numbers', () => { @@ -358,7 +358,15 @@ export function main() { expect(tokenizeAndHumanizeParts('{{ a }}')).toEqual([ [HtmlTokenType.TEXT, '{{ a }}'], [HtmlTokenType.EOF] ]); + }); + it('should detect interpolation end', () => { + expect(tokenizeAndHumanizeParts('{{value|filter:{params: {strict: true}}}}')).toEqual([ + [HtmlTokenType.TEXT, '{{ a }}'], [HtmlTokenType.EOF] + ]); + }); + + it('should parse interpolation with custom markers', () => { expect(tokenizeAndHumanizeParts('{% a %}', null, {start: '{%', end: '%}'})).toEqual([ [HtmlTokenType.TEXT, '{% a %}'], [HtmlTokenType.EOF] ]); @@ -598,11 +606,14 @@ export function main() { function tokenizeWithoutErrors( input: string, tokenizeExpansionForms: boolean = false, interpolationConfig?: InterpolationConfig): HtmlToken[] { - var tokenizeResult = tokenizeHtml(input, 'someUrl', tokenizeExpansionForms, interpolationConfig); + var tokenizeResult = tokenizeHtml( + input, 'someUrl', _getExpressionParser(), tokenizeExpansionForms, interpolationConfig); + if (tokenizeResult.errors.length > 0) { - var errorString = tokenizeResult.errors.join('\n'); - throw new BaseException(`Unexpected parse errors:\n${errorString}`); + const errorString = tokenizeResult.errors.join('\n'); + throw new Error(`Unexpected parse errors:\n${errorString}`); } + return tokenizeResult.tokens; } @@ -627,9 +638,10 @@ function tokenizeAndHumanizeLineColumn(input: string): any[] { } function tokenizeAndHumanizeErrors(input: string): any[] { - return tokenizeHtml(input, 'someUrl') - .errors.map( - tokenError => - [tokenError.tokenType, tokenError.msg, - humanizeLineColumn(tokenError.span.start)]); + return tokenizeHtml(input, 'someUrl', _getExpressionParser()) + .errors.map(e => [e.tokenType, e.msg, humanizeLineColumn(e.span.start)]); +} + +function _getExpressionParser(): ExpressionParser { + return new ExpressionParser(new ExpressionLexer()); } diff --git a/modules/@angular/compiler/test/html_parser_spec.ts b/modules/@angular/compiler/test/html_parser_spec.ts index 133f61eda3..c24491cce2 100644 --- a/modules/@angular/compiler/test/html_parser_spec.ts +++ b/modules/@angular/compiler/test/html_parser_spec.ts @@ -6,6 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; import {HtmlAttrAst, HtmlCommentAst, HtmlElementAst, HtmlExpansionAst, HtmlExpansionCaseAst, HtmlTextAst} from '@angular/compiler/src/html_ast'; import {HtmlTokenType} from '@angular/compiler/src/html_lexer'; import {HtmlParseTreeResult, HtmlParser, HtmlTreeError} from '@angular/compiler/src/html_parser'; @@ -17,7 +19,14 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './html_as export function main() { describe('HtmlParser', () => { var parser: HtmlParser; - beforeEach(() => { parser = new HtmlParser(); }); + var expLexer: ExpressionLexer; + var expParser: ExpressionParser; + + beforeEach(() => { + expLexer = new ExpressionLexer(); + expParser = new ExpressionParser(expLexer); + parser = new HtmlParser(expParser); + }); describe('parse', () => { describe('text nodes', () => { @@ -412,12 +421,12 @@ export function main() { } export function humanizeErrors(errors: ParseError[]): any[] { - return errors.map(error => { - if (error instanceof HtmlTreeError) { + return errors.map(e => { + if (e instanceof HtmlTreeError) { // Parser errors - return [error.elementName, error.msg, humanizeLineColumn(error.span.start)]; + return [e.elementName, e.msg, humanizeLineColumn(e.span.start)]; } // Tokenizer errors - return [(error).tokenType, error.msg, humanizeLineColumn(error.span.start)]; + return [(e).tokenType, e.msg, humanizeLineColumn(e.span.start)]; }); } diff --git a/modules/@angular/compiler/test/i18n/expander_spec.ts b/modules/@angular/compiler/test/i18n/expander_spec.ts index a5a3e9c6a8..8f5f6844c4 100644 --- a/modules/@angular/compiler/test/i18n/expander_spec.ts +++ b/modules/@angular/compiler/test/i18n/expander_spec.ts @@ -6,6 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; import {HtmlAttrAst, HtmlElementAst, HtmlTextAst} from '@angular/compiler/src/html_ast'; import {HtmlParser} from '@angular/compiler/src/html_parser'; import {ExpansionResult, expandNodes} from '@angular/compiler/src/i18n/expander'; @@ -16,7 +18,9 @@ import {ddescribe, describe, expect, iit, it} from '@angular/core/testing/testin export function main() { describe('Expander', () => { function expand(template: string): ExpansionResult { - const htmlParser = new HtmlParser(); + const expLexer = new ExpressionLexer(); + const expParser = new ExpressionParser(expLexer); + const htmlParser = new HtmlParser(expParser); const res = htmlParser.parse(template, 'url', true); return expandNodes(res.rootNodes); } diff --git a/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts b/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts index 6c1d5f5fa6..c18f779a7c 100644 --- a/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts +++ b/modules/@angular/compiler/test/i18n/i18n_html_parser_spec.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Lexer} from '@angular/compiler/src/expression_parser/lexer'; -import {Parser} from '@angular/compiler/src/expression_parser/parser'; +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; import {HtmlAttrAst, HtmlElementAst, HtmlTextAst} from '@angular/compiler/src/html_ast'; import {HtmlParseTreeResult, HtmlParser} from '@angular/compiler/src/html_parser'; import {I18nHtmlParser} from '@angular/compiler/src/i18n/i18n_html_parser'; @@ -26,8 +26,8 @@ export function main() { template: string, messages: {[key: string]: string}, implicitTags: string[] = [], implicitAttrs: {[k: string]: string[]} = {}, interpolation?: InterpolationConfig): HtmlParseTreeResult { - var parser = new Parser(new Lexer()); - let htmlParser = new HtmlParser(); + var expParser = new ExpressionParser(new ExpressionLexer()); + let htmlParser = new HtmlParser(expParser); let msgs = ''; StringMapWrapper.forEach( @@ -35,7 +35,7 @@ export function main() { let res = deserializeXmb(`${msgs}`, 'someUrl'); return new I18nHtmlParser( - htmlParser, parser, res.content, res.messages, implicitTags, implicitAttrs) + htmlParser, expParser, res.content, res.messages, implicitTags, implicitAttrs) .parse(template, 'someurl', true, interpolation); } @@ -80,8 +80,11 @@ export function main() { expect(humanizeDom(parse( '
', translations, [], {}, - {start: '{%', end: '%}'}))) - .toEqual([[HtmlElementAst, 'div', 0], [HtmlAttrAst, 'value', '{%b%} or {%a%}']]); + InterpolationConfig.fromArray(['{%', '%}'])))) + .toEqual([ + [HtmlElementAst, 'div', 0], + [HtmlAttrAst, 'value', '{%b%} or {%a%}'], + ]); }); it('should handle interpolation with custom placeholder names', () => { diff --git a/modules/@angular/compiler/test/i18n/message_extractor_spec.ts b/modules/@angular/compiler/test/i18n/message_extractor_spec.ts index 05d335ccd9..9d4964e83a 100644 --- a/modules/@angular/compiler/test/i18n/message_extractor_spec.ts +++ b/modules/@angular/compiler/test/i18n/message_extractor_spec.ts @@ -6,21 +6,23 @@ * found in the LICENSE file at https://angular.io/license */ -import {Lexer} from '@angular/compiler/src/expression_parser/lexer'; -import {Parser} from '@angular/compiler/src/expression_parser/parser'; +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; import {HtmlParser} from '@angular/compiler/src/html_parser'; import {Message} from '@angular/compiler/src/i18n/message'; import {MessageExtractor, removeDuplicates} from '@angular/compiler/src/i18n/message_extractor'; import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal'; + export function main() { describe('MessageExtractor', () => { let extractor: MessageExtractor; beforeEach(() => { - const htmlParser = new HtmlParser(); - const parser = new Parser(new Lexer()); - extractor = new MessageExtractor(htmlParser, parser, ['i18n-tag'], {'i18n-el': ['trans']}); + const expParser = new ExpressionParser(new ExpressionLexer()); + const htmlParser = new HtmlParser(expParser); + // TODO: pass expression parser + extractor = new MessageExtractor(htmlParser, expParser, ['i18n-tag'], {'i18n-el': ['trans']}); }); it('should extract from elements with the i18n attr', () => { diff --git a/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts b/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts index ff8a7cfdde..0622e47ddb 100644 --- a/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts +++ b/modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts @@ -6,6 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {Lexer as ExpressionLexer} from '@angular/compiler/src/expression_parser/lexer'; +import {Parser as ExpressionParser} from '@angular/compiler/src/expression_parser/parser'; import {HtmlElementAst} from '@angular/compiler/src/html_ast'; import {HtmlParser} from '@angular/compiler/src/html_parser'; import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry'; @@ -68,7 +70,9 @@ export function main() { }); it('should detect properties on namespaced elements', () => { - let htmlAst = new HtmlParser().parse('', 'TestComp'); + const expLexer = new ExpressionLexer(); + const expParser = new ExpressionParser(expLexer); + let htmlAst = new HtmlParser(expParser).parse('', 'TestComp'); let nodeName = (htmlAst.rootNodes[0]).name; expect(registry.hasProperty(nodeName, 'type')).toBeTruthy(); });