refactor(compiler): introduce summaries for metadata (#12799)

This does not yet introduce loading / serialization of summaries.

Part of #12787
This commit is contained in:
Tobias Bosch
2016-11-10 16:27:53 -08:00
committed by Victor Berchet
parent ef881475e9
commit fcb4e66493
17 changed files with 727 additions and 396 deletions

View File

@ -8,7 +8,7 @@
import {SecurityContext} from '@angular/core';
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, LiteralPrimitive, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
import {Parser} from '../expression_parser/parser';
import {isPresent} from '../facade/lang';
@ -52,16 +52,16 @@ export class BoundProperty {
* Parses bindings in templates and in the directive host area.
*/
export class BindingParser {
pipesByName: Map<string, CompilePipeMetadata> = new Map();
pipesByName: Map<string, CompilePipeSummary> = new Map();
constructor(
private _exprParser: Parser, private _interpolationConfig: InterpolationConfig,
private _schemaRegistry: ElementSchemaRegistry, pipes: CompilePipeMetadata[],
private _schemaRegistry: ElementSchemaRegistry, pipes: CompilePipeSummary[],
private _targetErrors: ParseError[]) {
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
}
createDirectiveHostPropertyAsts(dirMeta: CompileDirectiveMetadata, sourceSpan: ParseSourceSpan):
createDirectiveHostPropertyAsts(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
BoundElementPropertyAst[] {
if (dirMeta.hostProperties) {
const boundProps: BoundProperty[] = [];
@ -79,7 +79,7 @@ export class BindingParser {
}
}
createDirectiveHostEventAsts(dirMeta: CompileDirectiveMetadata, sourceSpan: ParseSourceSpan):
createDirectiveHostEventAsts(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
BoundEventAst[] {
if (dirMeta.hostListeners) {
const targetEventAsts: BoundEventAst[] = [];

View File

@ -8,7 +8,7 @@
import {SecurityContext} from '@angular/core';
import {CompileDirectiveMetadata, CompileProviderMetadata, CompileTokenMetadata} from '../compile_metadata';
import {CompileDirectiveSummary, CompileProviderMetadata, CompileTokenMetadata} from '../compile_metadata';
import {AST} from '../expression_parser/ast';
import {ParseSourceSpan} from '../parse_util';
import {LifecycleHooks} from '../private_import_core';
@ -168,7 +168,7 @@ export class BoundDirectivePropertyAst implements TemplateAst {
*/
export class DirectiveAst implements TemplateAst {
constructor(
public directive: CompileDirectiveMetadata, public inputs: BoundDirectivePropertyAst[],
public directive: CompileDirectiveSummary, public inputs: BoundDirectivePropertyAst[],
public hostProperties: BoundElementPropertyAst[], public hostEvents: BoundEventAst[],
public sourceSpan: ParseSourceSpan) {}
visit(visitor: TemplateAstVisitor, context: any): any {

View File

@ -8,7 +8,7 @@
import {Inject, Injectable, OpaqueToken, Optional, SchemaMetadata, SecurityContext} from '@angular/core';
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileTemplateMetadata, CompileTokenMetadata, removeIdentifierDuplicates} from '../compile_metadata';
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileTemplateMetadata, CompileTemplateSummary, CompileTokenMetadata, CompileTypeMetadata, removeIdentifierDuplicates} from '../compile_metadata';
import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
import {Parser} from '../expression_parser/parser';
import {isPresent} from '../facade/lang';
@ -90,8 +90,8 @@ export class TemplateParser {
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
parse(
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[], schemas: SchemaMetadata[], templateUrl: string): TemplateAst[] {
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveSummary[],
pipes: CompilePipeSummary[], schemas: SchemaMetadata[], templateUrl: string): TemplateAst[] {
const result = this.tryParse(component, template, directives, pipes, schemas, templateUrl);
const warnings = result.errors.filter(error => error.level === ParseErrorLevel.WARNING);
const errors = result.errors.filter(error => error.level === ParseErrorLevel.FATAL);
@ -109,8 +109,8 @@ export class TemplateParser {
}
tryParse(
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[], schemas: SchemaMetadata[],
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveSummary[],
pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
templateUrl: string): TemplateParseResult {
return this.tryParseHtml(
this.expandHtml(this._htmlParser.parse(
@ -120,13 +120,13 @@ export class TemplateParser {
tryParseHtml(
htmlAstWithErrors: ParseTreeResult, component: CompileDirectiveMetadata, template: string,
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
schemas: SchemaMetadata[], templateUrl: string): TemplateParseResult {
directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
templateUrl: string): TemplateParseResult {
var result: TemplateAst[];
var errors = htmlAstWithErrors.errors;
if (htmlAstWithErrors.rootNodes.length > 0) {
const uniqDirectives = removeIdentifierDuplicates(directives);
const uniqPipes = removeIdentifierDuplicates(pipes);
const uniqDirectives = removeSummaryDuplicates(directives);
const uniqPipes = removeSummaryDuplicates(pipes);
const providerViewContext =
new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan);
let interpolationConfig: InterpolationConfig;
@ -200,14 +200,14 @@ export class TemplateParser {
class TemplateParseVisitor implements html.Visitor {
selectorMatcher = new SelectorMatcher();
directivesIndex = new Map<CompileDirectiveMetadata, number>();
directivesIndex = new Map<CompileDirectiveSummary, number>();
ngContentCount: number = 0;
constructor(
public providerViewContext: ProviderViewContext, directives: CompileDirectiveMetadata[],
public providerViewContext: ProviderViewContext, directives: CompileDirectiveSummary[],
private _bindingParser: BindingParser, private _schemaRegistry: ElementSchemaRegistry,
private _schemas: SchemaMetadata[], private _targetErrors: TemplateParseError[]) {
directives.forEach((directive: CompileDirectiveMetadata, index: number) => {
directives.forEach((directive, index) => {
const selector = CssSelector.parse(directive.selector);
this.selectorMatcher.addSelectables(selector, directive);
this.directivesIndex.set(directive, index);
@ -360,7 +360,8 @@ class TemplateParseVisitor implements html.Visitor {
componentDirectiveAst.directive.template));
const componentTemplate = providerContext.viewContext.component.template;
this._validateElementAnimationInputOutputs(elementProps, events, componentTemplate);
this._validateElementAnimationInputOutputs(
elementProps, events, componentTemplate.toSummary());
}
if (hasInlineTemplates) {
@ -392,9 +393,9 @@ class TemplateParseVisitor implements html.Visitor {
private _validateElementAnimationInputOutputs(
inputs: BoundElementPropertyAst[], outputs: BoundEventAst[],
template: CompileTemplateMetadata) {
template: CompileTemplateSummary) {
const triggerLookup = new Set<string>();
template.animations.forEach(entry => { triggerLookup.add(entry.name); });
template.animations.forEach(entry => { triggerLookup.add(entry); });
const animationInputs = inputs.filter(input => input.isAnimation);
animationInputs.forEach(input => {
@ -518,7 +519,7 @@ class TemplateParseVisitor implements html.Visitor {
}
private _parseDirectives(selectorMatcher: SelectorMatcher, elementCssSelector: CssSelector):
{directives: CompileDirectiveMetadata[], matchElement: boolean} {
{directives: CompileDirectiveSummary[], matchElement: boolean} {
// Need to sort the directives so that we get consistent results throughout,
// as selectorMatcher uses Maps inside.
// Also deduplicate directives as they might match more than one time!
@ -538,12 +539,12 @@ class TemplateParseVisitor implements html.Visitor {
}
private _createDirectiveAsts(
isTemplateElement: boolean, elementName: string, directives: CompileDirectiveMetadata[],
isTemplateElement: boolean, elementName: string, directives: CompileDirectiveSummary[],
props: BoundProperty[], elementOrDirectiveRefs: ElementOrDirectiveRef[],
elementSourceSpan: ParseSourceSpan, targetReferences: ReferenceAst[]): DirectiveAst[] {
const matchedReferences = new Set<string>();
let component: CompileDirectiveMetadata = null;
const directiveAsts = directives.map((directive: CompileDirectiveMetadata) => {
let component: CompileDirectiveSummary = null;
const directiveAsts = directives.map((directive) => {
const sourceSpan = new ParseSourceSpan(
elementSourceSpan.start, elementSourceSpan.end, `Directive ${directive.type.name}`);
if (directive.isComponent) {
@ -837,3 +838,15 @@ const NON_BINDABLE_VISITOR = new NonBindableVisitor();
function _isEmptyTextNode(node: html.Node): boolean {
return node instanceof html.Text && node.value.trim().length == 0;
}
export function removeSummaryDuplicates<T extends{type: CompileTypeMetadata}>(items: T[]): T[] {
const map = new Map<any, T>();
items.forEach((item) => {
if (!map.get(item.type.reference)) {
map.set(item.type.reference, item);
}
});
return Array.from(map.values());
}