@angular/compiler
Version:
Angular - the compiler library
862 lines • 151 kB
JavaScript
/**
* @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 { rendererTypeName, tokenReference, viewClassName } from '../compile_metadata';
import { BindingForm, EventHandlerVars, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins } from '../compiler_util/expression_converter';
import { ChangeDetectionStrategy } from '../core';
import { Identifiers } from '../identifiers';
import { LifecycleHooks } from '../lifecycle_reflector';
import { isNgContainer } from '../ml_parser/tags';
import * as o from '../output/output_ast';
import { convertValueToOutputAst } from '../output/value_util';
import { ElementAst, EmbeddedTemplateAst, NgContentAst, templateVisitAll } from '../template_parser/template_ast';
import { componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, providerDef } from './provider_compiler';
const CLASS_ATTR = 'class';
const STYLE_ATTR = 'style';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
export class ViewCompileResult {
constructor(viewClassVar, rendererTypeVar) {
this.viewClassVar = viewClassVar;
this.rendererTypeVar = rendererTypeVar;
}
}
export class ViewCompiler {
constructor(_reflector) {
this._reflector = _reflector;
}
compileComponent(outputCtx, component, template, styles, usedPipes) {
let embeddedViewCount = 0;
const staticQueryIds = findStaticQueryIds(template);
let renderComponentVarName = undefined;
if (!component.isHost) {
const template = component.template;
const customRenderData = [];
if (template.animations && template.animations.length) {
customRenderData.push(new o.LiteralMapEntry('animation', convertValueToOutputAst(outputCtx, template.animations), true));
}
const renderComponentVar = o.variable(rendererTypeName(component.type.reference));
renderComponentVarName = renderComponentVar.name;
outputCtx.statements.push(renderComponentVar
.set(o.importExpr(Identifiers.createRendererType2).callFn([new o.LiteralMapExpr([
new o.LiteralMapEntry('encapsulation', o.literal(template.encapsulation), false),
new o.LiteralMapEntry('styles', styles, false),
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData), false)
])]))
.toDeclStmt(o.importType(Identifiers.RendererType2), [o.StmtModifier.Final, o.StmtModifier.Exported]));
}
const viewBuilderFactory = (parent) => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(this._reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, staticQueryIds, viewBuilderFactory);
};
const visitor = viewBuilderFactory(null);
visitor.visitAll([], template);
outputCtx.statements.push(...visitor.build());
return new ViewCompileResult(visitor.viewName, renderComponentVarName);
}
}
const LOG_VAR = o.variable('_l');
const VIEW_VAR = o.variable('_v');
const CHECK_VAR = o.variable('_ck');
const COMP_VAR = o.variable('_co');
const EVENT_NAME_VAR = o.variable('en');
const ALLOW_DEFAULT_VAR = o.variable(`ad`);
class ViewBuilder {
constructor(reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, staticQueryIds, viewBuilderFactory) {
this.reflector = reflector;
this.outputCtx = outputCtx;
this.parent = parent;
this.component = component;
this.embeddedViewIndex = embeddedViewIndex;
this.usedPipes = usedPipes;
this.staticQueryIds = staticQueryIds;
this.viewBuilderFactory = viewBuilderFactory;
this.nodes = [];
this.purePipeNodeIndices = Object.create(null);
// Need Object.create so that we don't have builtin values...
this.refNodeIndices = Object.create(null);
this.variables = [];
this.children = [];
// TODO(tbosch): The old view compiler used to use an `any` type
// for the context in any embedded view. We keep this behaivor for now
// to be able to introduce the new view compiler without too many errors.
this.compType = this.embeddedViewIndex > 0 ?
o.DYNAMIC_TYPE :
o.expressionType(outputCtx.importExpr(this.component.type.reference));
this.viewName = viewClassName(this.component.type.reference, this.embeddedViewIndex);
}
visitAll(variables, astNodes) {
this.variables = variables;
// create the pipes for the pure pipes immediately, so that we know their indices.
if (!this.parent) {
this.usedPipes.forEach((pipe) => {
if (pipe.pure) {
this.purePipeNodeIndices[pipe.name] = this._createPipe(null, pipe);
}
});
}
if (!this.parent) {
const queryIds = staticViewQueryIds(this.staticQueryIds);
this.component.viewQueries.forEach((query, queryIndex) => {
// Note: queries start with id 1 so we can use the number in a Bloom filter!
const queryId = queryIndex + 1;
const bindingType = query.first ? 0 /* First */ : 1 /* All */;
const flags = 134217728 /* TypeViewQuery */ | calcStaticDynamicQueryFlags(queryIds, queryId, query.first);
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: flags,
nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr([new o.LiteralMapEntry(query.propertyName, o.literal(bindingType), false)])
])
}));
});
}
templateVisitAll(this, astNodes);
if (this.parent && (astNodes.length === 0 || needsAdditionalRootNode(astNodes))) {
// if the view is an embedded view, then we need to add an additional root node in some cases
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: 1 /* TypeElement */,
nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(0 /* None */), o.NULL_EXPR, o.NULL_EXPR, o.literal(0)
])
}));
}
}
build(targetStatements = []) {
this.children.forEach((child) => child.build(targetStatements));
const { updateRendererStmts, updateDirectivesStmts, nodeDefExprs } = this._createNodeExpressions();
const updateRendererFn = this._createUpdateFn(updateRendererStmts);
const updateDirectivesFn = this._createUpdateFn(updateDirectivesStmts);
let viewFlags = 0 /* None */;
if (!this.parent && this.component.changeDetection === ChangeDetectionStrategy.OnPush) {
viewFlags |= 2 /* OnPush */;
}
const viewFactory = new o.DeclareFunctionStmt(this.viewName, [new o.FnParam(LOG_VAR.name)], [new o.ReturnStatement(o.importExpr(Identifiers.viewDef).callFn([
o.literal(viewFlags),
o.literalArr(nodeDefExprs),
updateDirectivesFn,
updateRendererFn,
]))], o.importType(Identifiers.ViewDefinition), this.embeddedViewIndex === 0 ? [o.StmtModifier.Exported] : []);
targetStatements.push(viewFactory);
return targetStatements;
}
_createUpdateFn(updateStmts) {
let updateFn;
if (updateStmts.length > 0) {
const preStmts = [];
if (!this.component.isHost && o.findReadVarNames(updateStmts).has(COMP_VAR.name)) {
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
}
updateFn = o.fn([
new o.FnParam(CHECK_VAR.name, o.INFERRED_TYPE),
new o.FnParam(VIEW_VAR.name, o.INFERRED_TYPE)
], [...preStmts, ...updateStmts], o.INFERRED_TYPE);
}
else {
updateFn = o.NULL_EXPR;
}
return updateFn;
}
visitNgContent(ast, context) {
// ngContentDef(ngContentIndex: number, index: number): NodeDef;
this.nodes.push(() => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 8 /* TypeNgContent */,
nodeDef: o.importExpr(Identifiers.ngContentDef).callFn([
o.literal(ast.ngContentIndex), o.literal(ast.index)
])
}));
}
visitText(ast, context) {
// Static text nodes have no check function
const checkIndex = -1;
this.nodes.push(() => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 2 /* TypeText */,
nodeDef: o.importExpr(Identifiers.textDef).callFn([
o.literal(checkIndex),
o.literal(ast.ngContentIndex),
o.literalArr([o.literal(ast.value)]),
])
}));
}
visitBoundText(ast, context) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array
this.nodes.push(null);
const astWithSource = ast.value;
const inter = astWithSource.ast;
const updateRendererExpressions = inter.expressions.map((expr, bindingIndex) => this._preprocessUpdateExpression({ nodeIndex, bindingIndex, sourceSpan: ast.sourceSpan, context: COMP_VAR, value: expr }));
// Check index is the same as the node index during compilation
// They might only differ at runtime
const checkIndex = nodeIndex;
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 2 /* TypeText */,
nodeDef: o.importExpr(Identifiers.textDef).callFn([
o.literal(checkIndex),
o.literal(ast.ngContentIndex),
o.literalArr(inter.strings.map(s => o.literal(s))),
]),
updateRenderer: updateRendererExpressions
});
}
visitEmbeddedTemplate(ast, context) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array
this.nodes.push(null);
const { flags, queryMatchesExpr, hostEvents } = this._visitElementOrTemplate(nodeIndex, ast);
const childVisitor = this.viewBuilderFactory(this);
this.children.push(childVisitor);
childVisitor.visitAll(ast.variables, ast.children);
const childCount = this.nodes.length - nodeIndex - 1;
// anchorDef(
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
// childCount: number, handleEventFn?: ElementHandleEventFn, templateFactory?:
// ViewDefinitionFactory): NodeDef;
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 1 /* TypeElement */ | flags,
nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(flags),
queryMatchesExpr,
o.literal(ast.ngContentIndex),
o.literal(childCount),
this._createElementHandleEventFn(nodeIndex, hostEvents),
o.variable(childVisitor.viewName),
])
});
}
visitElement(ast, context) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array so we can add children
this.nodes.push(null);
// Using a null element name creates an anchor.
const elName = isNgContainer(ast.name) ? null : ast.name;
const { flags, usedEvents, queryMatchesExpr, hostBindings: dirHostBindings, hostEvents } = this._visitElementOrTemplate(nodeIndex, ast);
let inputDefs = [];
let updateRendererExpressions = [];
let outputDefs = [];
if (elName) {
const hostBindings = ast.inputs
.map((inputAst) => ({
context: COMP_VAR,
inputAst,
dirAst: null,
}))
.concat(dirHostBindings);
if (hostBindings.length) {
updateRendererExpressions =
hostBindings.map((hostBinding, bindingIndex) => this._preprocessUpdateExpression({
context: hostBinding.context,
nodeIndex,
bindingIndex,
sourceSpan: hostBinding.inputAst.sourceSpan,
value: hostBinding.inputAst.value
}));
inputDefs = hostBindings.map(hostBinding => elementBindingDef(hostBinding.inputAst, hostBinding.dirAst));
}
outputDefs = usedEvents.map(([target, eventName]) => o.literalArr([o.literal(target), o.literal(eventName)]));
}
templateVisitAll(this, ast.children);
const childCount = this.nodes.length - nodeIndex - 1;
const compAst = ast.directives.find(dirAst => dirAst.directive.isComponent);
let compRendererType = o.NULL_EXPR;
let compView = o.NULL_EXPR;
if (compAst) {
compView = this.outputCtx.importExpr(compAst.directive.componentViewType);
compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType);
}
// Check index is the same as the node index during compilation
// They might only differ at runtime
const checkIndex = nodeIndex;
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 1 /* TypeElement */ | flags,
nodeDef: o.importExpr(Identifiers.elementDef).callFn([
o.literal(checkIndex),
o.literal(flags),
queryMatchesExpr,
o.literal(ast.ngContentIndex),
o.literal(childCount),
o.literal(elName),
elName ? fixedAttrsDef(ast) : o.NULL_EXPR,
inputDefs.length ? o.literalArr(inputDefs) : o.NULL_EXPR,
outputDefs.length ? o.literalArr(outputDefs) : o.NULL_EXPR,
this._createElementHandleEventFn(nodeIndex, hostEvents),
compView,
compRendererType,
]),
updateRenderer: updateRendererExpressions
});
}
_visitElementOrTemplate(nodeIndex, ast) {
let flags = 0 /* None */;
if (ast.hasViewContainer) {
flags |= 16777216 /* EmbeddedViews */;
}
const usedEvents = new Map();
ast.outputs.forEach((event) => {
const { name, target } = elementEventNameAndTarget(event, null);
usedEvents.set(elementEventFullName(target, name), [target, name]);
});
ast.directives.forEach((dirAst) => {
dirAst.hostEvents.forEach((event) => {
const { name, target } = elementEventNameAndTarget(event, dirAst);
usedEvents.set(elementEventFullName(target, name), [target, name]);
});
});
const hostBindings = [];
const hostEvents = [];
this._visitComponentFactoryResolverProvider(ast.directives);
ast.providers.forEach((providerAst, providerIndex) => {
let dirAst = undefined;
let dirIndex = undefined;
ast.directives.forEach((localDirAst, i) => {
if (localDirAst.directive.type.reference === tokenReference(providerAst.token)) {
dirAst = localDirAst;
dirIndex = i;
}
});
if (dirAst) {
const { hostBindings: dirHostBindings, hostEvents: dirHostEvents } = this._visitDirective(providerAst, dirAst, dirIndex, nodeIndex, ast.references, ast.queryMatches, usedEvents, this.staticQueryIds.get(ast));
hostBindings.push(...dirHostBindings);
hostEvents.push(...dirHostEvents);
}
else {
this._visitProvider(providerAst, ast.queryMatches);
}
});
let queryMatchExprs = [];
ast.queryMatches.forEach((match) => {
let valueType = undefined;
if (tokenReference(match.value) ===
this.reflector.resolveExternalReference(Identifiers.ElementRef)) {
valueType = 0 /* ElementRef */;
}
else if (tokenReference(match.value) ===
this.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
valueType = 3 /* ViewContainerRef */;
}
else if (tokenReference(match.value) ===
this.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
valueType = 2 /* TemplateRef */;
}
if (valueType != null) {
queryMatchExprs.push(o.literalArr([o.literal(match.queryId), o.literal(valueType)]));
}
});
ast.references.forEach((ref) => {
let valueType = undefined;
if (!ref.value) {
valueType = 1 /* RenderElement */;
}
else if (tokenReference(ref.value) ===
this.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
valueType = 2 /* TemplateRef */;
}
if (valueType != null) {
this.refNodeIndices[ref.name] = nodeIndex;
queryMatchExprs.push(o.literalArr([o.literal(ref.name), o.literal(valueType)]));
}
});
ast.outputs.forEach((outputAst) => {
hostEvents.push({ context: COMP_VAR, eventAst: outputAst, dirAst: null });
});
return {
flags,
usedEvents: Array.from(usedEvents.values()),
queryMatchesExpr: queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR,
hostBindings,
hostEvents: hostEvents
};
}
_visitDirective(providerAst, dirAst, directiveIndex, elementNodeIndex, refs, queryMatches, usedEvents, queryIds) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array so we can add children
this.nodes.push(null);
dirAst.directive.queries.forEach((query, queryIndex) => {
const queryId = dirAst.contentQueryStartId + queryIndex;
const flags = 67108864 /* TypeContentQuery */ | calcStaticDynamicQueryFlags(queryIds, queryId, query.first);
const bindingType = query.first ? 0 /* First */ : 1 /* All */;
this.nodes.push(() => ({
sourceSpan: dirAst.sourceSpan,
nodeFlags: flags,
nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr([new o.LiteralMapEntry(query.propertyName, o.literal(bindingType), false)])
]),
}));
});
// Note: the operation below might also create new nodeDefs,
// but we don't want them to be a child of a directive,
// as they might be a provider/pipe on their own.
// I.e. we only allow queries as children of directives nodes.
const childCount = this.nodes.length - nodeIndex - 1;
let { flags, queryMatchExprs, providerExpr, depsExpr } = this._visitProviderOrDirective(providerAst, queryMatches);
refs.forEach((ref) => {
if (ref.value && tokenReference(ref.value) === tokenReference(providerAst.token)) {
this.refNodeIndices[ref.name] = nodeIndex;
queryMatchExprs.push(o.literalArr([o.literal(ref.name), o.literal(4 /* Provider */)]));
}
});
if (dirAst.directive.isComponent) {
flags |= 32768 /* Component */;
}
const inputDefs = dirAst.inputs.map((inputAst, inputIndex) => {
const mapValue = o.literalArr([o.literal(inputIndex), o.literal(inputAst.directiveName)]);
// Note: it's important to not quote the key so that we can capture renames by minifiers!
return new o.LiteralMapEntry(inputAst.directiveName, mapValue, false);
});
const outputDefs = [];
const dirMeta = dirAst.directive;
Object.keys(dirMeta.outputs).forEach((propName) => {
const eventName = dirMeta.outputs[propName];
if (usedEvents.has(eventName)) {
// Note: it's important to not quote the key so that we can capture renames by minifiers!
outputDefs.push(new o.LiteralMapEntry(propName, o.literal(eventName), false));
}
});
let updateDirectiveExpressions = [];
if (dirAst.inputs.length || (flags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0) {
updateDirectiveExpressions =
dirAst.inputs.map((input, bindingIndex) => this._preprocessUpdateExpression({
nodeIndex,
bindingIndex,
sourceSpan: input.sourceSpan,
context: COMP_VAR,
value: input.value
}));
}
const dirContextExpr = o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
const hostBindings = dirAst.hostProperties.map((inputAst) => ({
context: dirContextExpr,
dirAst,
inputAst,
}));
const hostEvents = dirAst.hostEvents.map((hostEventAst) => ({
context: dirContextExpr,
eventAst: hostEventAst, dirAst,
}));
// Check index is the same as the node index during compilation
// They might only differ at runtime
const checkIndex = nodeIndex;
this.nodes[nodeIndex] = () => ({
sourceSpan: dirAst.sourceSpan,
nodeFlags: 16384 /* TypeDirective */ | flags,
nodeDef: o.importExpr(Identifiers.directiveDef).callFn([
o.literal(checkIndex),
o.literal(flags),
queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR,
o.literal(childCount),
providerExpr,
depsExpr,
inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR,
outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR,
]),
updateDirectives: updateDirectiveExpressions,
directive: dirAst.directive.type,
});
return { hostBindings, hostEvents };
}
_visitProvider(providerAst, queryMatches) {
this._addProviderNode(this._visitProviderOrDirective(providerAst, queryMatches));
}
_visitComponentFactoryResolverProvider(directives) {
const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent);
if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
const { providerExpr, depsExpr, flags, tokenExpr } = componentFactoryResolverProviderDef(this.reflector, this.outputCtx, 8192 /* PrivateProvider */, componentDirMeta.directive.entryComponents);
this._addProviderNode({
providerExpr,
depsExpr,
flags,
tokenExpr,
queryMatchExprs: [],
sourceSpan: componentDirMeta.sourceSpan
});
}
}
_addProviderNode(data) {
const nodeIndex = this.nodes.length;
// providerDef(
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], token:any,
// value: any, deps: ([DepFlags, any] | any)[]): NodeDef;
this.nodes.push(() => ({
sourceSpan: data.sourceSpan,
nodeFlags: data.flags,
nodeDef: o.importExpr(Identifiers.providerDef).callFn([
o.literal(data.flags),
data.queryMatchExprs.length ? o.literalArr(data.queryMatchExprs) : o.NULL_EXPR,
data.tokenExpr, data.providerExpr, data.depsExpr
])
}));
}
_visitProviderOrDirective(providerAst, queryMatches) {
let flags = 0 /* None */;
let queryMatchExprs = [];
queryMatches.forEach((match) => {
if (tokenReference(match.value) === tokenReference(providerAst.token)) {
queryMatchExprs.push(o.literalArr([o.literal(match.queryId), o.literal(4 /* Provider */)]));
}
});
const { providerExpr, depsExpr, flags: providerFlags, tokenExpr } = providerDef(this.outputCtx, providerAst);
return {
flags: flags | providerFlags,
queryMatchExprs,
providerExpr,
depsExpr,
tokenExpr,
sourceSpan: providerAst.sourceSpan
};
}
getLocal(name) {
if (name == EventHandlerVars.event.name) {
return EventHandlerVars.event;
}
let currViewExpr = VIEW_VAR;
for (let currBuilder = this; currBuilder; currBuilder = currBuilder.parent,
currViewExpr = currViewExpr.prop('parent').cast(o.DYNAMIC_TYPE)) {
// check references
const refNodeIndex = currBuilder.refNodeIndices[name];
if (refNodeIndex != null) {
return o.importExpr(Identifiers.nodeValue).callFn([currViewExpr, o.literal(refNodeIndex)]);
}
// check variables
const varAst = currBuilder.variables.find((varAst) => varAst.name === name);
if (varAst) {
const varValue = varAst.value || IMPLICIT_TEMPLATE_VAR;
return currViewExpr.prop('context').prop(varValue);
}
}
return null;
}
_createLiteralArrayConverter(sourceSpan, argCount) {
if (argCount === 0) {
const valueExpr = o.importExpr(Identifiers.EMPTY_ARRAY);
return () => valueExpr;
}
const checkIndex = this.nodes.length;
this.nodes.push(() => ({
sourceSpan,
nodeFlags: 32 /* TypePureArray */,
nodeDef: o.importExpr(Identifiers.pureArrayDef).callFn([
o.literal(checkIndex),
o.literal(argCount),
])
}));
return (args) => callCheckStmt(checkIndex, args);
}
_createLiteralMapConverter(sourceSpan, keys) {
if (keys.length === 0) {
const valueExpr = o.importExpr(Identifiers.EMPTY_MAP);
return () => valueExpr;
}
const map = o.literalMap(keys.map((e, i) => (Object.assign({}, e, { value: o.literal(i) }))));
const checkIndex = this.nodes.length;
this.nodes.push(() => ({
sourceSpan,
nodeFlags: 64 /* TypePureObject */,
nodeDef: o.importExpr(Identifiers.pureObjectDef).callFn([
o.literal(checkIndex),
map,
])
}));
return (args) => callCheckStmt(checkIndex, args);
}
_createPipeConverter(expression, name, argCount) {
const pipe = this.usedPipes.find((pipeSummary) => pipeSummary.name === name);
if (pipe.pure) {
const checkIndex = this.nodes.length;
this.nodes.push(() => ({
sourceSpan: expression.sourceSpan,
nodeFlags: 128 /* TypePurePipe */,
nodeDef: o.importExpr(Identifiers.purePipeDef).callFn([
o.literal(checkIndex),
o.literal(argCount),
])
}));
// find underlying pipe in the component view
let compViewExpr = VIEW_VAR;
let compBuilder = this;
while (compBuilder.parent) {
compBuilder = compBuilder.parent;
compViewExpr = compViewExpr.prop('parent').cast(o.DYNAMIC_TYPE);
}
const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
const pipeValueExpr = o.importExpr(Identifiers.nodeValue).callFn([compViewExpr, o.literal(pipeNodeIndex)]);
return (args) => callUnwrapValue(expression.nodeIndex, expression.bindingIndex, callCheckStmt(checkIndex, [pipeValueExpr].concat(args)));
}
else {
const nodeIndex = this._createPipe(expression.sourceSpan, pipe);
const nodeValueExpr = o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
return (args) => callUnwrapValue(expression.nodeIndex, expression.bindingIndex, nodeValueExpr.callMethod('transform', args));
}
}
_createPipe(sourceSpan, pipe) {
const nodeIndex = this.nodes.length;
let flags = 0 /* None */;
pipe.type.lifecycleHooks.forEach((lifecycleHook) => {
// for pipes, we only support ngOnDestroy
if (lifecycleHook === LifecycleHooks.OnDestroy) {
flags |= lifecycleHookToNodeFlag(lifecycleHook);
}
});
const depExprs = pipe.type.diDeps.map((diDep) => depDef(this.outputCtx, diDep));
// function pipeDef(
// flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef
this.nodes.push(() => ({
sourceSpan,
nodeFlags: 16 /* TypePipe */,
nodeDef: o.importExpr(Identifiers.pipeDef).callFn([
o.literal(flags), this.outputCtx.importExpr(pipe.type.reference), o.literalArr(depExprs)
])
}));
return nodeIndex;
}
/**
* For the AST in `UpdateExpression.value`:
* - create nodes for pipes, literal arrays and, literal maps,
* - update the AST to replace pipes, literal arrays and, literal maps with calls to check fn.
*
* WARNING: This might create new nodeDefs (for pipes and literal arrays and literal maps)!
*/
_preprocessUpdateExpression(expression) {
return {
nodeIndex: expression.nodeIndex,
bindingIndex: expression.bindingIndex,
sourceSpan: expression.sourceSpan,
context: expression.context,
value: convertPropertyBindingBuiltins({
createLiteralArrayConverter: (argCount) => this._createLiteralArrayConverter(expression.sourceSpan, argCount),
createLiteralMapConverter: (keys) => this._createLiteralMapConverter(expression.sourceSpan, keys),
createPipeConverter: (name, argCount) => this._createPipeConverter(expression, name, argCount)
}, expression.value)
};
}
_createNodeExpressions() {
const self = this;
let updateBindingCount = 0;
const updateRendererStmts = [];
const updateDirectivesStmts = [];
const nodeDefExprs = this.nodes.map((factory, nodeIndex) => {
const { nodeDef, nodeFlags, updateDirectives, updateRenderer, sourceSpan } = factory();
if (updateRenderer) {
updateRendererStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateRenderer, false));
}
if (updateDirectives) {
updateDirectivesStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateDirectives, (nodeFlags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0));
}
// We use a comma expression to call the log function before
// the nodeDef function, but still use the result of the nodeDef function
// as the value.
// Note: We only add the logger to elements / text nodes,
// so we don't generate too much code.
const logWithNodeDef = nodeFlags & 3 /* CatRenderNode */ ?
new o.CommaExpr([LOG_VAR.callFn([]).callFn([]), nodeDef]) :
nodeDef;
return o.applySourceSpanToExpressionIfNeeded(logWithNodeDef, sourceSpan);
});
return { updateRendererStmts, updateDirectivesStmts, nodeDefExprs };
function createUpdateStatements(nodeIndex, sourceSpan, expressions, allowEmptyExprs) {
const updateStmts = [];
const exprs = expressions.map(({ sourceSpan, context, value }) => {
const bindingId = `${updateBindingCount++}`;
const nameResolver = context === COMP_VAR ? self : null;
const { stmts, currValExpr } = convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
updateStmts.push(...stmts.map((stmt) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
});
if (expressions.length || allowEmptyExprs) {
updateStmts.push(o.applySourceSpanToStatementIfNeeded(callCheckStmt(nodeIndex, exprs).toStmt(), sourceSpan));
}
return updateStmts;
}
}
_createElementHandleEventFn(nodeIndex, handlers) {
const handleEventStmts = [];
let handleEventBindingCount = 0;
handlers.forEach(({ context, eventAst, dirAst }) => {
const bindingId = `${handleEventBindingCount++}`;
const nameResolver = context === COMP_VAR ? this : null;
const { stmts, allowDefault } = convertActionBinding(nameResolver, context, eventAst.handler, bindingId);
const trueStmts = stmts;
if (allowDefault) {
trueStmts.push(ALLOW_DEFAULT_VAR.set(allowDefault.and(ALLOW_DEFAULT_VAR)).toStmt());
}
const { target: eventTarget, name: eventName } = elementEventNameAndTarget(eventAst, dirAst);
const fullEventName = elementEventFullName(eventTarget, eventName);
handleEventStmts.push(o.applySourceSpanToStatementIfNeeded(new o.IfStmt(o.literal(fullEventName).identical(EVENT_NAME_VAR), trueStmts), eventAst.sourceSpan));
});
let handleEventFn;
if (handleEventStmts.length > 0) {
const preStmts = [ALLOW_DEFAULT_VAR.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)];
if (!this.component.isHost && o.findReadVarNames(handleEventStmts).has(COMP_VAR.name)) {
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
}
handleEventFn = o.fn([
new o.FnParam(VIEW_VAR.name, o.INFERRED_TYPE),
new o.FnParam(EVENT_NAME_VAR.name, o.INFERRED_TYPE),
new o.FnParam(EventHandlerVars.event.name, o.INFERRED_TYPE)
], [...preStmts, ...handleEventStmts, new o.ReturnStatement(ALLOW_DEFAULT_VAR)], o.INFERRED_TYPE);
}
else {
handleEventFn = o.NULL_EXPR;
}
return handleEventFn;
}
visitDirective(ast, context) { }
visitDirectiveProperty(ast, context) { }
visitReference(ast, context) { }
visitVariable(ast, context) { }
visitEvent(ast, context) { }
visitElementProperty(ast, context) { }
visitAttr(ast, context) { }
}
function needsAdditionalRootNode(astNodes) {
const lastAstNode = astNodes[astNodes.length - 1];
if (lastAstNode instanceof EmbeddedTemplateAst) {
return lastAstNode.hasViewContainer;
}
if (lastAstNode instanceof ElementAst) {
if (isNgContainer(lastAstNode.name) && lastAstNode.children.length) {
return needsAdditionalRootNode(lastAstNode.children);
}
return lastAstNode.hasViewContainer;
}
return lastAstNode instanceof NgContentAst;
}
function elementBindingDef(inputAst, dirAst) {
switch (inputAst.type) {
case 1 /* Attribute */:
return o.literalArr([
o.literal(1 /* TypeElementAttribute */), o.literal(inputAst.name),
o.literal(inputAst.securityContext)
]);
case 0 /* Property */:
return o.literalArr([
o.literal(8 /* TypeProperty */), o.literal(inputAst.name),
o.literal(inputAst.securityContext)
]);
case 4 /* Animation */:
const bindingType = 8 /* TypeProperty */ |
(dirAst && dirAst.directive.isComponent ? 32 /* SyntheticHostProperty */ :
16 /* SyntheticProperty */);
return o.literalArr([
o.literal(bindingType), o.literal('@' + inputAst.name), o.literal(inputAst.securityContext)
]);
case 2 /* Class */:
return o.literalArr([o.literal(2 /* TypeElementClass */), o.literal(inputAst.name), o.NULL_EXPR]);
case 3 /* Style */:
return o.literalArr([
o.literal(4 /* TypeElementStyle */), o.literal(inputAst.name), o.literal(inputAst.unit)
]);
}
}
function fixedAttrsDef(elementAst) {
const mapResult = Object.create(null);
elementAst.attrs.forEach(attrAst => { mapResult[attrAst.name] = attrAst.value; });
elementAst.directives.forEach(dirAst => {
Object.keys(dirAst.directive.hostAttributes).forEach(name => {
const value = dirAst.directive.hostAttributes[name];
const prevValue = mapResult[name];
mapResult[name] = prevValue != null ? mergeAttributeValue(name, prevValue, value) : value;
});
});
// Note: We need to sort to get a defined output order
// for tests and for caching generated artifacts...
return o.literalArr(Object.keys(mapResult).sort().map((attrName) => o.literalArr([o.literal(attrName), o.literal(mapResult[attrName])])));
}
function mergeAttributeValue(attrName, attrValue1, attrValue2) {
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
return `${attrValue1} ${attrValue2}`;
}
else {
return attrValue2;
}
}
function callCheckStmt(nodeIndex, exprs) {
if (exprs.length > 10) {
return CHECK_VAR.callFn([VIEW_VAR, o.literal(nodeIndex), o.literal(1 /* Dynamic */), o.literalArr(exprs)]);
}
else {
return CHECK_VAR.callFn([VIEW_VAR, o.literal(nodeIndex), o.literal(0 /* Inline */), ...exprs]);
}
}
function callUnwrapValue(nodeIndex, bindingIdx, expr) {
return o.importExpr(Identifiers.unwrapValue).callFn([
VIEW_VAR, o.literal(nodeIndex), o.literal(bindingIdx), expr
]);
}
function findStaticQueryIds(nodes, result = new Map()) {
nodes.forEach((node) => {
const staticQueryIds = new Set();
const dynamicQueryIds = new Set();
let queryMatches = undefined;
if (node instanceof ElementAst) {
findStaticQueryIds(node.children, result);
node.children.forEach((child) => {
const childData = result.get(child);
childData.staticQueryIds.forEach(queryId => staticQueryIds.add(queryId));
childData.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
});
queryMatches = node.queryMatches;
}
else if (node instanceof EmbeddedTemplateAst) {
findStaticQueryIds(node.children, result);
node.children.forEach((child) => {
const childData = result.get(child);
childData.staticQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
childData.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
});
queryMatches = node.queryMatches;
}
if (queryMatches) {
queryMatches.forEach((match) => staticQueryIds.add(match.queryId));
}
dynamicQueryIds.forEach(queryId => staticQueryIds.delete(queryId));
result.set(node, { staticQueryIds, dynamicQueryIds });
});
return result;
}
function staticViewQueryIds(nodeStaticQueryIds) {
const staticQueryIds = new Set();
const dynamicQueryIds = new Set();
Array.from(nodeStaticQueryIds.values()).forEach((entry) => {
entry.staticQueryIds.forEach(queryId => staticQueryIds.add(queryId));
entry.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
});
dynamicQueryIds.forEach(queryId => staticQueryIds.delete(queryId));
return { staticQueryIds, dynamicQueryIds };
}
function elementEventNameAndTarget(eventAst, dirAst) {
if (eventAst.isAnimation) {
return {
name: `@${eventAst.name}.${eventAst.phase}`,
target: dirAst && dirAst.directive.isComponent ? 'component' : null
};
}
else {
return eventAst;
}
}
function calcStaticDynamicQueryFlags(queryIds, queryId, isFirst) {
let flags = 0 /* None */;
// Note: We only make queries static that query for a single item.
// This is because of backwards compatibility with the old view compiler...
if (isFirst && (queryIds.staticQueryIds.has(queryId) || !queryIds.dynamicQueryIds.has(queryId))) {
flags |= 268435456 /* StaticQuery */;
}
else {
flags |= 536870912 /* DynamicQuery */;
}
return flags;
}
export function elementEventFullName(target, name) {
return target ? `${target}:${name}` : name;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlld19jb21waWxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbXBpbGVyL3NyYy92aWV3X2NvbXBpbGVyL3ZpZXdfY29tcGlsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUErQyxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFFbEksT0FBTyxFQUFDLFdBQVcsRUFBb0IsZ0JBQWdCLEVBQWlCLG9CQUFvQixFQUFFLHNCQUFzQixFQUFFLDhCQUE4QixFQUFDLE1BQU0sdUNBQXVDLENBQUM7QUFDbk0sT0FBTyxFQUE2Qix1QkFBdUIsRUFBeUQsTUFBTSxTQUFTLENBQUM7QUFFcEksT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDaEQsT0FBTyxLQUFLLENBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUMxQyxPQUFPLEVBQUMsdUJBQXVCLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUU3RCxPQUFPLEVBQXlHLFVBQVUsRUFBRSxtQkFBbUIsRUFBRSxZQUFZLEVBQXFILGdCQUFnQixFQUFDLE1BQU0saUNBQWlDLENBQUM7QUFHM1UsT0FBTyxFQUFDLG1DQUFtQyxFQUFFLE1BQU0sRUFBRSx1QkFBdUIsRUFBRSxXQUFXLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUV0SCxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUM7QUFDM0IsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDO0FBQzNCLE1BQU0scUJBQXFCLEdBQUcsWUFBWSxDQUFDO0FBRTNDLE1BQU07SUFDSixZQUFtQixZQUFvQixFQUFTLGVBQXVCO1FBQXBELGlCQUFZLEdB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