diff --git a/packages/compiler/src/template_parser/binding_parser.ts b/packages/compiler/src/template_parser/binding_parser.ts index 3c30006de8..a69acdd355 100644 --- a/packages/compiler/src/template_parser/binding_parser.ts +++ b/packages/compiler/src/template_parser/binding_parser.ts @@ -124,6 +124,7 @@ export class BindingParser { } } + // Parse an inline template binding. ie `` parseInlineTemplateBinding( prefixToken: string, value: string, sourceSpan: ParseSourceSpan, targetMatchableAttrs: string[][], targetProps: BoundProperty[], targetVars: VariableAst[]) { @@ -387,7 +388,8 @@ export class BindingParser { } } - private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan) { + // Make sure all the used pipes are known in `this.pipesByName` + private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan): void { if (ast) { const collector = new PipeCollector(); ast.visit(collector); diff --git a/packages/compiler/src/template_parser/template_parser.ts b/packages/compiler/src/template_parser/template_parser.ts index ea60d4ab1b..8f5607dd96 100644 --- a/packages/compiler/src/template_parser/template_parser.ts +++ b/packages/compiler/src/template_parser/template_parser.ts @@ -254,7 +254,7 @@ class TemplateParseVisitor implements html.Visitor { visitElement(element: html.Element, parent: ElementContext): any { const queryStartIndex = this.contentQueryStartId; - const nodeName = element.name; + const elName = element.name; const preparsedElement = preparseElement(element); if (preparsedElement.type === PreparsedElementType.SCRIPT || preparsedElement.type === PreparsedElementType.STYLE) { @@ -318,7 +318,7 @@ class TemplateParseVisitor implements html.Visitor { } }); - const elementCssSelector = createElementCssSelector(nodeName, matchableAttrs); + const elementCssSelector = createElementCssSelector(elName, matchableAttrs); const {directives: directiveMetas, matchElement} = this._parseDirectives(this.selectorMatcher, elementCssSelector); const references: ReferenceAst[] = []; @@ -341,13 +341,14 @@ class TemplateParseVisitor implements html.Visitor { isTemplateElement ? parent.providerContext ! : providerContext)); providerContext.afterElement(); // Override the actual selector when the `ngProjectAs` attribute is provided - const projectionSelector = preparsedElement.projectAs != null ? + const projectionSelector = preparsedElement.projectAs != '' ? CssSelector.parse(preparsedElement.projectAs)[0] : elementCssSelector; const ngContentIndex = parent.findNgContentIndex(projectionSelector) !; let parsedElement: TemplateAst; if (preparsedElement.type === PreparsedElementType.NG_CONTENT) { + // `` element if (element.children && !element.children.every(_isEmptyTextNode)) { this._reportError(` element cannot have content.`, element.sourceSpan !); } @@ -356,6 +357,7 @@ class TemplateParseVisitor implements html.Visitor { this.ngContentCount++, hasInlineTemplates ? null ! : ngContentIndex, element.sourceSpan !); } else if (isTemplateElement) { + // `` element this._assertAllEventsPublishedByDirectives(directiveAsts, events); this._assertNoComponentsNorElementBindingsOnTemplate( directiveAsts, elementProps, element.sourceSpan !); @@ -366,30 +368,30 @@ class TemplateParseVisitor implements html.Visitor { providerContext.queryMatches, children, hasInlineTemplates ? null ! : ngContentIndex, element.sourceSpan !); } else { + // element other than `` and `` this._assertElementExists(matchElement, element); this._assertOnlyOneComponent(directiveAsts, element.sourceSpan !); const ngContentIndex = hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector); parsedElement = new ElementAst( - nodeName, attrs, elementProps, events, references, - providerContext.transformedDirectiveAsts, providerContext.transformProviders, - providerContext.transformedHasViewContainer, providerContext.queryMatches, children, - hasInlineTemplates ? null : ngContentIndex, element.sourceSpan, - element.endSourceSpan || null); + elName, attrs, elementProps, events, references, providerContext.transformedDirectiveAsts, + providerContext.transformProviders, providerContext.transformedHasViewContainer, + providerContext.queryMatches, children, hasInlineTemplates ? null : ngContentIndex, + element.sourceSpan, element.endSourceSpan || null); } if (hasInlineTemplates) { + // The element as a *-attribute const templateQueryStartIndex = this.contentQueryStartId; const templateSelector = createElementCssSelector('ng-template', templateMatchableAttrs); - const {directives: templateDirectiveMetas} = - this._parseDirectives(this.selectorMatcher, templateSelector); + const {directives} = this._parseDirectives(this.selectorMatcher, templateSelector); const templateBoundDirectivePropNames = new Set(); const templateDirectiveAsts = this._createDirectiveAsts( - true, element.name, templateDirectiveMetas, templateElementOrDirectiveProps, [], - element.sourceSpan !, [], templateBoundDirectivePropNames); + true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan !, [], + templateBoundDirectivePropNames); const templateElementProps: BoundElementPropertyAst[] = this._createElementPropertyAsts( - element.name, templateElementOrDirectiveProps, templateBoundDirectivePropNames); + elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames); this._assertNoComponentsNorElementBindingsOnTemplate( templateDirectiveAsts, templateElementProps, element.sourceSpan !); const templateProviderContext = new ProviderElementContext( diff --git a/packages/compiler/src/template_parser/template_preparser.ts b/packages/compiler/src/template_parser/template_preparser.ts index f0b484240d..d76d53b231 100644 --- a/packages/compiler/src/template_parser/template_preparser.ts +++ b/packages/compiler/src/template_parser/template_preparser.ts @@ -24,7 +24,7 @@ export function preparseElement(ast: html.Element): PreparsedElement { let hrefAttr: string = null !; let relAttr: string = null !; let nonBindable = false; - let projectAs: string = null !; + let projectAs = ''; ast.attrs.forEach(attr => { const lcAttrName = attr.name.toLowerCase(); if (lcAttrName == NG_CONTENT_SELECT_ATTR) {