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