| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | import { | 
					
						
							|  |  |  |   ListWrapper, | 
					
						
							|  |  |  |   StringMapWrapper, | 
					
						
							|  |  |  |   SetWrapper, | 
					
						
							|  |  |  |   MapWrapper | 
					
						
							|  |  |  | } from 'angular2/src/facade/collection'; | 
					
						
							|  |  |  | import {RegExpWrapper, isPresent, StringWrapper, isBlank, isArray} from 'angular2/src/facade/lang'; | 
					
						
							| 
									
										
										
										
											2015-11-20 16:55:56 -08:00
										 |  |  | import {Injectable, Inject, OpaqueToken, Optional} from 'angular2/core'; | 
					
						
							| 
									
										
										
										
											2015-11-19 10:51:16 -08:00
										 |  |  | import {CONST_EXPR} from 'angular2/src/facade/lang'; | 
					
						
							| 
									
										
										
										
											2015-11-06 17:34:07 -08:00
										 |  |  | import {BaseException} from 'angular2/src/facade/exceptions'; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | import { | 
					
						
							|  |  |  |   AST, | 
					
						
							|  |  |  |   Interpolation, | 
					
						
							|  |  |  |   ASTWithSource, | 
					
						
							|  |  |  |   TemplateBinding, | 
					
						
							|  |  |  |   RecursiveAstVisitor, | 
					
						
							|  |  |  |   BindingPipe | 
					
						
							|  |  |  | } from './expression_parser/ast'; | 
					
						
							|  |  |  | import {Parser} from './expression_parser/parser'; | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   CompileTokenMap, | 
					
						
							|  |  |  |   CompileDirectiveMetadata, | 
					
						
							|  |  |  |   CompilePipeMetadata, | 
					
						
							|  |  |  |   CompileMetadataWithType, | 
					
						
							|  |  |  |   CompileProviderMetadata, | 
					
						
							|  |  |  |   CompileTokenMetadata, | 
					
						
							|  |  |  |   CompileTypeMetadata | 
					
						
							|  |  |  | } from './compile_metadata'; | 
					
						
							| 
									
										
										
										
											2015-09-14 15:59:09 -07:00
										 |  |  | import {HtmlParser} from './html_parser'; | 
					
						
							| 
									
										
										
										
											2016-01-08 12:01:29 -08:00
										 |  |  | import {splitNsName, mergeNsAndName} from './html_tags'; | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | import {ParseSourceSpan, ParseError, ParseLocation} from './parse_util'; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | import {MAX_INTERPOLATION_VALUES} from 'angular2/src/core/linker/view_utils'; | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  | import { | 
					
						
							|  |  |  |   ElementAst, | 
					
						
							|  |  |  |   BoundElementPropertyAst, | 
					
						
							|  |  |  |   BoundEventAst, | 
					
						
							|  |  |  |   VariableAst, | 
					
						
							|  |  |  |   TemplateAst, | 
					
						
							|  |  |  |   TemplateAstVisitor, | 
					
						
							|  |  |  |   templateVisitAll, | 
					
						
							|  |  |  |   TextAst, | 
					
						
							|  |  |  |   BoundTextAst, | 
					
						
							|  |  |  |   EmbeddedTemplateAst, | 
					
						
							|  |  |  |   AttrAst, | 
					
						
							|  |  |  |   NgContentAst, | 
					
						
							|  |  |  |   PropertyBindingType, | 
					
						
							|  |  |  |   DirectiveAst, | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   BoundDirectivePropertyAst, | 
					
						
							|  |  |  |   ProviderAst, | 
					
						
							|  |  |  |   ProviderAstType | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  | } from './template_ast'; | 
					
						
							| 
									
										
										
										
											2015-11-05 14:07:57 -08:00
										 |  |  | import {CssSelector, SelectorMatcher} from 'angular2/src/compiler/selector'; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 14:07:57 -08:00
										 |  |  | import {ElementSchemaRegistry} from 'angular2/src/compiler/schema/element_schema_registry'; | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  | import {preparseElement, PreparsedElement, PreparsedElementType} from './template_preparser'; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-14 09:39:40 -07:00
										 |  |  | import {isStyleUrlResolvable} from './style_url_resolver'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  | import { | 
					
						
							|  |  |  |   HtmlAstVisitor, | 
					
						
							|  |  |  |   HtmlAst, | 
					
						
							|  |  |  |   HtmlElementAst, | 
					
						
							|  |  |  |   HtmlAttrAst, | 
					
						
							|  |  |  |   HtmlTextAst, | 
					
						
							|  |  |  |   HtmlCommentAst, | 
					
						
							| 
									
										
										
										
											2016-04-12 11:46:49 -07:00
										 |  |  |   HtmlExpansionAst, | 
					
						
							|  |  |  |   HtmlExpansionCaseAst, | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   htmlVisitAll | 
					
						
							|  |  |  | } from './html_ast'; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  | import {splitAtColon} from './util'; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | import {ProviderElementContext, ProviderViewContext} from './provider_parser'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | // Group 1 = "bind-"
 | 
					
						
							|  |  |  | // Group 2 = "var-" or "#"
 | 
					
						
							|  |  |  | // Group 3 = "on-"
 | 
					
						
							|  |  |  | // Group 4 = "bindon-"
 | 
					
						
							|  |  |  | // Group 5 = the identifier after "bind-", "var-/#", or "on-"
 | 
					
						
							| 
									
										
										
										
											2016-01-12 22:40:22 -08:00
										 |  |  | // Group 6 = identifier inside [()]
 | 
					
						
							|  |  |  | // Group 7 = identifier inside []
 | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | // Group 8 = identifier inside ()
 | 
					
						
							|  |  |  | var BIND_NAME_REGEXP = | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |     /^(?:(?:(?:(bind-)|(var-|#)|(on-)|(bindon-))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/g; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const TEMPLATE_ELEMENT = 'template'; | 
					
						
							|  |  |  | const TEMPLATE_ATTR = 'template'; | 
					
						
							|  |  |  | const TEMPLATE_ATTR_PREFIX = '*'; | 
					
						
							|  |  |  | const CLASS_ATTR = 'class'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | var PROPERTY_PARTS_SEPARATOR = '.'; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | const ATTRIBUTE_PREFIX = 'attr'; | 
					
						
							|  |  |  | const CLASS_PREFIX = 'class'; | 
					
						
							|  |  |  | const STYLE_PREFIX = 'style'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  | var TEXT_CSS_SELECTOR = CssSelector.parse('*')[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-03 15:49:09 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Provides an array of {@link TemplateAstVisitor}s which will be used to transform | 
					
						
							|  |  |  |  * parsed templates before compilation is invoked, allowing custom expression syntax | 
					
						
							|  |  |  |  * and other advanced transformations. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is currently an internal-only feature and not meant for general use. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2015-11-19 10:51:16 -08:00
										 |  |  | export const TEMPLATE_TRANSFORMS = CONST_EXPR(new OpaqueToken('TemplateTransforms')); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | export class TemplateParseError extends ParseError { | 
					
						
							| 
									
										
										
										
											2016-02-16 16:46:51 -08:00
										 |  |  |   constructor(message: string, span: ParseSourceSpan) { super(span, message); } | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:14:08 -07:00
										 |  |  | export class TemplateParseResult { | 
					
						
							|  |  |  |   constructor(public templateAst?: TemplateAst[], public errors?: ParseError[]) {} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-14 15:59:09 -07:00
										 |  |  | @Injectable() | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | export class TemplateParser { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   constructor(private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry, | 
					
						
							|  |  |  |               private _htmlParser: HtmlParser, | 
					
						
							|  |  |  |               @Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   parse(component: CompileDirectiveMetadata, template: string, | 
					
						
							|  |  |  |         directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[], | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         templateUrl: string): TemplateAst[] { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     var result = this.tryParse(component, template, directives, pipes, templateUrl); | 
					
						
							| 
									
										
										
										
											2016-03-31 12:14:08 -07:00
										 |  |  |     if (isPresent(result.errors)) { | 
					
						
							|  |  |  |       var errorString = result.errors.join('\n'); | 
					
						
							|  |  |  |       throw new BaseException(`Template parse errors:\n${errorString}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result.templateAst; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   tryParse(component: CompileDirectiveMetadata, template: string, | 
					
						
							|  |  |  |            directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[], | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |            templateUrl: string): TemplateParseResult { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     var htmlAstWithErrors = this._htmlParser.parse(template, templateUrl); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     var errors: ParseError[] = htmlAstWithErrors.errors; | 
					
						
							|  |  |  |     var result; | 
					
						
							|  |  |  |     if (htmlAstWithErrors.rootNodes.length > 0) { | 
					
						
							|  |  |  |       var uniqDirectives = <CompileDirectiveMetadata[]>removeDuplicates(directives); | 
					
						
							|  |  |  |       var uniqPipes = <CompilePipeMetadata[]>removeDuplicates(pipes); | 
					
						
							|  |  |  |       var providerViewContext = | 
					
						
							|  |  |  |           new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan); | 
					
						
							|  |  |  |       var parseVisitor = new TemplateParseVisitor(providerViewContext, uniqDirectives, uniqPipes, | 
					
						
							|  |  |  |                                                   this._exprParser, this._schemaRegistry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       result = htmlVisitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT); | 
					
						
							|  |  |  |       errors = errors.concat(parseVisitor.errors).concat(providerViewContext.errors); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       result = []; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     if (errors.length > 0) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:14:08 -07:00
										 |  |  |       return new TemplateParseResult(result, errors); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-11-19 10:51:16 -08:00
										 |  |  |     if (isPresent(this.transforms)) { | 
					
						
							|  |  |  |       this.transforms.forEach( | 
					
						
							|  |  |  |           (transform: TemplateAstVisitor) => { result = templateVisitAll(transform, result); }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-03-31 12:14:08 -07:00
										 |  |  |     return new TemplateParseResult(result); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TemplateParseVisitor implements HtmlAstVisitor { | 
					
						
							|  |  |  |   selectorMatcher: SelectorMatcher; | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   errors: TemplateParseError[] = []; | 
					
						
							| 
									
										
										
										
											2015-09-29 11:11:06 -07:00
										 |  |  |   directivesIndex = new Map<CompileDirectiveMetadata, number>(); | 
					
						
							| 
									
										
										
										
											2015-10-07 17:15:12 -07:00
										 |  |  |   ngContentCount: number = 0; | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |   pipesByName: Map<string, CompilePipeMetadata>; | 
					
						
							| 
									
										
										
										
											2015-10-07 17:15:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   constructor(public providerViewContext: ProviderViewContext, | 
					
						
							|  |  |  |               directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[], | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |               private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry) { | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     this.selectorMatcher = new SelectorMatcher(); | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |     ListWrapper.forEachWithIndex(directives, | 
					
						
							|  |  |  |                                  (directive: CompileDirectiveMetadata, index: number) => { | 
					
						
							|  |  |  |                                    var selector = CssSelector.parse(directive.selector); | 
					
						
							|  |  |  |                                    this.selectorMatcher.addSelectables(selector, directive); | 
					
						
							|  |  |  |                                    this.directivesIndex.set(directive, index); | 
					
						
							|  |  |  |                                  }); | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |     this.pipesByName = new Map<string, CompilePipeMetadata>(); | 
					
						
							|  |  |  |     pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe)); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   private _reportError(message: string, sourceSpan: ParseSourceSpan) { | 
					
						
							| 
									
										
										
										
											2016-02-16 16:46:51 -08:00
										 |  |  |     this.errors.push(new TemplateParseError(message, sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   private _parseInterpolation(value: string, sourceSpan: ParseSourceSpan): ASTWithSource { | 
					
						
							|  |  |  |     var sourceInfo = sourceSpan.start.toString(); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |       var ast = this._exprParser.parseInterpolation(value, sourceInfo); | 
					
						
							|  |  |  |       this._checkPipes(ast, sourceSpan); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       if (isPresent(ast) && | 
					
						
							|  |  |  |           (<Interpolation>ast.ast).expressions.length > MAX_INTERPOLATION_VALUES) { | 
					
						
							|  |  |  |         throw new BaseException( | 
					
						
							|  |  |  |             `Only support at most ${MAX_INTERPOLATION_VALUES} interpolation values!`); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |       return ast; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._reportError(`${e}`, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   private _parseAction(value: string, sourceSpan: ParseSourceSpan): ASTWithSource { | 
					
						
							|  |  |  |     var sourceInfo = sourceSpan.start.toString(); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |       var ast = this._exprParser.parseAction(value, sourceInfo); | 
					
						
							|  |  |  |       this._checkPipes(ast, sourceSpan); | 
					
						
							|  |  |  |       return ast; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._reportError(`${e}`, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   private _parseBinding(value: string, sourceSpan: ParseSourceSpan): ASTWithSource { | 
					
						
							|  |  |  |     var sourceInfo = sourceSpan.start.toString(); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |       var ast = this._exprParser.parseBinding(value, sourceInfo); | 
					
						
							|  |  |  |       this._checkPipes(ast, sourceSpan); | 
					
						
							|  |  |  |       return ast; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._reportError(`${e}`, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   private _parseTemplateBindings(value: string, sourceSpan: ParseSourceSpan): TemplateBinding[] { | 
					
						
							|  |  |  |     var sourceInfo = sourceSpan.start.toString(); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |       var bindings = this._exprParser.parseTemplateBindings(value, sourceInfo); | 
					
						
							|  |  |  |       bindings.forEach((binding) => { | 
					
						
							|  |  |  |         if (isPresent(binding.expression)) { | 
					
						
							|  |  |  |           this._checkPipes(binding.expression, sourceSpan); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       return bindings; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._reportError(`${e}`, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       return []; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |   private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan) { | 
					
						
							|  |  |  |     if (isPresent(ast)) { | 
					
						
							|  |  |  |       var collector = new PipeCollector(); | 
					
						
							|  |  |  |       ast.visit(collector); | 
					
						
							|  |  |  |       collector.pipes.forEach((pipeName) => { | 
					
						
							|  |  |  |         if (!this.pipesByName.has(pipeName)) { | 
					
						
							|  |  |  |           this._reportError(`The pipe '${pipeName}' could not be found`, sourceSpan); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 16:01:25 -07:00
										 |  |  |   visitExpansion(ast: HtmlExpansionAst, context: any): any { return null; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any { return null; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   visitText(ast: HtmlTextAst, parent: ElementContext): any { | 
					
						
							|  |  |  |     var ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR); | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     var expr = this._parseInterpolation(ast.value, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     if (isPresent(expr)) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       return new BoundTextAst(expr, ngContentIndex, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       return new TextAst(ast.value, ngContentIndex, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |   visitAttr(ast: HtmlAttrAst, contex: any): any { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     return new AttrAst(ast.name, ast.value, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 20:21:20 -08:00
										 |  |  |   visitComment(ast: HtmlCommentAst, context: any): any { return null; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 16:01:25 -07:00
										 |  |  |   visitElement(element: HtmlElementAst, parent: ElementContext): any { | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var nodeName = element.name; | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     var preparsedElement = preparseElement(element); | 
					
						
							|  |  |  |     if (preparsedElement.type === PreparsedElementType.SCRIPT || | 
					
						
							| 
									
										
										
										
											2015-10-14 09:39:40 -07:00
										 |  |  |         preparsedElement.type === PreparsedElementType.STYLE) { | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       // Skipping <script> for security reasons
 | 
					
						
							| 
									
										
										
										
											2015-10-14 09:39:40 -07:00
										 |  |  |       // Skipping <style> as we already processed them
 | 
					
						
							|  |  |  |       // in the StyleCompiler
 | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (preparsedElement.type === PreparsedElementType.STYLESHEET && | 
					
						
							|  |  |  |         isStyleUrlResolvable(preparsedElement.hrefAttr)) { | 
					
						
							|  |  |  |       // Skipping stylesheets with either relative urls or package scheme as we already processed
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       // them in the StyleCompiler
 | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var matchableAttrs: string[][] = []; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var elementOrDirectiveProps: BoundElementOrDirectiveProperty[] = []; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var vars: VariableAst[] = []; | 
					
						
							|  |  |  |     var events: BoundEventAst[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var templateElementOrDirectiveProps: BoundElementOrDirectiveProperty[] = []; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var templateVars: VariableAst[] = []; | 
					
						
							|  |  |  |     var templateMatchableAttrs: string[][] = []; | 
					
						
							|  |  |  |     var hasInlineTemplates = false; | 
					
						
							|  |  |  |     var attrs = []; | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     element.attrs.forEach(attr => { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       var hasBinding = this._parseAttr(attr, matchableAttrs, elementOrDirectiveProps, events, vars); | 
					
						
							|  |  |  |       var hasTemplateBinding = this._parseInlineTemplateBinding( | 
					
						
							|  |  |  |           attr, templateMatchableAttrs, templateElementOrDirectiveProps, templateVars); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       if (!hasBinding && !hasTemplateBinding) { | 
					
						
							|  |  |  |         // don't include the bindings as attributes as well in the AST
 | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |         attrs.push(this.visitAttr(attr, null)); | 
					
						
							| 
									
										
										
										
											2015-12-15 09:39:07 -08:00
										 |  |  |         matchableAttrs.push([attr.name, attr.value]); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (hasTemplateBinding) { | 
					
						
							|  |  |  |         hasInlineTemplates = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-09 09:32:15 -08:00
										 |  |  |     var lcElName = splitNsName(nodeName.toLowerCase())[1]; | 
					
						
							| 
									
										
										
										
											2015-12-08 09:01:15 -08:00
										 |  |  |     var isTemplateElement = lcElName == TEMPLATE_ELEMENT; | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     var directiveMetas = this._parseDirectives(this.selectorMatcher, elementCssSelector); | 
					
						
							|  |  |  |     var directiveAsts = | 
					
						
							|  |  |  |         this._createDirectiveAsts(element.name, directiveMetas, elementOrDirectiveProps, | 
					
						
							|  |  |  |                                   isTemplateElement ? [] : vars, element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var elementProps: BoundElementPropertyAst[] = | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |         this._createElementPropertyAsts(element.name, elementOrDirectiveProps, directiveAsts); | 
					
						
							|  |  |  |     var isViewRoot = parent.isTemplateElement || hasInlineTemplates; | 
					
						
							|  |  |  |     var providerContext = | 
					
						
							|  |  |  |         new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot, | 
					
						
							|  |  |  |                                    directiveAsts, attrs, element.sourceSpan); | 
					
						
							|  |  |  |     var children = htmlVisitAll( | 
					
						
							|  |  |  |         preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, | 
					
						
							|  |  |  |         ElementContext.create(isTemplateElement, directiveAsts, | 
					
						
							|  |  |  |                               isTemplateElement ? parent.providerContext : providerContext)); | 
					
						
							|  |  |  |     providerContext.afterElement(); | 
					
						
							| 
									
										
										
										
											2016-03-23 14:15:05 -07:00
										 |  |  |     // Override the actual selector when the `ngProjectAs` attribute is provided
 | 
					
						
							|  |  |  |     var projectionSelector = isPresent(preparsedElement.projectAs) ? | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |                                  CssSelector.parse(preparsedElement.projectAs)[0] : | 
					
						
							|  |  |  |                                  elementCssSelector; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     var ngContentIndex = parent.findNgContentIndex(projectionSelector); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var parsedElement; | 
					
						
							| 
									
										
										
										
											2016-03-23 14:15:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     if (preparsedElement.type === PreparsedElementType.NG_CONTENT) { | 
					
						
							| 
									
										
										
										
											2015-12-03 14:20:00 -08:00
										 |  |  |       if (isPresent(element.children) && element.children.length > 0) { | 
					
						
							|  |  |  |         this._reportError( | 
					
						
							|  |  |  |             `<ng-content> element cannot have content. <ng-content> must be immediately followed by </ng-content>`, | 
					
						
							|  |  |  |             element.sourceSpan); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-03-23 14:15:05 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       parsedElement = new NgContentAst( | 
					
						
							|  |  |  |           this.ngContentCount++, hasInlineTemplates ? null : ngContentIndex, element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     } else if (isTemplateElement) { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       this._assertAllEventsPublishedByDirectives(directiveAsts, events); | 
					
						
							|  |  |  |       this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps, | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |                                                            element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2016-03-23 14:15:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |       parsedElement = | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |           new EmbeddedTemplateAst(attrs, events, vars, providerContext.transformedDirectiveAsts, | 
					
						
							|  |  |  |                                   providerContext.transformProviders, children, | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |                                   hasInlineTemplates ? null : ngContentIndex, element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       this._assertOnlyOneComponent(directiveAsts, element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-10-09 09:07:58 -07:00
										 |  |  |       var elementExportAsVars = vars.filter(varAst => varAst.value.length === 0); | 
					
						
							| 
									
										
										
										
											2016-03-23 14:15:05 -07:00
										 |  |  |       let ngContentIndex = | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |           hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector); | 
					
						
							| 
									
										
										
										
											2016-03-23 14:15:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       parsedElement = new ElementAst( | 
					
						
							|  |  |  |           nodeName, attrs, elementProps, events, elementExportAsVars, | 
					
						
							|  |  |  |           providerContext.transformedDirectiveAsts, providerContext.transformProviders, children, | 
					
						
							|  |  |  |           hasInlineTemplates ? null : ngContentIndex, element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (hasInlineTemplates) { | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       var templateCssSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |       var templateDirectiveMetas = this._parseDirectives(this.selectorMatcher, templateCssSelector); | 
					
						
							|  |  |  |       var templateDirectiveAsts = | 
					
						
							|  |  |  |           this._createDirectiveAsts(element.name, templateDirectiveMetas, | 
					
						
							|  |  |  |                                     templateElementOrDirectiveProps, [], element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       var templateElementProps: BoundElementPropertyAst[] = this._createElementPropertyAsts( | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |           element.name, templateElementOrDirectiveProps, templateDirectiveAsts); | 
					
						
							|  |  |  |       this._assertNoComponentsNorElementBindingsOnTemplate( | 
					
						
							|  |  |  |           templateDirectiveAsts, templateElementProps, element.sourceSpan); | 
					
						
							|  |  |  |       var templateProviderContext = new ProviderElementContext( | 
					
						
							|  |  |  |           this.providerViewContext, parent.providerContext, parent.isTemplateElement, | 
					
						
							|  |  |  |           templateDirectiveAsts, [], element.sourceSpan); | 
					
						
							|  |  |  |       templateProviderContext.afterElement(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       parsedElement = new EmbeddedTemplateAst([], [], templateVars, | 
					
						
							|  |  |  |                                               templateProviderContext.transformedDirectiveAsts, | 
					
						
							|  |  |  |                                               templateProviderContext.transformProviders, | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |                                               [parsedElement], ngContentIndex, element.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     return parsedElement; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseInlineTemplateBinding(attr: HtmlAttrAst, targetMatchableAttrs: string[][], | 
					
						
							|  |  |  |                                       targetProps: BoundElementOrDirectiveProperty[], | 
					
						
							|  |  |  |                                       targetVars: VariableAst[]): boolean { | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var templateBindingsSource = null; | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |     if (attr.name == TEMPLATE_ATTR) { | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       templateBindingsSource = attr.value; | 
					
						
							| 
									
										
										
										
											2015-10-31 13:04:26 -07:00
										 |  |  |     } else if (attr.name.startsWith(TEMPLATE_ATTR_PREFIX)) { | 
					
						
							|  |  |  |       var key = attr.name.substring(TEMPLATE_ATTR_PREFIX.length);  // remove the star
 | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       templateBindingsSource = (attr.value.length == 0) ? key : key + ' ' + attr.value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (isPresent(templateBindingsSource)) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       var bindings = this._parseTemplateBindings(templateBindingsSource, attr.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       for (var i = 0; i < bindings.length; i++) { | 
					
						
							|  |  |  |         var binding = bindings[i]; | 
					
						
							|  |  |  |         if (binding.keyIsVar) { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |           targetVars.push(new VariableAst(binding.key, binding.name, attr.sourceSpan)); | 
					
						
							|  |  |  |           targetMatchableAttrs.push([binding.key, binding.name]); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |         } else if (isPresent(binding.expression)) { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |           this._parsePropertyAst(binding.key, binding.expression, attr.sourceSpan, | 
					
						
							|  |  |  |                                  targetMatchableAttrs, targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |           targetMatchableAttrs.push([binding.key, '']); | 
					
						
							|  |  |  |           this._parseLiteralAttr(binding.key, null, attr.sourceSpan, targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseAttr(attr: HtmlAttrAst, targetMatchableAttrs: string[][], | 
					
						
							|  |  |  |                      targetProps: BoundElementOrDirectiveProperty[], targetEvents: BoundEventAst[], | 
					
						
							|  |  |  |                      targetVars: VariableAst[]): boolean { | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var attrName = this._normalizeAttributeName(attr.name); | 
					
						
							|  |  |  |     var attrValue = attr.value; | 
					
						
							|  |  |  |     var bindParts = RegExpWrapper.firstMatch(BIND_NAME_REGEXP, attrName); | 
					
						
							|  |  |  |     var hasBinding = false; | 
					
						
							|  |  |  |     if (isPresent(bindParts)) { | 
					
						
							|  |  |  |       hasBinding = true; | 
					
						
							|  |  |  |       if (isPresent(bindParts[1])) {  // match: bind-prop
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._parseProperty(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                             targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       } else if (isPresent( | 
					
						
							|  |  |  |                      bindParts[2])) {  // match: var-name / var-name="iden" / #name / #name="iden"
 | 
					
						
							|  |  |  |         var identifier = bindParts[5]; | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |         this._parseVariable(identifier, attrValue, attr.sourceSpan, targetVars); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       } else if (isPresent(bindParts[3])) {  // match: on-event
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._parseEvent(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                          targetEvents); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       } else if (isPresent(bindParts[4])) {  // match: bindon-prop
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._parseProperty(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                             targetProps); | 
					
						
							|  |  |  |         this._parseAssignmentEvent(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                                    targetEvents); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       } else if (isPresent(bindParts[6])) {  // match: [(expr)]
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._parseProperty(bindParts[6], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                             targetProps); | 
					
						
							|  |  |  |         this._parseAssignmentEvent(bindParts[6], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                                    targetEvents); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       } else if (isPresent(bindParts[7])) {  // match: [expr]
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._parseProperty(bindParts[7], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                             targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       } else if (isPresent(bindParts[8])) {  // match: (event)
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._parseEvent(bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                          targetEvents); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |       hasBinding = this._parsePropertyInterpolation(attrName, attrValue, attr.sourceSpan, | 
					
						
							|  |  |  |                                                     targetMatchableAttrs, targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!hasBinding) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._parseLiteralAttr(attrName, attrValue, attr.sourceSpan, targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     return hasBinding; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private _normalizeAttributeName(attrName: string): string { | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  |     return attrName.toLowerCase().startsWith('data-') ? attrName.substring(5) : attrName; | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseVariable(identifier: string, value: string, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                          targetVars: VariableAst[]) { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |     if (identifier.indexOf('-') > -1) { | 
					
						
							|  |  |  |       this._reportError(`"-" is not allowed in variable names`, sourceSpan); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     targetVars.push(new VariableAst(identifier, value, sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseProperty(name: string, expression: string, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                          targetMatchableAttrs: string[][], | 
					
						
							|  |  |  |                          targetProps: BoundElementOrDirectiveProperty[]) { | 
					
						
							|  |  |  |     this._parsePropertyAst(name, this._parseBinding(expression, sourceSpan), sourceSpan, | 
					
						
							|  |  |  |                            targetMatchableAttrs, targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parsePropertyInterpolation(name: string, value: string, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                                       targetMatchableAttrs: string[][], | 
					
						
							|  |  |  |                                       targetProps: BoundElementOrDirectiveProperty[]): boolean { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     var expr = this._parseInterpolation(value, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     if (isPresent(expr)) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._parsePropertyAst(name, expr, sourceSpan, targetMatchableAttrs, targetProps); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parsePropertyAst(name: string, ast: ASTWithSource, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                             targetMatchableAttrs: string[][], | 
					
						
							|  |  |  |                             targetProps: BoundElementOrDirectiveProperty[]) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     targetMatchableAttrs.push([name, ast.source]); | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     targetProps.push(new BoundElementOrDirectiveProperty(name, ast, false, sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseAssignmentEvent(name: string, expression: string, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                                 targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) { | 
					
						
							|  |  |  |     this._parseEvent(`${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, | 
					
						
							|  |  |  |                      targetEvents); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseEvent(name: string, expression: string, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                       targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     // long format: 'target: eventName'
 | 
					
						
							|  |  |  |     var parts = splitAtColon(name, [null, name]); | 
					
						
							|  |  |  |     var target = parts[0]; | 
					
						
							|  |  |  |     var eventName = parts[1]; | 
					
						
							| 
									
										
										
										
											2016-02-03 11:35:42 -08:00
										 |  |  |     var ast = this._parseAction(expression, sourceSpan); | 
					
						
							|  |  |  |     targetMatchableAttrs.push([name, ast.source]); | 
					
						
							|  |  |  |     targetEvents.push(new BoundEventAst(eventName, target, ast, sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     // Don't detect directives for event names for now,
 | 
					
						
							|  |  |  |     // so don't add the event name to the matchableAttrs
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseLiteralAttr(name: string, value: string, sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                             targetProps: BoundElementOrDirectiveProperty[]) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     targetProps.push(new BoundElementOrDirectiveProperty( | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |         name, this._exprParser.wrapLiteralPrimitive(value, ''), true, sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _parseDirectives(selectorMatcher: SelectorMatcher, | 
					
						
							|  |  |  |                            elementCssSelector: CssSelector): CompileDirectiveMetadata[] { | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     var directives = []; | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |     selectorMatcher.match(elementCssSelector, | 
					
						
							|  |  |  |                           (selector, directive) => { directives.push(directive); }); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     // Need to sort the directives so that we get consistent results throughout,
 | 
					
						
							|  |  |  |     // as selectorMatcher uses Maps inside.
 | 
					
						
							|  |  |  |     // Also need to make components the first directive in the array
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |     ListWrapper.sort(directives, | 
					
						
							|  |  |  |                      (dir1: CompileDirectiveMetadata, dir2: CompileDirectiveMetadata) => { | 
					
						
							|  |  |  |                        var dir1Comp = dir1.isComponent; | 
					
						
							|  |  |  |                        var dir2Comp = dir2.isComponent; | 
					
						
							|  |  |  |                        if (dir1Comp && !dir2Comp) { | 
					
						
							|  |  |  |                          return -1; | 
					
						
							|  |  |  |                        } else if (!dir1Comp && dir2Comp) { | 
					
						
							|  |  |  |                          return 1; | 
					
						
							|  |  |  |                        } else { | 
					
						
							|  |  |  |                          return this.directivesIndex.get(dir1) - this.directivesIndex.get(dir2); | 
					
						
							|  |  |  |                        } | 
					
						
							|  |  |  |                      }); | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  |     return directives; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _createDirectiveAsts(elementName: string, directives: CompileDirectiveMetadata[], | 
					
						
							|  |  |  |                                props: BoundElementOrDirectiveProperty[], | 
					
						
							|  |  |  |                                possibleExportAsVars: VariableAst[], | 
					
						
							|  |  |  |                                sourceSpan: ParseSourceSpan): DirectiveAst[] { | 
					
						
							| 
									
										
										
										
											2015-09-29 11:11:06 -07:00
										 |  |  |     var matchedVariables = new Set<string>(); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     var directiveAsts = directives.map((directive: CompileDirectiveMetadata) => { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       var hostProperties: BoundElementPropertyAst[] = []; | 
					
						
							|  |  |  |       var hostEvents: BoundEventAst[] = []; | 
					
						
							|  |  |  |       var directiveProperties: BoundDirectivePropertyAst[] = []; | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |       this._createDirectiveHostPropertyAsts(elementName, directive.hostProperties, sourceSpan, | 
					
						
							|  |  |  |                                             hostProperties); | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._createDirectiveHostEventAsts(directive.hostListeners, sourceSpan, hostEvents); | 
					
						
							| 
									
										
										
										
											2015-09-30 20:59:23 -07:00
										 |  |  |       this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       var exportAsVars = []; | 
					
						
							|  |  |  |       possibleExportAsVars.forEach((varAst) => { | 
					
						
							|  |  |  |         if ((varAst.value.length === 0 && directive.isComponent) || | 
					
						
							|  |  |  |             (directive.exportAs == varAst.value)) { | 
					
						
							|  |  |  |           exportAsVars.push(varAst); | 
					
						
							|  |  |  |           matchedVariables.add(varAst.name); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |       return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents, | 
					
						
							|  |  |  |                               exportAsVars, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |     possibleExportAsVars.forEach((varAst) => { | 
					
						
							|  |  |  |       if (varAst.value.length > 0 && !SetWrapper.has(matchedVariables, varAst.name)) { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         this._reportError(`There is no directive with "exportAs" set to "${varAst.value}"`, | 
					
						
							|  |  |  |                           varAst.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     return directiveAsts; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _createDirectiveHostPropertyAsts(elementName: string, hostProps: {[key: string]: string}, | 
					
						
							|  |  |  |                                            sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                                            targetPropertyAsts: BoundElementPropertyAst[]) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     if (isPresent(hostProps)) { | 
					
						
							| 
									
										
										
										
											2016-02-19 11:49:31 -08:00
										 |  |  |       StringMapWrapper.forEach(hostProps, (expression: string, propName: string) => { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |         var exprAst = this._parseBinding(expression, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |         targetPropertyAsts.push( | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |             this._createElementPropertyAst(elementName, propName, exprAst, sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _createDirectiveHostEventAsts(hostListeners: {[key: string]: string}, | 
					
						
							|  |  |  |                                         sourceSpan: ParseSourceSpan, | 
					
						
							|  |  |  |                                         targetEventAsts: BoundEventAst[]) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     if (isPresent(hostListeners)) { | 
					
						
							| 
									
										
										
										
											2016-02-19 11:49:31 -08:00
										 |  |  |       StringMapWrapper.forEach(hostListeners, (expression: string, propName: string) => { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |         this._parseEvent(propName, expression, sourceSpan, [], targetEventAsts); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _createDirectivePropertyAsts(directiveProperties: {[key: string]: string}, | 
					
						
							|  |  |  |                                        boundProps: BoundElementOrDirectiveProperty[], | 
					
						
							|  |  |  |                                        targetBoundDirectiveProps: BoundDirectivePropertyAst[]) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     if (isPresent(directiveProperties)) { | 
					
						
							| 
									
										
										
										
											2015-09-29 11:11:06 -07:00
										 |  |  |       var boundPropsByName = new Map<string, BoundElementOrDirectiveProperty>(); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       boundProps.forEach(boundProp => { | 
					
						
							|  |  |  |         var prevValue = boundPropsByName.get(boundProp.name); | 
					
						
							|  |  |  |         if (isBlank(prevValue) || prevValue.isLiteral) { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |           // give [a]="b" a higher precedence than a="b" on the same element
 | 
					
						
							|  |  |  |           boundPropsByName.set(boundProp.name, boundProp); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       StringMapWrapper.forEach(directiveProperties, (elProp: string, dirProp: string) => { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |         var boundProp = boundPropsByName.get(elProp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Bindings are optional, so this binding only needs to be set up if an expression is given.
 | 
					
						
							|  |  |  |         if (isPresent(boundProp)) { | 
					
						
							|  |  |  |           targetBoundDirectiveProps.push(new BoundDirectivePropertyAst( | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |               dirProp, boundProp.name, boundProp.expression, boundProp.sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _createElementPropertyAsts(elementName: string, props: BoundElementOrDirectiveProperty[], | 
					
						
							|  |  |  |                                      directives: DirectiveAst[]): BoundElementPropertyAst[] { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var boundElementProps: BoundElementPropertyAst[] = []; | 
					
						
							| 
									
										
										
										
											2015-09-29 11:11:06 -07:00
										 |  |  |     var boundDirectivePropsIndex = new Map<string, BoundDirectivePropertyAst>(); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     directives.forEach((directive: DirectiveAst) => { | 
					
						
							| 
									
										
										
										
											2015-09-30 20:59:23 -07:00
										 |  |  |       directive.inputs.forEach((prop: BoundDirectivePropertyAst) => { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |         boundDirectivePropsIndex.set(prop.templateName, prop); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     props.forEach((prop: BoundElementOrDirectiveProperty) => { | 
					
						
							|  |  |  |       if (!prop.isLiteral && isBlank(boundDirectivePropsIndex.get(prop.name))) { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |         boundElementProps.push(this._createElementPropertyAst(elementName, prop.name, | 
					
						
							|  |  |  |                                                               prop.expression, prop.sourceSpan)); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return boundElementProps; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _createElementPropertyAst(elementName: string, name: string, ast: AST, | 
					
						
							|  |  |  |                                     sourceSpan: ParseSourceSpan): BoundElementPropertyAst { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var unit = null; | 
					
						
							|  |  |  |     var bindingType; | 
					
						
							|  |  |  |     var boundPropertyName; | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     var parts = name.split(PROPERTY_PARTS_SEPARATOR); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     if (parts.length === 1) { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       boundPropertyName = this._schemaRegistry.getMappedPropName(parts[0]); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       bindingType = PropertyBindingType.Property; | 
					
						
							|  |  |  |       if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName)) { | 
					
						
							|  |  |  |         this._reportError( | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |             `Can't bind to '${boundPropertyName}' since it isn't a known native property`, | 
					
						
							|  |  |  |             sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       if (parts[0] == ATTRIBUTE_PREFIX) { | 
					
						
							|  |  |  |         boundPropertyName = parts[1]; | 
					
						
							| 
									
										
										
										
											2016-01-08 12:01:29 -08:00
										 |  |  |         let nsSeparatorIdx = boundPropertyName.indexOf(':'); | 
					
						
							|  |  |  |         if (nsSeparatorIdx > -1) { | 
					
						
							|  |  |  |           let ns = boundPropertyName.substring(0, nsSeparatorIdx); | 
					
						
							|  |  |  |           let name = boundPropertyName.substring(nsSeparatorIdx + 1); | 
					
						
							|  |  |  |           boundPropertyName = mergeNsAndName(ns, name); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  |         bindingType = PropertyBindingType.Attribute; | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       } else if (parts[0] == CLASS_PREFIX) { | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  |         boundPropertyName = parts[1]; | 
					
						
							|  |  |  |         bindingType = PropertyBindingType.Class; | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       } else if (parts[0] == STYLE_PREFIX) { | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  |         unit = parts.length > 2 ? parts[2] : null; | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |         boundPropertyName = parts[1]; | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  |         bindingType = PropertyBindingType.Style; | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |         this._reportError(`Invalid property name '${name}'`, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  |         bindingType = null; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-11-10 15:56:25 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     return new BoundElementPropertyAst(boundPropertyName, bindingType, ast, unit, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private _findComponentDirectiveNames(directives: DirectiveAst[]): string[] { | 
					
						
							|  |  |  |     var componentTypeNames: string[] = []; | 
					
						
							|  |  |  |     directives.forEach(directive => { | 
					
						
							| 
									
										
										
										
											2015-09-14 15:59:09 -07:00
										 |  |  |       var typeName = directive.directive.type.name; | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |       if (directive.directive.isComponent) { | 
					
						
							|  |  |  |         componentTypeNames.push(typeName); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return componentTypeNames; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |   private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var componentTypeNames = this._findComponentDirectiveNames(directives); | 
					
						
							|  |  |  |     if (componentTypeNames.length > 1) { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |       this._reportError(`More than one component: ${componentTypeNames.join(',')}`, sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _assertNoComponentsNorElementBindingsOnTemplate(directives: DirectiveAst[], | 
					
						
							|  |  |  |                                                           elementProps: BoundElementPropertyAst[], | 
					
						
							|  |  |  |                                                           sourceSpan: ParseSourceSpan) { | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     var componentTypeNames: string[] = this._findComponentDirectiveNames(directives); | 
					
						
							|  |  |  |     if (componentTypeNames.length > 0) { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |       this._reportError(`Components on an embedded template: ${componentTypeNames.join(',')}`, | 
					
						
							|  |  |  |                         sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     elementProps.forEach(prop => { | 
					
						
							|  |  |  |       this._reportError( | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |           `Property binding ${prop.name} not used by any directive on an embedded template`, | 
					
						
							|  |  |  |           sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-10-13 17:43:15 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   private _assertAllEventsPublishedByDirectives(directives: DirectiveAst[], | 
					
						
							|  |  |  |                                                 events: BoundEventAst[]) { | 
					
						
							| 
									
										
										
										
											2015-10-13 17:43:15 -07:00
										 |  |  |     var allDirectiveEvents = new Set<string>(); | 
					
						
							|  |  |  |     directives.forEach(directive => { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |       StringMapWrapper.forEach(directive.directive.outputs, | 
					
						
							|  |  |  |                                (eventName: string, _) => { allDirectiveEvents.add(eventName); }); | 
					
						
							| 
									
										
										
										
											2015-10-13 17:43:15 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     events.forEach(event => { | 
					
						
							| 
									
										
										
										
											2015-10-13 17:43:15 -07:00
										 |  |  |       if (isPresent(event.target) || !SetWrapper.has(allDirectiveEvents, event.name)) { | 
					
						
							|  |  |  |         this._reportError( | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |             `Event binding ${event.fullName} not emitted by any directive on an embedded template`, | 
					
						
							|  |  |  |             event.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-10-13 17:43:15 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  | class NonBindableVisitor implements HtmlAstVisitor { | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   visitElement(ast: HtmlElementAst, parent: ElementContext): ElementAst { | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |     var preparsedElement = preparseElement(ast); | 
					
						
							|  |  |  |     if (preparsedElement.type === PreparsedElementType.SCRIPT || | 
					
						
							|  |  |  |         preparsedElement.type === PreparsedElementType.STYLE || | 
					
						
							|  |  |  |         preparsedElement.type === PreparsedElementType.STYLESHEET) { | 
					
						
							|  |  |  |       // Skipping <script> for security reasons
 | 
					
						
							|  |  |  |       // Skipping <style> and stylesheets as we already processed them
 | 
					
						
							|  |  |  |       // in the StyleCompiler
 | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var attrNameAndValues = ast.attrs.map(attrAst => [attrAst.name, attrAst.value]); | 
					
						
							|  |  |  |     var selector = createElementCssSelector(ast.name, attrNameAndValues); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     var ngContentIndex = parent.findNgContentIndex(selector); | 
					
						
							|  |  |  |     var children = htmlVisitAll(this, ast.children, EMPTY_ELEMENT_CONTEXT); | 
					
						
							|  |  |  |     return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], children, | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |                           ngContentIndex, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-03-06 20:21:20 -08:00
										 |  |  |   visitComment(ast: HtmlCommentAst, context: any): any { return null; } | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |   visitAttr(ast: HtmlAttrAst, context: any): AttrAst { | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     return new AttrAst(ast.name, ast.value, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   visitText(ast: HtmlTextAst, parent: ElementContext): TextAst { | 
					
						
							|  |  |  |     var ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR); | 
					
						
							| 
									
										
										
										
											2015-10-07 09:34:21 -07:00
										 |  |  |     return new TextAst(ast.value, ngContentIndex, ast.sourceSpan); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-04-12 11:46:49 -07:00
										 |  |  |   visitExpansion(ast: HtmlExpansionAst, context: any): any { return ast; } | 
					
						
							|  |  |  |   visitExpansionCase(ast: HtmlExpansionCaseAst, context: any): any { return ast; } | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | class BoundElementOrDirectiveProperty { | 
					
						
							| 
									
										
										
										
											2016-04-12 09:40:37 -07:00
										 |  |  |   constructor(public name: string, public expression: AST, public isLiteral: boolean, | 
					
						
							|  |  |  |               public sourceSpan: ParseSourceSpan) {} | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-25 15:36:02 -07:00
										 |  |  | export function splitClasses(classAttrValue: string): string[] { | 
					
						
							|  |  |  |   return StringWrapper.split(classAttrValue.trim(), /\s+/g); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-08-27 16:29:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | class ElementContext { | 
					
						
							|  |  |  |   static create(isTemplateElement: boolean, directives: DirectiveAst[], | 
					
						
							|  |  |  |                 providerContext: ProviderElementContext): ElementContext { | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |     var matcher = new SelectorMatcher(); | 
					
						
							|  |  |  |     var wildcardNgContentIndex = null; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     if (directives.length > 0 && directives[0].directive.isComponent) { | 
					
						
							|  |  |  |       var ngContentSelectors = directives[0].directive.template.ngContentSelectors; | 
					
						
							|  |  |  |       for (var i = 0; i < ngContentSelectors.length; i++) { | 
					
						
							|  |  |  |         var selector = ngContentSelectors[i]; | 
					
						
							|  |  |  |         if (StringWrapper.equals(selector, '*')) { | 
					
						
							|  |  |  |           wildcardNgContentIndex = i; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           matcher.addSelectables(CssSelector.parse(ngContentSelectors[i]), i); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     return new ElementContext(isTemplateElement, matcher, wildcardNgContentIndex, providerContext); | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   constructor(public isTemplateElement: boolean, private _ngContentIndexMatcher: SelectorMatcher, | 
					
						
							|  |  |  |               private _wildcardNgContentIndex: number, | 
					
						
							|  |  |  |               public providerContext: ProviderElementContext) {} | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   findNgContentIndex(selector: CssSelector): number { | 
					
						
							|  |  |  |     var ngContentIndices = []; | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     this._ngContentIndexMatcher.match( | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |         selector, (selector, ngContentIndex) => { ngContentIndices.push(ngContentIndex); }); | 
					
						
							|  |  |  |     ListWrapper.sort(ngContentIndices); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     if (isPresent(this._wildcardNgContentIndex)) { | 
					
						
							|  |  |  |       ngContentIndices.push(this._wildcardNgContentIndex); | 
					
						
							| 
									
										
										
										
											2015-10-29 16:23:13 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-11 13:37:05 -07:00
										 |  |  |     return ngContentIndices.length > 0 ? ngContentIndices[0] : null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  | function createElementCssSelector(elementName: string, matchableAttrs: string[][]): CssSelector { | 
					
						
							|  |  |  |   var cssSelector = new CssSelector(); | 
					
						
							| 
									
										
										
										
											2015-12-09 09:32:15 -08:00
										 |  |  |   let elNameNoNs = splitNsName(elementName)[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cssSelector.setElement(elNameNoNs); | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (var i = 0; i < matchableAttrs.length; i++) { | 
					
						
							| 
									
										
										
										
											2015-12-09 09:32:15 -08:00
										 |  |  |     let attrName = matchableAttrs[i][0]; | 
					
						
							|  |  |  |     let attrNameNoNs = splitNsName(attrName)[1]; | 
					
						
							|  |  |  |     let attrValue = matchableAttrs[i][1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cssSelector.addAttribute(attrNameNoNs, attrValue); | 
					
						
							|  |  |  |     if (attrName.toLowerCase() == CLASS_ATTR) { | 
					
						
							| 
									
										
										
										
											2015-09-18 10:33:23 -07:00
										 |  |  |       var classes = splitClasses(attrValue); | 
					
						
							|  |  |  |       classes.forEach(className => cssSelector.addClassName(className)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return cssSelector; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | var EMPTY_ELEMENT_CONTEXT = new ElementContext(true, new SelectorMatcher(), null, null); | 
					
						
							| 
									
										
										
										
											2015-09-29 11:11:06 -07:00
										 |  |  | var NON_BINDABLE_VISITOR = new NonBindableVisitor(); | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class PipeCollector extends RecursiveAstVisitor { | 
					
						
							|  |  |  |   pipes: Set<string> = new Set<string>(); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |   visitPipe(ast: BindingPipe, context: any): any { | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |     this.pipes.add(ast.name); | 
					
						
							|  |  |  |     ast.exp.visit(this); | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  |     this.visitAll(ast.args, context); | 
					
						
							| 
									
										
										
										
											2015-12-02 10:35:51 -08:00
										 |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-06 14:13:44 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | function removeDuplicates(items: CompileMetadataWithType[]): CompileMetadataWithType[] { | 
					
						
							|  |  |  |   let res = []; | 
					
						
							|  |  |  |   items.forEach(item => { | 
					
						
							|  |  |  |     let hasMatch = | 
					
						
							|  |  |  |         res.filter(r => r.type.name == item.type.name && r.type.moduleUrl == item.type.moduleUrl && | 
					
						
							|  |  |  |                         r.type.runtime == item.type.runtime) | 
					
						
							|  |  |  |             .length > 0; | 
					
						
							|  |  |  |     if (!hasMatch) { | 
					
						
							|  |  |  |       res.push(item); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   return res; | 
					
						
							|  |  |  | } |