refactor(compiler): minor cleanups

This commit is contained in:
Tobias Bosch 2016-10-24 11:11:31 -07:00 committed by vsavkin
parent 4cac650675
commit fe299f4dfc
11 changed files with 184 additions and 118 deletions

View File

@ -22,13 +22,14 @@ export function createDiTokenExpression(token: CompileTokenMetadata): o.Expressi
}
}
export function createFastArray(values: o.Expression[]): o.Expression {
export function createInlineArray(values: o.Expression[]): o.Expression {
if (values.length === 0) {
return o.importExpr(resolveIdentifier(Identifiers.EMPTY_FAST_ARRAY));
return o.importExpr(resolveIdentifier(Identifiers.EMPTY_INLINE_ARRAY));
}
const index = Math.ceil(values.length / 2) - 1;
const identifierSpec = index < Identifiers.fastArrays.length ? Identifiers.fastArrays[index] :
Identifiers.FastArrayDynamic;
const log2 = Math.log(values.length) / Math.log(2);
const index = Math.ceil(log2);
const identifierSpec = index < Identifiers.inlineArrays.length ? Identifiers.inlineArrays[index] :
Identifiers.InlineArrayDynamic;
const identifier = resolveIdentifier(identifierSpec);
return o.importExpr(identifier).instantiate([
<o.Expression>o.literal(values.length)

View File

@ -48,9 +48,9 @@ export class DirectiveWrapperCompiler {
compile(dirMeta: CompileDirectiveMetadata): DirectiveWrapperCompileResult {
const builder = new DirectiveWrapperBuilder(this.compilerConfig, dirMeta);
Object.keys(dirMeta.inputs).forEach((inputFieldName) => {
createCheckInputMethod(inputFieldName, builder);
addCheckInputMethod(inputFieldName, builder);
});
createDetectChangesInternalMethod(builder);
addDetectChangesInternalMethod(builder);
const classStmt = builder.build();
return new DirectiveWrapperCompileResult([classStmt], classStmt.name);
}
@ -102,12 +102,12 @@ class DirectiveWrapperBuilder implements ClassBuilder {
return createClassStmt({
name: DirectiveWrapperCompiler.dirWrapperClassName(this.dirMeta.type),
ctorParams: dirDepParamNames.map((paramName) => new o.FnParam(paramName, o.DYNAMIC_TYPE)),
builders: [{fields: fields, ctorStmts: ctorStmts}, this]
})
builders: [{fields, ctorStmts}, this]
});
}
}
function createDetectChangesInternalMethod(builder: DirectiveWrapperBuilder) {
function addDetectChangesInternalMethod(builder: DirectiveWrapperBuilder) {
const changedVar = o.variable('changed');
const stmts: o.Statement[] = [
changedVar.set(o.THIS_EXPR.prop(CHANGED_FIELD_NAME)).toDeclStmt(),
@ -157,7 +157,7 @@ function createDetectChangesInternalMethod(builder: DirectiveWrapperBuilder) {
stmts, o.BOOL_TYPE));
}
function createCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
function addCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
const fieldName = `_${input}`;
const fieldExpr = o.THIS_EXPR.prop(fieldName);
// private is fine here as no child view will reference the cached value...

View File

@ -294,23 +294,24 @@ export class Identifiers {
};
// This is just the interface!
static FastArray:
IdentifierSpec = {name: 'FastArray', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: null};
static fastArrays: IdentifierSpec[] = [
{name: 'FastArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray2},
{name: 'FastArray4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray4},
{name: 'FastArray8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray8},
{name: 'FastArray16', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray16},
static InlineArray:
IdentifierSpec = {name: 'InlineArray', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: null};
static inlineArrays: IdentifierSpec[] = [
{name: 'InlineArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray2},
{name: 'InlineArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray2},
{name: 'InlineArray4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray4},
{name: 'InlineArray8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray8},
{name: 'InlineArray16', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray16},
];
static EMPTY_FAST_ARRAY: IdentifierSpec = {
name: 'EMPTY_FAST_ARRAY',
static EMPTY_INLINE_ARRAY: IdentifierSpec = {
name: 'EMPTY_INLINE_ARRAY',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.EMPTY_FAST_ARRAY
runtime: view_utils.EMPTY_INLINE_ARRAY
};
static FastArrayDynamic: IdentifierSpec = {
name: 'FastArrayDynamic',
static InlineArrayDynamic: IdentifierSpec = {
name: 'InlineArrayDynamic',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.FastArrayDynamic
runtime: view_utils.InlineArrayDynamic
};
}

View File

@ -84,14 +84,14 @@ export class NgModuleCompiler {
}
class _InjectorBuilder implements ClassBuilder {
private _tokens: CompileTokenMetadata[] = [];
private _instances = new Map<any, o.Expression>();
fields: o.ClassField[] = [];
private _createStmts: o.Statement[] = [];
private _destroyStmts: o.Statement[] = [];
getters: o.ClassGetter[] = [];
methods: o.ClassMethod[] = [];
ctorStmts: o.Statement[] = [];
private _tokens: CompileTokenMetadata[] = [];
private _instances = new Map<any, o.Expression>();
private _createStmts: o.Statement[] = [];
private _destroyStmts: o.Statement[] = [];
constructor(
private _ngModuleMeta: CompileNgModuleMetadata,
@ -154,7 +154,7 @@ class _InjectorBuilder implements ClassBuilder {
parent: o.importExpr(
resolveIdentifier(Identifiers.NgModuleInjector), [o.importType(this._ngModuleMeta.type)]),
parentArgs: parentArgs,
builders: [{methods: methods}, this]
builders: [{methods}, this]
});
}

View File

@ -28,9 +28,6 @@ const STYLE_PREFIX = 'style';
const ANIMATE_PROP_PREFIX = 'animate-';
/**
* Type of a parsed property
*/
export enum BoundPropertyType {
DEFAULT,
LITERAL_ATTR,
@ -55,18 +52,17 @@ export class BoundProperty {
*/
export class BindingParser {
pipesByName: Map<string, CompilePipeMetadata> = new Map();
errors: ParseError[] = [];
constructor(
private _exprParser: Parser, private _interpolationConfig: InterpolationConfig,
protected _schemaRegistry: ElementSchemaRegistry, protected _schemas: SchemaMetadata[],
pipes: CompilePipeMetadata[]) {
private _schemaRegistry: ElementSchemaRegistry, private _schemas: SchemaMetadata[],
pipes: CompilePipeMetadata[], private _targetErrors: ParseError[]) {
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
}
createDirectiveHostPropertyAsts(
elementName: string, hostProps: {[key: string]: string}, sourceSpan: ParseSourceSpan,
targetPropertyAsts: BoundElementPropertyAst[]) {
elementName: string, hostProps: {[key: string]: string},
sourceSpan: ParseSourceSpan): BoundElementPropertyAst[] {
if (hostProps) {
const boundProps: BoundProperty[] = [];
Object.keys(hostProps).forEach(propName => {
@ -74,30 +70,30 @@ export class BindingParser {
if (typeof expression === 'string') {
this.parsePropertyBinding(propName, expression, true, sourceSpan, [], boundProps);
} else {
this.reportError(
this._reportError(
`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
sourceSpan);
}
});
boundProps.forEach(
(prop) => { targetPropertyAsts.push(this.createElementPropertyAst(elementName, prop)); });
return boundProps.map((prop) => this.createElementPropertyAst(elementName, prop));
}
}
createDirectiveHostEventAsts(
hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan,
targetEventAsts: BoundEventAst[]) {
createDirectiveHostEventAsts(hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan):
BoundEventAst[] {
if (hostListeners) {
const targetEventAsts: BoundEventAst[] = [];
Object.keys(hostListeners).forEach(propName => {
const expression = hostListeners[propName];
if (typeof expression === 'string') {
this.parseEvent(propName, expression, sourceSpan, [], targetEventAsts);
} else {
this.reportError(
this._reportError(
`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
sourceSpan);
}
});
return targetEventAsts;
}
}
@ -115,7 +111,7 @@ export class BindingParser {
}
return ast;
} catch (e) {
this.reportError(`${e}`, sourceSpan);
this._reportError(`${e}`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
}
@ -150,10 +146,10 @@ export class BindingParser {
}
});
bindingsResult.warnings.forEach(
(warning) => { this.reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
(warning) => { this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
return bindingsResult.templateBindings;
} catch (e) {
this.reportError(`${e}`, sourceSpan);
this._reportError(`${e}`, sourceSpan);
return [];
}
}
@ -163,8 +159,8 @@ export class BindingParser {
targetProps: BoundProperty[]) {
if (_isAnimationLabel(name)) {
name = name.substring(1);
if (isPresent(value) && value.length > 0) {
this.reportError(
if (value) {
this._reportError(
`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`,
sourceSpan, ParseErrorLevel.FATAL);
@ -239,7 +235,7 @@ export class BindingParser {
this._checkPipes(ast, sourceSpan);
return ast;
} catch (e) {
this.reportError(`${e}`, sourceSpan);
this._reportError(`${e}`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
}
@ -271,7 +267,7 @@ export class BindingParser {
`\n1. If '${elementName}' is an Angular component and it has '${boundPropertyName}' input, then verify that it is part of this module.` +
`\n2. If '${elementName}' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message.\n`;
}
this.reportError(errorMsg, boundProp.sourceSpan);
this._reportError(errorMsg, boundProp.sourceSpan);
}
} else {
if (parts[0] == ATTRIBUTE_PREFIX) {
@ -299,7 +295,7 @@ export class BindingParser {
bindingType = PropertyBindingType.Style;
securityContext = SecurityContext.STYLE;
} else {
this.reportError(`Invalid property name '${boundProp.name}'`, boundProp.sourceSpan);
this._reportError(`Invalid property name '${boundProp.name}'`, boundProp.sourceSpan);
bindingType = null;
securityContext = null;
}
@ -336,13 +332,13 @@ export class BindingParser {
break;
default:
this.reportError(
this._reportError(
`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`,
sourceSpan);
break;
}
} else {
this.reportError(
this._reportError(
`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`,
sourceSpan);
}
@ -369,26 +365,26 @@ export class BindingParser {
this._reportExpressionParserErrors(ast.errors, sourceSpan);
}
if (!ast || ast.ast instanceof EmptyExpr) {
this.reportError(`Empty expressions are not allowed`, sourceSpan);
this._reportError(`Empty expressions are not allowed`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
this._checkPipes(ast, sourceSpan);
return ast;
} catch (e) {
this.reportError(`${e}`, sourceSpan);
this._reportError(`${e}`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
}
}
reportError(
private _reportError(
message: string, sourceSpan: ParseSourceSpan,
level: ParseErrorLevel = ParseErrorLevel.FATAL) {
this.errors.push(new ParseError(sourceSpan, message, level));
this._targetErrors.push(new ParseError(sourceSpan, message, level));
}
private _reportExpressionParserErrors(errors: ParserError[], sourceSpan: ParseSourceSpan) {
for (const error of errors) {
this.reportError(error.message, sourceSpan);
this._reportError(error.message, sourceSpan);
}
}
@ -398,7 +394,7 @@ export class BindingParser {
ast.visit(collector);
collector.pipes.forEach((pipeName) => {
if (!this.pipesByName.has(pipeName)) {
this.reportError(`The pipe '${pipeName}' could not be found`, sourceSpan);
this._reportError(`The pipe '${pipeName}' could not be found`, sourceSpan);
}
});
}
@ -415,13 +411,13 @@ export class BindingParser {
const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
this._schemaRegistry.validateProperty(propName);
if (report.error) {
this.reportError(report.msg, sourceSpan, ParseErrorLevel.FATAL);
this._reportError(report.msg, sourceSpan, ParseErrorLevel.FATAL);
}
}
}
export class PipeCollector extends RecursiveAstVisitor {
pipes: Set<string> = new Set<string>();
pipes = new Set<string>();
visitPipe(ast: BindingPipe, context: any): any {
this.pipes.add(ast.name);
ast.exp.visit(this);

View File

@ -136,11 +136,13 @@ export class TemplateParser {
end: component.template.interpolation[1]
};
}
const bindingParser = new BindingParser(
this._exprParser, interpolationConfig, this._schemaRegistry, schemas, uniqPipes, errors);
const parseVisitor = new TemplateParseVisitor(
providerViewContext, uniqDirectives, uniqPipes, this._exprParser, interpolationConfig,
this._schemaRegistry, schemas);
providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas,
errors);
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
errors.push(...parseVisitor.errors, ...providerViewContext.errors);
errors.push(...providerViewContext.errors);
} else {
result = [];
}
@ -196,18 +198,15 @@ export class TemplateParser {
}
}
class TemplateParseVisitor extends BindingParser implements html.Visitor {
class TemplateParseVisitor implements html.Visitor {
selectorMatcher = new SelectorMatcher();
errors: TemplateParseError[] = [];
directivesIndex = new Map<CompileDirectiveMetadata, number>();
ngContentCount: number = 0;
constructor(
public providerViewContext: ProviderViewContext, directives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[], _exprParser: Parser, interpolationConfig: InterpolationConfig,
_schemaRegistry: ElementSchemaRegistry, schemas: SchemaMetadata[]) {
super(_exprParser, interpolationConfig, _schemaRegistry, schemas, pipes);
private _bindingParser: BindingParser, private _schemaRegistry: ElementSchemaRegistry,
private _schemas: SchemaMetadata[], private _targetErrors: TemplateParseError[]) {
directives.forEach((directive: CompileDirectiveMetadata, index: number) => {
const selector = CssSelector.parse(directive.selector);
this.selectorMatcher.addSelectables(selector, directive);
@ -221,7 +220,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
visitText(text: html.Text, parent: ElementContext): any {
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR);
const expr = this.parseInterpolation(text.value, text.sourceSpan);
const expr = this._bindingParser.parseInterpolation(text.value, text.sourceSpan);
if (isPresent(expr)) {
return new BoundTextAst(expr, ngContentIndex, text.sourceSpan);
} else {
@ -282,12 +281,12 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
const hasTemplateBinding = isPresent(templateBindingsSource);
if (hasTemplateBinding) {
if (hasInlineTemplates) {
this.reportError(
this._reportError(
`Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *`,
attr.sourceSpan);
}
hasInlineTemplates = true;
this.parseInlineTemplateBinding(
this._bindingParser.parseInlineTemplateBinding(
attr.name, templateBindingsSource, attr.sourceSpan, templateMatchableAttrs,
templateElementOrDirectiveProps, templateElementVars);
}
@ -327,7 +326,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
if (element.children && !element.children.every(_isEmptyTextNode)) {
this.reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
}
parsedElement = new NgContentAst(
@ -400,7 +399,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
animationInputs.forEach(input => {
const name = input.name;
if (!triggerLookup.has(name)) {
this.reportError(`Couldn't find an animation entry for "${name}"`, input.sourceSpan);
this._reportError(`Couldn't find an animation entry for "${name}"`, input.sourceSpan);
}
});
@ -408,7 +407,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
if (output.isAnimation) {
const found = animationInputs.find(input => input.name == output.name);
if (!found) {
this.reportError(
this._reportError(
`Unable to listen on (@${output.name}.${output.phase}) because the animation trigger [@${output.name}] isn't being used on the same element`,
output.sourceSpan);
}
@ -430,7 +429,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
if (bindParts !== null) {
hasBinding = true;
if (isPresent(bindParts[KW_BIND_IDX])) {
this.parsePropertyBinding(
this._bindingParser.parsePropertyBinding(
bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps);
} else if (bindParts[KW_LET_IDX]) {
@ -438,7 +437,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
const identifier = bindParts[IDENT_KW_IDX];
this._parseVariable(identifier, value, srcSpan, targetVars);
} else {
this.reportError(`"let-" is only supported on template elements.`, srcSpan);
this._reportError(`"let-" is only supported on template elements.`, srcSpan);
}
} else if (bindParts[KW_REF_IDX]) {
@ -446,41 +445,42 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
this._parseReference(identifier, value, srcSpan, targetRefs);
} else if (bindParts[KW_ON_IDX]) {
this.parseEvent(
this._bindingParser.parseEvent(
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
} else if (bindParts[KW_BINDON_IDX]) {
this.parsePropertyBinding(
this._bindingParser.parsePropertyBinding(
bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps);
this._parseAssignmentEvent(
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
} else if (bindParts[KW_AT_IDX]) {
this.parseLiteralAttr(name, value, srcSpan, targetMatchableAttrs, targetProps);
this._bindingParser.parseLiteralAttr(
name, value, srcSpan, targetMatchableAttrs, targetProps);
} else if (bindParts[IDENT_BANANA_BOX_IDX]) {
this.parsePropertyBinding(
this._bindingParser.parsePropertyBinding(
bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, targetMatchableAttrs,
targetProps);
this._parseAssignmentEvent(
bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
} else if (bindParts[IDENT_PROPERTY_IDX]) {
this.parsePropertyBinding(
this._bindingParser.parsePropertyBinding(
bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, targetMatchableAttrs,
targetProps);
} else if (bindParts[IDENT_EVENT_IDX]) {
this.parseEvent(
this._bindingParser.parseEvent(
bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
}
} else {
hasBinding =
this.parsePropertyInterpolation(name, value, srcSpan, targetMatchableAttrs, targetProps);
hasBinding = this._bindingParser.parsePropertyInterpolation(
name, value, srcSpan, targetMatchableAttrs, targetProps);
}
if (!hasBinding) {
this.parseLiteralAttr(name, value, srcSpan, targetMatchableAttrs, targetProps);
this._bindingParser.parseLiteralAttr(name, value, srcSpan, targetMatchableAttrs, targetProps);
}
return hasBinding;
@ -493,7 +493,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
private _parseVariable(
identifier: string, value: string, sourceSpan: ParseSourceSpan, targetVars: VariableAst[]) {
if (identifier.indexOf('-') > -1) {
this.reportError(`"-" is not allowed in variable names`, sourceSpan);
this._reportError(`"-" is not allowed in variable names`, sourceSpan);
}
targetVars.push(new VariableAst(identifier, value, sourceSpan));
@ -503,7 +503,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
identifier: string, value: string, sourceSpan: ParseSourceSpan,
targetRefs: ElementOrDirectiveRef[]) {
if (identifier.indexOf('-') > -1) {
this.reportError(`"-" is not allowed in reference names`, sourceSpan);
this._reportError(`"-" is not allowed in reference names`, sourceSpan);
}
targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
@ -512,7 +512,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
private _parseAssignmentEvent(
name: string, expression: string, sourceSpan: ParseSourceSpan,
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
this.parseEvent(
this._bindingParser.parseEvent(
`${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, targetEvents);
}
@ -548,12 +548,11 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
if (directive.isComponent) {
component = directive;
}
const hostProperties: BoundElementPropertyAst[] = [];
const hostEvents: BoundEventAst[] = [];
const directiveProperties: BoundDirectivePropertyAst[] = [];
this.createDirectiveHostPropertyAsts(
elementName, directive.hostProperties, sourceSpan, hostProperties);
this.createDirectiveHostEventAsts(directive.hostListeners, sourceSpan, hostEvents);
const hostProperties = this._bindingParser.createDirectiveHostPropertyAsts(
elementName, directive.hostProperties, sourceSpan);
const hostEvents =
this._bindingParser.createDirectiveHostEventAsts(directive.hostListeners, sourceSpan);
this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties);
elementOrDirectiveRefs.forEach((elOrDirRef) => {
if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
@ -569,7 +568,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
elementOrDirectiveRefs.forEach((elOrDirRef) => {
if (elOrDirRef.value.length > 0) {
if (!matchedReferences.has(elOrDirRef.name)) {
this.reportError(
this._reportError(
`There is no directive with "exportAs" set to "${elOrDirRef.value}"`,
elOrDirRef.sourceSpan);
}
@ -624,7 +623,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
props.forEach((prop: BoundProperty) => {
if (!prop.isLiteral && !boundDirectivePropsIndex.get(prop.name)) {
boundElementProps.push(this.createElementPropertyAst(elementName, prop));
boundElementProps.push(this._bindingParser.createElementPropertyAst(elementName, prop));
}
});
return boundElementProps;
@ -642,7 +641,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) {
const componentTypeNames = this._findComponentDirectiveNames(directives);
if (componentTypeNames.length > 1) {
this.reportError(`More than one component: ${componentTypeNames.join(',')}`, sourceSpan);
this._reportError(`More than one component: ${componentTypeNames.join(',')}`, sourceSpan);
}
}
@ -662,7 +661,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
const errorMsg = `'${elName}' is not a known element:\n` +
`1. If '${elName}' is an Angular component, then verify that it is part of this module.\n` +
`2. If '${elName}' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message.`;
this.reportError(errorMsg, element.sourceSpan);
this._reportError(errorMsg, element.sourceSpan);
}
}
@ -671,11 +670,11 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
sourceSpan: ParseSourceSpan) {
const componentTypeNames: string[] = this._findComponentDirectiveNames(directives);
if (componentTypeNames.length > 0) {
this.reportError(
this._reportError(
`Components on an embedded template: ${componentTypeNames.join(',')}`, sourceSpan);
}
elementProps.forEach(prop => {
this.reportError(
this._reportError(
`Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section.`,
sourceSpan);
});
@ -694,12 +693,18 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
events.forEach(event => {
if (isPresent(event.target) || !allDirectiveEvents.has(event.name)) {
this.reportError(
this._reportError(
`Event binding ${event.fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "directives" section.`,
event.sourceSpan);
}
});
}
private _reportError(
message: string, sourceSpan: ParseSourceSpan,
level: ParseErrorLevel = ParseErrorLevel.FATAL) {
this._targetErrors.push(new ParseError(sourceSpan, message, level));
}
}
class NonBindableVisitor implements html.Visitor {

View File

@ -10,7 +10,7 @@ import {ViewEncapsulation} from '@angular/core';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
import {createSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
import {createDiTokenExpression, createFastArray} from '../compiler_util/identifier_util';
import {createDiTokenExpression, createInlineArray} from '../compiler_util/identifier_util';
import {isPresent} from '../facade/lang';
import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
import {createClassStmt} from '../output/class_builder';
@ -167,7 +167,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
'createTemplateAnchor', [this._getParentRenderNode(parent), debugContextExpr]);
} else {
const htmlAttrs = _readHtmlAttrs(ast.attrs);
const attrNameAndValues = createFastArray(
const attrNameAndValues = createInlineArray(
_mergeHtmlAndDirectiveAttrs(htmlAttrs, directives).map(v => o.literal(v)));
if (nodeIndex === 0 && this.view.viewType === ViewType.HOST) {
createRenderNodeExpr =

View File

@ -0,0 +1,63 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {createInlineArray} from '../../src/compiler_util/identifier_util';
import {Identifiers, resolveIdentifier} from '../../src/identifiers';
import * as o from '../../src/output/output_ast';
export function main() {
describe('createInlineArray', () => {
function check(argCount: number, expectedIdentifier: any) {
const args = createArgs(argCount);
expect(createInlineArray(args))
.toEqual(o.importExpr(resolveIdentifier(expectedIdentifier)).instantiate([
<o.Expression>o.literal(argCount)
].concat(args)));
}
function createArgs(count: number): o.Expression[] {
const result: o.Expression[] = [];
for (var i = 0; i < count; i++) {
result.push(o.NULL_EXPR);
}
return result;
}
it('should work for arrays of length 0', () => {
expect(createInlineArray([
])).toEqual(o.importExpr(resolveIdentifier(Identifiers.EMPTY_INLINE_ARRAY)));
});
it('should work for arrays of length 1 - 2', () => {
check(1, Identifiers.inlineArrays[0]);
check(2, Identifiers.inlineArrays[1]);
});
it('should work for arrays of length 3 - 4', () => {
for (var i = 3; i <= 4; i++) {
check(i, Identifiers.inlineArrays[2]);
}
});
it('should work for arrays of length 5 - 8', () => {
for (var i = 5; i <= 8; i++) {
check(i, Identifiers.inlineArrays[3]);
}
});
it('should work for arrays of length 9 - 16', () => {
for (var i = 9; i <= 16; i++) {
check(i, Identifiers.inlineArrays[4]);
}
});
it('should work for arrays of length > 16',
() => { check(17, Identifiers.InlineArrayDynamic); });
});
}

View File

@ -379,7 +379,7 @@ function camelCaseToDashCase(input: string): string {
}
export function createRenderElement(
renderer: Renderer, parentElement: any, name: string, attrs: FastArray<string>,
renderer: Renderer, parentElement: any, name: string, attrs: InlineArray<string>,
debugInfo?: RenderDebugInfo): any {
const el = renderer.createElement(parentElement, name, debugInfo);
for (var i = 0; i < attrs.length; i += 2) {
@ -389,8 +389,8 @@ export function createRenderElement(
}
export function selectOrCreateRenderHostElement(
renderer: Renderer, elementName: string, attrs: FastArray<string>,
rootSelectorOrNode: string | any, debugInfo: RenderDebugInfo): any {
renderer: Renderer, elementName: string, attrs: InlineArray<string>,
rootSelectorOrNode: string | any, debugInfo?: RenderDebugInfo): any {
var hostElement: any;
if (isPresent(rootSelectorOrNode)) {
hostElement = renderer.selectRootElement(rootSelectorOrNode, debugInfo);
@ -400,17 +400,17 @@ export function selectOrCreateRenderHostElement(
return hostElement;
}
export interface FastArray<T> {
export interface InlineArray<T> {
length: number;
get(index: number): T;
}
class FastArray0 implements FastArray<any> {
class InlineArray0 implements InlineArray<any> {
length = 0;
get(index: number): any { return undefined; }
}
export class FastArray2<T> implements FastArray<T> {
export class InlineArray2<T> implements InlineArray<T> {
constructor(public length: number, private _v0: T, private _v1: T) {}
get(index: number) {
switch (index) {
@ -424,7 +424,7 @@ export class FastArray2<T> implements FastArray<T> {
}
}
export class FastArray4<T> implements FastArray<T> {
export class InlineArray4<T> implements InlineArray<T> {
constructor(
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T) {}
get(index: number) {
@ -443,7 +443,7 @@ export class FastArray4<T> implements FastArray<T> {
}
}
export class FastArray8<T> implements FastArray<T> {
export class InlineArray8<T> implements InlineArray<T> {
constructor(
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T,
private _v4: T, private _v5: T, private _v6: T, private _v7: T) {}
@ -471,7 +471,7 @@ export class FastArray8<T> implements FastArray<T> {
}
}
export class FastArray16<T> implements FastArray<T> {
export class InlineArray16<T> implements InlineArray<T> {
constructor(
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T,
private _v4: T, private _v5: T, private _v6: T, private _v7: T, private _v8: T,
@ -517,7 +517,7 @@ export class FastArray16<T> implements FastArray<T> {
}
}
export class FastArrayDynamic<T> implements FastArray<T> {
export class InlineArrayDynamic<T> implements InlineArray<T> {
private _values: any[];
// Note: We still take the length argument so this class can be created
// in the same ways as the other classes!
@ -526,4 +526,4 @@ export class FastArrayDynamic<T> implements FastArray<T> {
get(index: number) { return this._values[index]; }
}
export const EMPTY_FAST_ARRAY: FastArray<any> = new FastArray0();
export const EMPTY_INLINE_ARRAY: InlineArray<any> = new InlineArray0();

View File

@ -34,7 +34,7 @@ class _View_TreeComponent_Host0 extends import1.AppView<any> {
}
createInternal(rootSelector: string): import2.AppElement {
this._el_0 = import4.selectOrCreateRenderHostElement(
this.renderer, 'tree', import4.EMPTY_FAST_ARRAY, rootSelector, (null as any));
this.renderer, 'tree', import4.EMPTY_INLINE_ARRAY, rootSelector, (null as any));
this._vc_0 = new import2.AppElement(0, (null as any), this, this._el_0);
this._TreeComponent_0_4 = new _View_TreeComponent0(this._el_0);
this._vc_0.initComponent(this._TreeComponent_0_4.context, [], <any>this._TreeComponent_0_4);

View File

@ -36,7 +36,7 @@ class _View_TreeRootComponent_Host0 extends import1.AppView<any> {
}
createInternal(rootSelector: string): import2.AppElement {
this._el_0 = import4.selectOrCreateRenderHostElement(
this.renderer, 'tree', import4.EMPTY_FAST_ARRAY, rootSelector, (null as any));
this.renderer, 'tree', import4.EMPTY_INLINE_ARRAY, rootSelector, (null as any));
this._appEl_0 = new import2.AppElement(0, (null as any), this, this._el_0);
var compView_0: any =
viewFactory_TreeRootComponent0(this.viewUtils, this.injector(0), this._appEl_0);