refactor(compiler): minor cleanups
This commit is contained in:
parent
4cac650675
commit
fe299f4dfc
|
@ -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) {
|
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 log2 = Math.log(values.length) / Math.log(2);
|
||||||
const identifierSpec = index < Identifiers.fastArrays.length ? Identifiers.fastArrays[index] :
|
const index = Math.ceil(log2);
|
||||||
Identifiers.FastArrayDynamic;
|
const identifierSpec = index < Identifiers.inlineArrays.length ? Identifiers.inlineArrays[index] :
|
||||||
|
Identifiers.InlineArrayDynamic;
|
||||||
const identifier = resolveIdentifier(identifierSpec);
|
const identifier = resolveIdentifier(identifierSpec);
|
||||||
return o.importExpr(identifier).instantiate([
|
return o.importExpr(identifier).instantiate([
|
||||||
<o.Expression>o.literal(values.length)
|
<o.Expression>o.literal(values.length)
|
||||||
|
|
|
@ -48,9 +48,9 @@ export class DirectiveWrapperCompiler {
|
||||||
compile(dirMeta: CompileDirectiveMetadata): DirectiveWrapperCompileResult {
|
compile(dirMeta: CompileDirectiveMetadata): DirectiveWrapperCompileResult {
|
||||||
const builder = new DirectiveWrapperBuilder(this.compilerConfig, dirMeta);
|
const builder = new DirectiveWrapperBuilder(this.compilerConfig, dirMeta);
|
||||||
Object.keys(dirMeta.inputs).forEach((inputFieldName) => {
|
Object.keys(dirMeta.inputs).forEach((inputFieldName) => {
|
||||||
createCheckInputMethod(inputFieldName, builder);
|
addCheckInputMethod(inputFieldName, builder);
|
||||||
});
|
});
|
||||||
createDetectChangesInternalMethod(builder);
|
addDetectChangesInternalMethod(builder);
|
||||||
const classStmt = builder.build();
|
const classStmt = builder.build();
|
||||||
return new DirectiveWrapperCompileResult([classStmt], classStmt.name);
|
return new DirectiveWrapperCompileResult([classStmt], classStmt.name);
|
||||||
}
|
}
|
||||||
|
@ -102,12 +102,12 @@ class DirectiveWrapperBuilder implements ClassBuilder {
|
||||||
return createClassStmt({
|
return createClassStmt({
|
||||||
name: DirectiveWrapperCompiler.dirWrapperClassName(this.dirMeta.type),
|
name: DirectiveWrapperCompiler.dirWrapperClassName(this.dirMeta.type),
|
||||||
ctorParams: dirDepParamNames.map((paramName) => new o.FnParam(paramName, o.DYNAMIC_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 changedVar = o.variable('changed');
|
||||||
const stmts: o.Statement[] = [
|
const stmts: o.Statement[] = [
|
||||||
changedVar.set(o.THIS_EXPR.prop(CHANGED_FIELD_NAME)).toDeclStmt(),
|
changedVar.set(o.THIS_EXPR.prop(CHANGED_FIELD_NAME)).toDeclStmt(),
|
||||||
|
@ -157,7 +157,7 @@ function createDetectChangesInternalMethod(builder: DirectiveWrapperBuilder) {
|
||||||
stmts, o.BOOL_TYPE));
|
stmts, o.BOOL_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
|
function addCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
|
||||||
const fieldName = `_${input}`;
|
const fieldName = `_${input}`;
|
||||||
const fieldExpr = o.THIS_EXPR.prop(fieldName);
|
const fieldExpr = o.THIS_EXPR.prop(fieldName);
|
||||||
// private is fine here as no child view will reference the cached value...
|
// private is fine here as no child view will reference the cached value...
|
||||||
|
|
|
@ -294,23 +294,24 @@ export class Identifiers {
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is just the interface!
|
// This is just the interface!
|
||||||
static FastArray:
|
static InlineArray:
|
||||||
IdentifierSpec = {name: 'FastArray', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: null};
|
IdentifierSpec = {name: 'InlineArray', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: null};
|
||||||
static fastArrays: IdentifierSpec[] = [
|
static inlineArrays: IdentifierSpec[] = [
|
||||||
{name: 'FastArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray2},
|
{name: 'InlineArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray2},
|
||||||
{name: 'FastArray4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray4},
|
{name: 'InlineArray2', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray2},
|
||||||
{name: 'FastArray8', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray8},
|
{name: 'InlineArray4', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.InlineArray4},
|
||||||
{name: 'FastArray16', moduleUrl: VIEW_UTILS_MODULE_URL, runtime: view_utils.FastArray16},
|
{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 = {
|
static EMPTY_INLINE_ARRAY: IdentifierSpec = {
|
||||||
name: 'EMPTY_FAST_ARRAY',
|
name: 'EMPTY_INLINE_ARRAY',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
runtime: view_utils.EMPTY_FAST_ARRAY
|
runtime: view_utils.EMPTY_INLINE_ARRAY
|
||||||
};
|
};
|
||||||
static FastArrayDynamic: IdentifierSpec = {
|
static InlineArrayDynamic: IdentifierSpec = {
|
||||||
name: 'FastArrayDynamic',
|
name: 'InlineArrayDynamic',
|
||||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||||
runtime: view_utils.FastArrayDynamic
|
runtime: view_utils.InlineArrayDynamic
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,14 +84,14 @@ export class NgModuleCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InjectorBuilder implements ClassBuilder {
|
class _InjectorBuilder implements ClassBuilder {
|
||||||
private _tokens: CompileTokenMetadata[] = [];
|
|
||||||
private _instances = new Map<any, o.Expression>();
|
|
||||||
fields: o.ClassField[] = [];
|
fields: o.ClassField[] = [];
|
||||||
private _createStmts: o.Statement[] = [];
|
|
||||||
private _destroyStmts: o.Statement[] = [];
|
|
||||||
getters: o.ClassGetter[] = [];
|
getters: o.ClassGetter[] = [];
|
||||||
methods: o.ClassMethod[] = [];
|
methods: o.ClassMethod[] = [];
|
||||||
ctorStmts: o.Statement[] = [];
|
ctorStmts: o.Statement[] = [];
|
||||||
|
private _tokens: CompileTokenMetadata[] = [];
|
||||||
|
private _instances = new Map<any, o.Expression>();
|
||||||
|
private _createStmts: o.Statement[] = [];
|
||||||
|
private _destroyStmts: o.Statement[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _ngModuleMeta: CompileNgModuleMetadata,
|
private _ngModuleMeta: CompileNgModuleMetadata,
|
||||||
|
@ -154,7 +154,7 @@ class _InjectorBuilder implements ClassBuilder {
|
||||||
parent: o.importExpr(
|
parent: o.importExpr(
|
||||||
resolveIdentifier(Identifiers.NgModuleInjector), [o.importType(this._ngModuleMeta.type)]),
|
resolveIdentifier(Identifiers.NgModuleInjector), [o.importType(this._ngModuleMeta.type)]),
|
||||||
parentArgs: parentArgs,
|
parentArgs: parentArgs,
|
||||||
builders: [{methods: methods}, this]
|
builders: [{methods}, this]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,6 @@ const STYLE_PREFIX = 'style';
|
||||||
|
|
||||||
const ANIMATE_PROP_PREFIX = 'animate-';
|
const ANIMATE_PROP_PREFIX = 'animate-';
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of a parsed property
|
|
||||||
*/
|
|
||||||
export enum BoundPropertyType {
|
export enum BoundPropertyType {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
LITERAL_ATTR,
|
LITERAL_ATTR,
|
||||||
|
@ -55,18 +52,17 @@ export class BoundProperty {
|
||||||
*/
|
*/
|
||||||
export class BindingParser {
|
export class BindingParser {
|
||||||
pipesByName: Map<string, CompilePipeMetadata> = new Map();
|
pipesByName: Map<string, CompilePipeMetadata> = new Map();
|
||||||
errors: ParseError[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _exprParser: Parser, private _interpolationConfig: InterpolationConfig,
|
private _exprParser: Parser, private _interpolationConfig: InterpolationConfig,
|
||||||
protected _schemaRegistry: ElementSchemaRegistry, protected _schemas: SchemaMetadata[],
|
private _schemaRegistry: ElementSchemaRegistry, private _schemas: SchemaMetadata[],
|
||||||
pipes: CompilePipeMetadata[]) {
|
pipes: CompilePipeMetadata[], private _targetErrors: ParseError[]) {
|
||||||
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
|
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
createDirectiveHostPropertyAsts(
|
createDirectiveHostPropertyAsts(
|
||||||
elementName: string, hostProps: {[key: string]: string}, sourceSpan: ParseSourceSpan,
|
elementName: string, hostProps: {[key: string]: string},
|
||||||
targetPropertyAsts: BoundElementPropertyAst[]) {
|
sourceSpan: ParseSourceSpan): BoundElementPropertyAst[] {
|
||||||
if (hostProps) {
|
if (hostProps) {
|
||||||
const boundProps: BoundProperty[] = [];
|
const boundProps: BoundProperty[] = [];
|
||||||
Object.keys(hostProps).forEach(propName => {
|
Object.keys(hostProps).forEach(propName => {
|
||||||
|
@ -74,30 +70,30 @@ export class BindingParser {
|
||||||
if (typeof expression === 'string') {
|
if (typeof expression === 'string') {
|
||||||
this.parsePropertyBinding(propName, expression, true, sourceSpan, [], boundProps);
|
this.parsePropertyBinding(propName, expression, true, sourceSpan, [], boundProps);
|
||||||
} else {
|
} 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})`,
|
`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
boundProps.forEach(
|
return boundProps.map((prop) => this.createElementPropertyAst(elementName, prop));
|
||||||
(prop) => { targetPropertyAsts.push(this.createElementPropertyAst(elementName, prop)); });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createDirectiveHostEventAsts(
|
createDirectiveHostEventAsts(hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan):
|
||||||
hostListeners: {[key: string]: string}, sourceSpan: ParseSourceSpan,
|
BoundEventAst[] {
|
||||||
targetEventAsts: BoundEventAst[]) {
|
|
||||||
if (hostListeners) {
|
if (hostListeners) {
|
||||||
|
const targetEventAsts: BoundEventAst[] = [];
|
||||||
Object.keys(hostListeners).forEach(propName => {
|
Object.keys(hostListeners).forEach(propName => {
|
||||||
const expression = hostListeners[propName];
|
const expression = hostListeners[propName];
|
||||||
if (typeof expression === 'string') {
|
if (typeof expression === 'string') {
|
||||||
this.parseEvent(propName, expression, sourceSpan, [], targetEventAsts);
|
this.parseEvent(propName, expression, sourceSpan, [], targetEventAsts);
|
||||||
} else {
|
} else {
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return targetEventAsts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +111,7 @@ export class BindingParser {
|
||||||
}
|
}
|
||||||
return ast;
|
return ast;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,10 +146,10 @@ export class BindingParser {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bindingsResult.warnings.forEach(
|
bindingsResult.warnings.forEach(
|
||||||
(warning) => { this.reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
|
(warning) => { this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
|
||||||
return bindingsResult.templateBindings;
|
return bindingsResult.templateBindings;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,8 +159,8 @@ export class BindingParser {
|
||||||
targetProps: BoundProperty[]) {
|
targetProps: BoundProperty[]) {
|
||||||
if (_isAnimationLabel(name)) {
|
if (_isAnimationLabel(name)) {
|
||||||
name = name.substring(1);
|
name = name.substring(1);
|
||||||
if (isPresent(value) && value.length > 0) {
|
if (value) {
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
|
`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.`,
|
` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`,
|
||||||
sourceSpan, ParseErrorLevel.FATAL);
|
sourceSpan, ParseErrorLevel.FATAL);
|
||||||
|
@ -239,7 +235,7 @@ export class BindingParser {
|
||||||
this._checkPipes(ast, sourceSpan);
|
this._checkPipes(ast, sourceSpan);
|
||||||
return ast;
|
return ast;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
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.` +
|
`\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`;
|
`\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 {
|
} else {
|
||||||
if (parts[0] == ATTRIBUTE_PREFIX) {
|
if (parts[0] == ATTRIBUTE_PREFIX) {
|
||||||
|
@ -299,7 +295,7 @@ export class BindingParser {
|
||||||
bindingType = PropertyBindingType.Style;
|
bindingType = PropertyBindingType.Style;
|
||||||
securityContext = SecurityContext.STYLE;
|
securityContext = SecurityContext.STYLE;
|
||||||
} else {
|
} else {
|
||||||
this.reportError(`Invalid property name '${boundProp.name}'`, boundProp.sourceSpan);
|
this._reportError(`Invalid property name '${boundProp.name}'`, boundProp.sourceSpan);
|
||||||
bindingType = null;
|
bindingType = null;
|
||||||
securityContext = null;
|
securityContext = null;
|
||||||
}
|
}
|
||||||
|
@ -336,13 +332,13 @@ export class BindingParser {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`,
|
`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`,
|
`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`,
|
||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
|
@ -369,26 +365,26 @@ export class BindingParser {
|
||||||
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
||||||
}
|
}
|
||||||
if (!ast || ast.ast instanceof EmptyExpr) {
|
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);
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
||||||
}
|
}
|
||||||
this._checkPipes(ast, sourceSpan);
|
this._checkPipes(ast, sourceSpan);
|
||||||
return ast;
|
return ast;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reportError(
|
private _reportError(
|
||||||
message: string, sourceSpan: ParseSourceSpan,
|
message: string, sourceSpan: ParseSourceSpan,
|
||||||
level: ParseErrorLevel = ParseErrorLevel.FATAL) {
|
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) {
|
private _reportExpressionParserErrors(errors: ParserError[], sourceSpan: ParseSourceSpan) {
|
||||||
for (const error of errors) {
|
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);
|
ast.visit(collector);
|
||||||
collector.pipes.forEach((pipeName) => {
|
collector.pipes.forEach((pipeName) => {
|
||||||
if (!this.pipesByName.has(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) :
|
const report = isAttr ? this._schemaRegistry.validateAttribute(propName) :
|
||||||
this._schemaRegistry.validateProperty(propName);
|
this._schemaRegistry.validateProperty(propName);
|
||||||
if (report.error) {
|
if (report.error) {
|
||||||
this.reportError(report.msg, sourceSpan, ParseErrorLevel.FATAL);
|
this._reportError(report.msg, sourceSpan, ParseErrorLevel.FATAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PipeCollector extends RecursiveAstVisitor {
|
export class PipeCollector extends RecursiveAstVisitor {
|
||||||
pipes: Set<string> = new Set<string>();
|
pipes = new Set<string>();
|
||||||
visitPipe(ast: BindingPipe, context: any): any {
|
visitPipe(ast: BindingPipe, context: any): any {
|
||||||
this.pipes.add(ast.name);
|
this.pipes.add(ast.name);
|
||||||
ast.exp.visit(this);
|
ast.exp.visit(this);
|
||||||
|
|
|
@ -136,11 +136,13 @@ export class TemplateParser {
|
||||||
end: component.template.interpolation[1]
|
end: component.template.interpolation[1]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const bindingParser = new BindingParser(
|
||||||
|
this._exprParser, interpolationConfig, this._schemaRegistry, schemas, uniqPipes, errors);
|
||||||
const parseVisitor = new TemplateParseVisitor(
|
const parseVisitor = new TemplateParseVisitor(
|
||||||
providerViewContext, uniqDirectives, uniqPipes, this._exprParser, interpolationConfig,
|
providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas,
|
||||||
this._schemaRegistry, schemas);
|
errors);
|
||||||
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
||||||
errors.push(...parseVisitor.errors, ...providerViewContext.errors);
|
errors.push(...providerViewContext.errors);
|
||||||
} else {
|
} else {
|
||||||
result = [];
|
result = [];
|
||||||
}
|
}
|
||||||
|
@ -196,18 +198,15 @@ export class TemplateParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
class TemplateParseVisitor implements html.Visitor {
|
||||||
selectorMatcher = new SelectorMatcher();
|
selectorMatcher = new SelectorMatcher();
|
||||||
errors: TemplateParseError[] = [];
|
|
||||||
directivesIndex = new Map<CompileDirectiveMetadata, number>();
|
directivesIndex = new Map<CompileDirectiveMetadata, number>();
|
||||||
ngContentCount: number = 0;
|
ngContentCount: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public providerViewContext: ProviderViewContext, directives: CompileDirectiveMetadata[],
|
public providerViewContext: ProviderViewContext, directives: CompileDirectiveMetadata[],
|
||||||
pipes: CompilePipeMetadata[], _exprParser: Parser, interpolationConfig: InterpolationConfig,
|
private _bindingParser: BindingParser, private _schemaRegistry: ElementSchemaRegistry,
|
||||||
_schemaRegistry: ElementSchemaRegistry, schemas: SchemaMetadata[]) {
|
private _schemas: SchemaMetadata[], private _targetErrors: TemplateParseError[]) {
|
||||||
super(_exprParser, interpolationConfig, _schemaRegistry, schemas, pipes);
|
|
||||||
|
|
||||||
directives.forEach((directive: CompileDirectiveMetadata, index: number) => {
|
directives.forEach((directive: CompileDirectiveMetadata, index: number) => {
|
||||||
const selector = CssSelector.parse(directive.selector);
|
const selector = CssSelector.parse(directive.selector);
|
||||||
this.selectorMatcher.addSelectables(selector, directive);
|
this.selectorMatcher.addSelectables(selector, directive);
|
||||||
|
@ -221,7 +220,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
|
|
||||||
visitText(text: html.Text, parent: ElementContext): any {
|
visitText(text: html.Text, parent: ElementContext): any {
|
||||||
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR);
|
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)) {
|
if (isPresent(expr)) {
|
||||||
return new BoundTextAst(expr, ngContentIndex, text.sourceSpan);
|
return new BoundTextAst(expr, ngContentIndex, text.sourceSpan);
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,12 +281,12 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
const hasTemplateBinding = isPresent(templateBindingsSource);
|
const hasTemplateBinding = isPresent(templateBindingsSource);
|
||||||
if (hasTemplateBinding) {
|
if (hasTemplateBinding) {
|
||||||
if (hasInlineTemplates) {
|
if (hasInlineTemplates) {
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *`,
|
`Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *`,
|
||||||
attr.sourceSpan);
|
attr.sourceSpan);
|
||||||
}
|
}
|
||||||
hasInlineTemplates = true;
|
hasInlineTemplates = true;
|
||||||
this.parseInlineTemplateBinding(
|
this._bindingParser.parseInlineTemplateBinding(
|
||||||
attr.name, templateBindingsSource, attr.sourceSpan, templateMatchableAttrs,
|
attr.name, templateBindingsSource, attr.sourceSpan, templateMatchableAttrs,
|
||||||
templateElementOrDirectiveProps, templateElementVars);
|
templateElementOrDirectiveProps, templateElementVars);
|
||||||
}
|
}
|
||||||
|
@ -327,7 +326,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
|
|
||||||
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
|
||||||
if (element.children && !element.children.every(_isEmptyTextNode)) {
|
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(
|
parsedElement = new NgContentAst(
|
||||||
|
@ -400,7 +399,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
animationInputs.forEach(input => {
|
animationInputs.forEach(input => {
|
||||||
const name = input.name;
|
const name = input.name;
|
||||||
if (!triggerLookup.has(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) {
|
if (output.isAnimation) {
|
||||||
const found = animationInputs.find(input => input.name == output.name);
|
const found = animationInputs.find(input => input.name == output.name);
|
||||||
if (!found) {
|
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`,
|
`Unable to listen on (@${output.name}.${output.phase}) because the animation trigger [@${output.name}] isn't being used on the same element`,
|
||||||
output.sourceSpan);
|
output.sourceSpan);
|
||||||
}
|
}
|
||||||
|
@ -430,7 +429,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
if (bindParts !== null) {
|
if (bindParts !== null) {
|
||||||
hasBinding = true;
|
hasBinding = true;
|
||||||
if (isPresent(bindParts[KW_BIND_IDX])) {
|
if (isPresent(bindParts[KW_BIND_IDX])) {
|
||||||
this.parsePropertyBinding(
|
this._bindingParser.parsePropertyBinding(
|
||||||
bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps);
|
bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps);
|
||||||
|
|
||||||
} else if (bindParts[KW_LET_IDX]) {
|
} else if (bindParts[KW_LET_IDX]) {
|
||||||
|
@ -438,7 +437,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
const identifier = bindParts[IDENT_KW_IDX];
|
const identifier = bindParts[IDENT_KW_IDX];
|
||||||
this._parseVariable(identifier, value, srcSpan, targetVars);
|
this._parseVariable(identifier, value, srcSpan, targetVars);
|
||||||
} else {
|
} 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]) {
|
} else if (bindParts[KW_REF_IDX]) {
|
||||||
|
@ -446,41 +445,42 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
this._parseReference(identifier, value, srcSpan, targetRefs);
|
this._parseReference(identifier, value, srcSpan, targetRefs);
|
||||||
|
|
||||||
} else if (bindParts[KW_ON_IDX]) {
|
} else if (bindParts[KW_ON_IDX]) {
|
||||||
this.parseEvent(
|
this._bindingParser.parseEvent(
|
||||||
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
|
|
||||||
} else if (bindParts[KW_BINDON_IDX]) {
|
} else if (bindParts[KW_BINDON_IDX]) {
|
||||||
this.parsePropertyBinding(
|
this._bindingParser.parsePropertyBinding(
|
||||||
bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps);
|
bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps);
|
||||||
this._parseAssignmentEvent(
|
this._parseAssignmentEvent(
|
||||||
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
|
|
||||||
} else if (bindParts[KW_AT_IDX]) {
|
} 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]) {
|
} else if (bindParts[IDENT_BANANA_BOX_IDX]) {
|
||||||
this.parsePropertyBinding(
|
this._bindingParser.parsePropertyBinding(
|
||||||
bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, targetMatchableAttrs,
|
bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, targetMatchableAttrs,
|
||||||
targetProps);
|
targetProps);
|
||||||
this._parseAssignmentEvent(
|
this._parseAssignmentEvent(
|
||||||
bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
|
|
||||||
} else if (bindParts[IDENT_PROPERTY_IDX]) {
|
} else if (bindParts[IDENT_PROPERTY_IDX]) {
|
||||||
this.parsePropertyBinding(
|
this._bindingParser.parsePropertyBinding(
|
||||||
bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, targetMatchableAttrs,
|
bindParts[IDENT_PROPERTY_IDX], value, false, srcSpan, targetMatchableAttrs,
|
||||||
targetProps);
|
targetProps);
|
||||||
|
|
||||||
} else if (bindParts[IDENT_EVENT_IDX]) {
|
} else if (bindParts[IDENT_EVENT_IDX]) {
|
||||||
this.parseEvent(
|
this._bindingParser.parseEvent(
|
||||||
bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, targetEvents);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hasBinding =
|
hasBinding = this._bindingParser.parsePropertyInterpolation(
|
||||||
this.parsePropertyInterpolation(name, value, srcSpan, targetMatchableAttrs, targetProps);
|
name, value, srcSpan, targetMatchableAttrs, targetProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasBinding) {
|
if (!hasBinding) {
|
||||||
this.parseLiteralAttr(name, value, srcSpan, targetMatchableAttrs, targetProps);
|
this._bindingParser.parseLiteralAttr(name, value, srcSpan, targetMatchableAttrs, targetProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasBinding;
|
return hasBinding;
|
||||||
|
@ -493,7 +493,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
private _parseVariable(
|
private _parseVariable(
|
||||||
identifier: string, value: string, sourceSpan: ParseSourceSpan, targetVars: VariableAst[]) {
|
identifier: string, value: string, sourceSpan: ParseSourceSpan, targetVars: VariableAst[]) {
|
||||||
if (identifier.indexOf('-') > -1) {
|
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));
|
targetVars.push(new VariableAst(identifier, value, sourceSpan));
|
||||||
|
@ -503,7 +503,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
identifier: string, value: string, sourceSpan: ParseSourceSpan,
|
identifier: string, value: string, sourceSpan: ParseSourceSpan,
|
||||||
targetRefs: ElementOrDirectiveRef[]) {
|
targetRefs: ElementOrDirectiveRef[]) {
|
||||||
if (identifier.indexOf('-') > -1) {
|
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));
|
targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
|
||||||
|
@ -512,7 +512,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
private _parseAssignmentEvent(
|
private _parseAssignmentEvent(
|
||||||
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
name: string, expression: string, sourceSpan: ParseSourceSpan,
|
||||||
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
targetMatchableAttrs: string[][], targetEvents: BoundEventAst[]) {
|
||||||
this.parseEvent(
|
this._bindingParser.parseEvent(
|
||||||
`${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, targetEvents);
|
`${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, targetEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,12 +548,11 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
if (directive.isComponent) {
|
if (directive.isComponent) {
|
||||||
component = directive;
|
component = directive;
|
||||||
}
|
}
|
||||||
const hostProperties: BoundElementPropertyAst[] = [];
|
|
||||||
const hostEvents: BoundEventAst[] = [];
|
|
||||||
const directiveProperties: BoundDirectivePropertyAst[] = [];
|
const directiveProperties: BoundDirectivePropertyAst[] = [];
|
||||||
this.createDirectiveHostPropertyAsts(
|
const hostProperties = this._bindingParser.createDirectiveHostPropertyAsts(
|
||||||
elementName, directive.hostProperties, sourceSpan, hostProperties);
|
elementName, directive.hostProperties, sourceSpan);
|
||||||
this.createDirectiveHostEventAsts(directive.hostListeners, sourceSpan, hostEvents);
|
const hostEvents =
|
||||||
|
this._bindingParser.createDirectiveHostEventAsts(directive.hostListeners, sourceSpan);
|
||||||
this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties);
|
this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties);
|
||||||
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
||||||
if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
|
if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
|
||||||
|
@ -569,7 +568,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
||||||
if (elOrDirRef.value.length > 0) {
|
if (elOrDirRef.value.length > 0) {
|
||||||
if (!matchedReferences.has(elOrDirRef.name)) {
|
if (!matchedReferences.has(elOrDirRef.name)) {
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`There is no directive with "exportAs" set to "${elOrDirRef.value}"`,
|
`There is no directive with "exportAs" set to "${elOrDirRef.value}"`,
|
||||||
elOrDirRef.sourceSpan);
|
elOrDirRef.sourceSpan);
|
||||||
}
|
}
|
||||||
|
@ -624,7 +623,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
|
|
||||||
props.forEach((prop: BoundProperty) => {
|
props.forEach((prop: BoundProperty) => {
|
||||||
if (!prop.isLiteral && !boundDirectivePropsIndex.get(prop.name)) {
|
if (!prop.isLiteral && !boundDirectivePropsIndex.get(prop.name)) {
|
||||||
boundElementProps.push(this.createElementPropertyAst(elementName, prop));
|
boundElementProps.push(this._bindingParser.createElementPropertyAst(elementName, prop));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return boundElementProps;
|
return boundElementProps;
|
||||||
|
@ -642,7 +641,7 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) {
|
private _assertOnlyOneComponent(directives: DirectiveAst[], sourceSpan: ParseSourceSpan) {
|
||||||
const componentTypeNames = this._findComponentDirectiveNames(directives);
|
const componentTypeNames = this._findComponentDirectiveNames(directives);
|
||||||
if (componentTypeNames.length > 1) {
|
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` +
|
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` +
|
`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.`;
|
`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) {
|
sourceSpan: ParseSourceSpan) {
|
||||||
const componentTypeNames: string[] = this._findComponentDirectiveNames(directives);
|
const componentTypeNames: string[] = this._findComponentDirectiveNames(directives);
|
||||||
if (componentTypeNames.length > 0) {
|
if (componentTypeNames.length > 0) {
|
||||||
this.reportError(
|
this._reportError(
|
||||||
`Components on an embedded template: ${componentTypeNames.join(',')}`, sourceSpan);
|
`Components on an embedded template: ${componentTypeNames.join(',')}`, sourceSpan);
|
||||||
}
|
}
|
||||||
elementProps.forEach(prop => {
|
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.`,
|
`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);
|
sourceSpan);
|
||||||
});
|
});
|
||||||
|
@ -694,12 +693,18 @@ class TemplateParseVisitor extends BindingParser implements html.Visitor {
|
||||||
|
|
||||||
events.forEach(event => {
|
events.forEach(event => {
|
||||||
if (isPresent(event.target) || !allDirectiveEvents.has(event.name)) {
|
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 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);
|
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 {
|
class NonBindableVisitor implements html.Visitor {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||||
import {createSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
|
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 {isPresent} from '../facade/lang';
|
||||||
import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
|
import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
|
||||||
import {createClassStmt} from '../output/class_builder';
|
import {createClassStmt} from '../output/class_builder';
|
||||||
|
@ -167,7 +167,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
'createTemplateAnchor', [this._getParentRenderNode(parent), debugContextExpr]);
|
'createTemplateAnchor', [this._getParentRenderNode(parent), debugContextExpr]);
|
||||||
} else {
|
} else {
|
||||||
const htmlAttrs = _readHtmlAttrs(ast.attrs);
|
const htmlAttrs = _readHtmlAttrs(ast.attrs);
|
||||||
const attrNameAndValues = createFastArray(
|
const attrNameAndValues = createInlineArray(
|
||||||
_mergeHtmlAndDirectiveAttrs(htmlAttrs, directives).map(v => o.literal(v)));
|
_mergeHtmlAndDirectiveAttrs(htmlAttrs, directives).map(v => o.literal(v)));
|
||||||
if (nodeIndex === 0 && this.view.viewType === ViewType.HOST) {
|
if (nodeIndex === 0 && this.view.viewType === ViewType.HOST) {
|
||||||
createRenderNodeExpr =
|
createRenderNodeExpr =
|
||||||
|
|
|
@ -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); });
|
||||||
|
});
|
||||||
|
}
|
|
@ -379,7 +379,7 @@ function camelCaseToDashCase(input: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRenderElement(
|
export function createRenderElement(
|
||||||
renderer: Renderer, parentElement: any, name: string, attrs: FastArray<string>,
|
renderer: Renderer, parentElement: any, name: string, attrs: InlineArray<string>,
|
||||||
debugInfo?: RenderDebugInfo): any {
|
debugInfo?: RenderDebugInfo): any {
|
||||||
const el = renderer.createElement(parentElement, name, debugInfo);
|
const el = renderer.createElement(parentElement, name, debugInfo);
|
||||||
for (var i = 0; i < attrs.length; i += 2) {
|
for (var i = 0; i < attrs.length; i += 2) {
|
||||||
|
@ -389,8 +389,8 @@ export function createRenderElement(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectOrCreateRenderHostElement(
|
export function selectOrCreateRenderHostElement(
|
||||||
renderer: Renderer, elementName: string, attrs: FastArray<string>,
|
renderer: Renderer, elementName: string, attrs: InlineArray<string>,
|
||||||
rootSelectorOrNode: string | any, debugInfo: RenderDebugInfo): any {
|
rootSelectorOrNode: string | any, debugInfo?: RenderDebugInfo): any {
|
||||||
var hostElement: any;
|
var hostElement: any;
|
||||||
if (isPresent(rootSelectorOrNode)) {
|
if (isPresent(rootSelectorOrNode)) {
|
||||||
hostElement = renderer.selectRootElement(rootSelectorOrNode, debugInfo);
|
hostElement = renderer.selectRootElement(rootSelectorOrNode, debugInfo);
|
||||||
|
@ -400,17 +400,17 @@ export function selectOrCreateRenderHostElement(
|
||||||
return hostElement;
|
return hostElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FastArray<T> {
|
export interface InlineArray<T> {
|
||||||
length: number;
|
length: number;
|
||||||
get(index: number): T;
|
get(index: number): T;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FastArray0 implements FastArray<any> {
|
class InlineArray0 implements InlineArray<any> {
|
||||||
length = 0;
|
length = 0;
|
||||||
get(index: number): any { return undefined; }
|
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) {}
|
constructor(public length: number, private _v0: T, private _v1: T) {}
|
||||||
get(index: number) {
|
get(index: number) {
|
||||||
switch (index) {
|
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(
|
constructor(
|
||||||
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T) {}
|
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T) {}
|
||||||
get(index: number) {
|
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(
|
constructor(
|
||||||
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T,
|
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 _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(
|
constructor(
|
||||||
public length: number, private _v0: T, private _v1: T, private _v2: T, private _v3: T,
|
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,
|
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[];
|
private _values: any[];
|
||||||
// Note: We still take the length argument so this class can be created
|
// Note: We still take the length argument so this class can be created
|
||||||
// in the same ways as the other classes!
|
// 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]; }
|
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();
|
||||||
|
|
|
@ -34,7 +34,7 @@ class _View_TreeComponent_Host0 extends import1.AppView<any> {
|
||||||
}
|
}
|
||||||
createInternal(rootSelector: string): import2.AppElement {
|
createInternal(rootSelector: string): import2.AppElement {
|
||||||
this._el_0 = import4.selectOrCreateRenderHostElement(
|
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._vc_0 = new import2.AppElement(0, (null as any), this, this._el_0);
|
||||||
this._TreeComponent_0_4 = new _View_TreeComponent0(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);
|
this._vc_0.initComponent(this._TreeComponent_0_4.context, [], <any>this._TreeComponent_0_4);
|
||||||
|
|
|
@ -36,7 +36,7 @@ class _View_TreeRootComponent_Host0 extends import1.AppView<any> {
|
||||||
}
|
}
|
||||||
createInternal(rootSelector: string): import2.AppElement {
|
createInternal(rootSelector: string): import2.AppElement {
|
||||||
this._el_0 = import4.selectOrCreateRenderHostElement(
|
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);
|
this._appEl_0 = new import2.AppElement(0, (null as any), this, this._el_0);
|
||||||
var compView_0: any =
|
var compView_0: any =
|
||||||
viewFactory_TreeRootComponent0(this.viewUtils, this.injector(0), this._appEl_0);
|
viewFactory_TreeRootComponent0(this.viewUtils, this.injector(0), this._appEl_0);
|
||||||
|
|
Loading…
Reference in New Issue