perf: delete pre-view-engine core, compiler, platform-browser, etc code (#14788)

After the introduction of the view engine, we can drop a lot of code that is not used any more.

This should reduce the size of the app bundles because a lot of this code was not being properly tree-shaken by today's tools even though it was dead code.
This commit is contained in:
Tobias Bosch
2017-02-27 23:08:19 -08:00
committed by Igor Minar
parent e58cb7ba08
commit 126fda2613
151 changed files with 1283 additions and 14864 deletions

View File

@ -1,402 +0,0 @@
/**
* @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 {CompileDiDependencyMetadata, CompileDirectiveSummary, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, tokenName, tokenReference} from '../compile_metadata';
import {createDiTokenExpression} from '../compiler_util/identifier_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {isPresent} from '../facade/lang';
import {Identifiers, createIdentifier, createIdentifierToken, identifierToken, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {convertValueToOutputAst} from '../output/value_util';
import {ProviderAst, ProviderAstType, ReferenceAst, TemplateAst} from '../template_parser/template_ast';
import {CompileMethod} from './compile_method';
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
import {CompileView, CompileViewRootNode} from './compile_view';
import {InjectMethodVars} from './constants';
import {ComponentFactoryDependency, DirectiveWrapperDependency} from './deps';
import {getPropertyInView, injectFromViewParentInjector} from './util';
export class CompileNode {
constructor(
public parent: CompileElement, public view: CompileView, public nodeIndex: number,
public renderNode: o.Expression, public sourceAst: TemplateAst) {}
isNull(): boolean { return !this.renderNode; }
isRootElement(): boolean { return this.view != this.parent.view; }
}
export class CompileElement extends CompileNode {
static createNull(): CompileElement {
return new CompileElement(null, null, null, null, null, null, [], [], false, false, []);
}
public compViewExpr: o.Expression = null;
public viewContainer: o.ReadPropExpr;
public elementRef: o.Expression;
public instances = new Map<any, o.Expression>();
public directiveWrapperInstance = new Map<any, o.Expression>();
private _resolvedProviders: Map<any, ProviderAst>;
private _queryCount = 0;
private _queries = new Map<any, CompileQuery[]>();
public contentNodesByNgContentIndex: Array<CompileViewRootNode>[] = null;
public embeddedView: CompileView;
public referenceTokens: {[key: string]: CompileTokenMetadata};
constructor(
parent: CompileElement, view: CompileView, nodeIndex: number, renderNode: o.Expression,
sourceAst: TemplateAst, public component: CompileDirectiveSummary,
private _directives: CompileDirectiveSummary[],
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
public hasEmbeddedView: boolean, references: ReferenceAst[]) {
super(parent, view, nodeIndex, renderNode, sourceAst);
this.referenceTokens = {};
references.forEach(ref => this.referenceTokens[ref.name] = ref.value);
this.elementRef =
o.importExpr(createIdentifier(Identifiers.ElementRef)).instantiate([this.renderNode]);
this.instances.set(resolveIdentifier(Identifiers.ElementRef), this.elementRef);
this.instances.set(
resolveIdentifier(Identifiers.Injector),
o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]));
this.instances.set(resolveIdentifier(Identifiers.Renderer), o.THIS_EXPR.prop('renderer'));
if (this.hasViewContainer || this.hasEmbeddedView) {
this._createViewContainer();
}
if (this.component) {
this._createComponentFactoryResolver();
}
}
private _createViewContainer() {
const fieldName = `_vc_${this.nodeIndex}`;
const parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
// private is fine here as no child view will reference a ViewContainer
this.view.fields.push(new o.ClassField(
fieldName, o.importType(createIdentifier(Identifiers.ViewContainer)),
[o.StmtModifier.Private]));
const statement =
o.THIS_EXPR.prop(fieldName)
.set(o.importExpr(createIdentifier(Identifiers.ViewContainer)).instantiate([
o.literal(this.nodeIndex), o.literal(parentNodeIndex), o.THIS_EXPR, this.renderNode
]))
.toStmt();
this.view.createMethod.addStmt(statement);
this.viewContainer = o.THIS_EXPR.prop(fieldName);
this.instances.set(resolveIdentifier(Identifiers.ViewContainer), this.viewContainer);
this.view.viewContainers.push(this.viewContainer);
}
private _createComponentFactoryResolver() {
const entryComponents = this.component.entryComponents.map((entryComponent) => {
this.view.targetDependencies.push(
new ComponentFactoryDependency(entryComponent.componentType));
return {reference: entryComponent.componentFactory};
});
if (!entryComponents || entryComponents.length === 0) {
return;
}
const createComponentFactoryResolverExpr =
o.importExpr(createIdentifier(Identifiers.CodegenComponentFactoryResolver)).instantiate([
o.literalArr(entryComponents.map((entryComponent) => o.importExpr(entryComponent))),
injectFromViewParentInjector(
this.view, createIdentifierToken(Identifiers.ComponentFactoryResolver), false)
]);
const provider: CompileProviderMetadata = {
token: createIdentifierToken(Identifiers.ComponentFactoryResolver),
useValue: createComponentFactoryResolverExpr
};
// Add ComponentFactoryResolver as first provider as it does not have deps on other providers
// ProviderAstType.PrivateService as only the component and its view can see it,
// but nobody else
this._resolvedProvidersArray.unshift(new ProviderAst(
provider.token, false, true, [provider], ProviderAstType.PrivateService, [],
this.sourceAst.sourceSpan));
}
setComponentView(compViewExpr: o.Expression) {
this.compViewExpr = compViewExpr;
this.contentNodesByNgContentIndex =
new Array(this.component.template.ngContentSelectors.length);
for (let i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
this.contentNodesByNgContentIndex[i] = [];
}
}
setEmbeddedView(embeddedView: CompileView) {
this.embeddedView = embeddedView;
if (isPresent(embeddedView)) {
const createTemplateRefExpr =
o.importExpr(createIdentifier(Identifiers.TemplateRef_)).instantiate([
o.THIS_EXPR, o.literal(this.nodeIndex), this.renderNode
]);
const provider: CompileProviderMetadata = {
token: createIdentifierToken(Identifiers.TemplateRef),
useValue: createTemplateRefExpr
};
// Add TemplateRef as first provider as it does not have deps on other providers
this._resolvedProvidersArray.unshift(new ProviderAst(
provider.token, false, true, [provider], ProviderAstType.Builtin, [],
this.sourceAst.sourceSpan));
}
}
beforeChildren(): void {
if (this.hasViewContainer) {
this.instances.set(
resolveIdentifier(Identifiers.ViewContainerRef), this.viewContainer.prop('vcRef'));
}
this._resolvedProviders = new Map<any, ProviderAst>();
this._resolvedProvidersArray.forEach(
provider => this._resolvedProviders.set(tokenReference(provider.token), provider));
// create all the provider instances, some in the view constructor,
// some as getters. We rely on the fact that they are already sorted topologically.
Array.from(this._resolvedProviders.values()).forEach((resolvedProvider) => {
const isDirectiveWrapper = resolvedProvider.providerType === ProviderAstType.Component ||
resolvedProvider.providerType === ProviderAstType.Directive;
const providerValueExpressions = resolvedProvider.providers.map((provider) => {
if (provider.useExisting) {
return this._getDependency(resolvedProvider.providerType, {token: provider.useExisting});
} else if (provider.useFactory) {
const deps = provider.deps || provider.useFactory.diDeps;
const depsExpr =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
return o.importExpr(provider.useFactory).callFn(depsExpr);
} else if (provider.useClass) {
const deps = provider.deps || provider.useClass.diDeps;
const depsExpr =
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep));
if (isDirectiveWrapper) {
const dirMeta =
this._directives.find(dir => dir.type.reference === provider.useClass.reference);
this.view.targetDependencies.push(
new DirectiveWrapperDependency(dirMeta.type.reference));
return DirectiveWrapperExpressions.create({reference: dirMeta.wrapperType}, depsExpr);
} else {
return o.importExpr(provider.useClass)
.instantiate(depsExpr, o.importType(provider.useClass));
}
} else {
return convertValueToOutputAst(provider.useValue);
}
});
const propName =
`_${tokenName(resolvedProvider.token)}_${this.nodeIndex}_${this.instances.size}`;
const instance = createProviderProperty(
propName, providerValueExpressions, resolvedProvider.multiProvider,
resolvedProvider.eager, this);
if (isDirectiveWrapper) {
this.directiveWrapperInstance.set(tokenReference(resolvedProvider.token), instance);
this.instances.set(
tokenReference(resolvedProvider.token), DirectiveWrapperExpressions.context(instance));
} else {
this.instances.set(tokenReference(resolvedProvider.token), instance);
}
});
for (let i = 0; i < this._directives.length; i++) {
const directive = this._directives[i];
const directiveInstance = this.instances.get(tokenReference(identifierToken(directive.type)));
directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); });
}
Object.keys(this.referenceTokens).forEach(varName => {
const token = this.referenceTokens[varName];
let varValue: o.Expression;
if (token) {
varValue = this.instances.get(tokenReference(token));
} else {
varValue = this.renderNode;
}
this.view.locals.set(varName, varValue);
});
}
afterChildren(childNodeCount: number) {
Array.from(this._resolvedProviders.values()).forEach((resolvedProvider) => {
// Note: afterChildren is called after recursing into children.
// This is good so that an injector match in an element that is closer to a requesting element
// matches first.
const providerExpr = this.instances.get(tokenReference(resolvedProvider.token));
// Note: view providers are only visible on the injector of that element.
// This is not fully correct as the rules during codegen don't allow a directive
// to get hold of a view provdier on the same element. We still do this semantic
// as it simplifies our model to having only one runtime injector per element.
const providerChildNodeCount =
resolvedProvider.providerType === ProviderAstType.PrivateService ? 0 : childNodeCount;
this.view.injectorGetMethod.addStmt(createInjectInternalCondition(
this.nodeIndex, providerChildNodeCount, resolvedProvider, providerExpr));
});
}
finish() {
Array.from(this._queries.values())
.forEach(
queries => queries.forEach(
q => q.generateStatements(
this.view.createMethod, this.view.updateContentQueriesMethod)));
}
addContentNode(ngContentIndex: number, nodeExpr: CompileViewRootNode) {
this.contentNodesByNgContentIndex[ngContentIndex].push(nodeExpr);
}
getComponent(): o.Expression {
return isPresent(this.component) ?
this.instances.get(tokenReference(identifierToken(this.component.type))) :
null;
}
getProviderTokens(): CompileTokenMetadata[] {
return Array.from(this._resolvedProviders.values()).map(provider => provider.token);
}
getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
const result: CompileQuery[] = [];
let currentEl: CompileElement = this;
let distance = 0;
let queries: CompileQuery[];
while (!currentEl.isNull()) {
queries = currentEl._queries.get(tokenReference(token));
if (isPresent(queries)) {
result.push(...queries.filter((query) => query.meta.descendants || distance <= 1));
}
if (currentEl._directives.length > 0) {
distance++;
}
currentEl = currentEl.parent;
}
queries = this.view.componentView.viewQueries.get(tokenReference(token));
if (isPresent(queries)) {
result.push(...queries);
}
return result;
}
private _addQuery(queryMeta: CompileQueryMetadata, directiveInstance: o.Expression):
CompileQuery {
const propName =
`_query_${tokenName(queryMeta.selectors[0])}_${this.nodeIndex}_${this._queryCount++}`;
const queryList = createQueryList(propName, this.view);
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this.view);
addQueryToTokenMap(this._queries, query);
return query;
}
private _getLocalDependency(
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata): o.Expression {
let result: o.Expression = null;
if (isPresent(dep.token)) {
// access builtins with special visibility
if (!result) {
if (tokenReference(dep.token) === resolveIdentifier(Identifiers.ChangeDetectorRef)) {
if (requestingProviderType === ProviderAstType.Component) {
return this.compViewExpr.prop('ref');
} else {
return getPropertyInView(o.THIS_EXPR.prop('ref'), this.view, this.view.componentView);
}
}
}
// access regular providers on the element
if (!result) {
const resolvedProvider = this._resolvedProviders.get(tokenReference(dep.token));
// don't allow directives / public services to access private services.
// only components and private services can access private services.
if (resolvedProvider && (requestingProviderType === ProviderAstType.Directive ||
requestingProviderType === ProviderAstType.PublicService) &&
resolvedProvider.providerType === ProviderAstType.PrivateService) {
return null;
}
result = this.instances.get(tokenReference(dep.token));
}
}
return result;
}
private _getDependency(requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata):
o.Expression {
let currElement: CompileElement = this;
let result: o.Expression = null;
if (dep.isValue) {
result = o.literal(dep.value);
}
if (!result && !dep.isSkipSelf) {
result = this._getLocalDependency(requestingProviderType, dep);
}
// check parent elements
while (!result && !currElement.parent.isNull()) {
currElement = currElement.parent;
result = currElement._getLocalDependency(ProviderAstType.PublicService, {token: dep.token});
}
if (!result) {
result = injectFromViewParentInjector(this.view, dep.token, dep.isOptional);
}
if (!result) {
result = o.NULL_EXPR;
}
return getPropertyInView(result, this.view, currElement.view);
}
}
function createInjectInternalCondition(
nodeIndex: number, childNodeCount: number, provider: ProviderAst,
providerExpr: o.Expression): o.Statement {
let indexCondition: o.Expression;
if (childNodeCount > 0) {
indexCondition = o.literal(nodeIndex)
.lowerEquals(InjectMethodVars.requestNodeIndex)
.and(InjectMethodVars.requestNodeIndex.lowerEquals(
o.literal(nodeIndex + childNodeCount)));
} else {
indexCondition = o.literal(nodeIndex).identical(InjectMethodVars.requestNodeIndex);
}
return new o.IfStmt(
InjectMethodVars.token.identical(createDiTokenExpression(provider.token)).and(indexCondition),
[new o.ReturnStatement(providerExpr)]);
}
function createProviderProperty(
propName: string, providerValueExpressions: o.Expression[], isMulti: boolean, isEager: boolean,
compileElement: CompileElement): o.Expression {
const view = compileElement.view;
let resolvedProviderValueExpr: o.Expression;
let type: o.Type;
if (isMulti) {
resolvedProviderValueExpr = o.literalArr(providerValueExpressions);
type = new o.ArrayType(o.DYNAMIC_TYPE);
} else {
resolvedProviderValueExpr = providerValueExpressions[0];
type = providerValueExpressions[0].type;
}
if (!type) {
type = o.DYNAMIC_TYPE;
}
if (isEager) {
view.fields.push(new o.ClassField(propName, type));
view.createMethod.addStmt(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
} else {
const internalField = `_${propName}`;
view.fields.push(new o.ClassField(internalField, type));
const getter = new CompileMethod(view);
getter.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
// Note: Equals is important for JS so that it also checks the undefined case!
getter.addStmt(new o.IfStmt(
o.THIS_EXPR.prop(internalField).isBlank(),
[o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]));
getter.addStmt(new o.ReturnStatement(o.THIS_EXPR.prop(internalField)));
view.getters.push(new o.ClassGetter(propName, getter.finish(), type));
}
return o.THIS_EXPR.prop(propName);
}

View File

@ -1,81 +0,0 @@
/**
* @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 * as o from '../output/output_ast';
import {TemplateAst} from '../template_parser/template_ast';
import {CompileView} from './compile_view';
class _DebugState {
constructor(public nodeIndex: number, public sourceAst: TemplateAst) {}
}
const NULL_DEBUG_STATE = new _DebugState(null, null);
export class CompileMethod {
private _newState: _DebugState = NULL_DEBUG_STATE;
private _currState: _DebugState = NULL_DEBUG_STATE;
private _debugEnabled: boolean;
private _bodyStatements: o.Statement[] = [];
constructor(private _view: CompileView) {
this._debugEnabled = this._view.genConfig.genDebugInfo;
}
private _updateDebugContextIfNeeded() {
if (this._newState.nodeIndex !== this._currState.nodeIndex ||
this._newState.sourceAst !== this._currState.sourceAst) {
const expr = this._updateDebugContext(this._newState);
if (expr) {
this._bodyStatements.push(expr.toStmt());
}
}
}
private _updateDebugContext(newState: _DebugState): o.Expression {
this._currState = this._newState = newState;
if (this._debugEnabled) {
const sourceLocation = newState.sourceAst ? newState.sourceAst.sourceSpan.start : null;
return o.THIS_EXPR.callMethod('debug', [
o.literal(newState.nodeIndex),
sourceLocation ? o.literal(sourceLocation.line) : o.NULL_EXPR,
sourceLocation ? o.literal(sourceLocation.col) : o.NULL_EXPR
]);
} else {
return null;
}
}
resetDebugInfoExpr(nodeIndex: number, templateAst: TemplateAst): o.Expression {
const res = this._updateDebugContext(new _DebugState(nodeIndex, templateAst));
return res || o.NULL_EXPR;
}
resetDebugInfo(nodeIndex: number, templateAst: TemplateAst) {
this._newState = new _DebugState(nodeIndex, templateAst);
}
push(...stmts: o.Statement[]) { this.addStmts(stmts); }
addStmt(stmt: o.Statement) {
this._updateDebugContextIfNeeded();
this._bodyStatements.push(stmt);
}
addStmts(stmts: o.Statement[]) {
this._updateDebugContextIfNeeded();
this._bodyStatements.push(...stmts);
}
finish(): o.Statement[] { return this._bodyStatements; }
isEmpty(): boolean { return this._bodyStatements.length === 0; }
}

View File

@ -1,94 +0,0 @@
/**
* @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 {CompilePipeSummary, tokenReference} from '../compile_metadata';
import {createPureProxy} from '../compiler_util/identifier_util';
import {Identifiers, createIdentifier, resolveIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {CompileView} from './compile_view';
import {getPropertyInView, injectFromViewParentInjector} from './util';
export class CompilePipe {
static call(view: CompileView, name: string, args: o.Expression[]): o.Expression {
const compView = view.componentView;
const meta = _findPipeMeta(compView, name);
let pipe: CompilePipe;
if (meta.pure) {
// pure pipes live on the component view
pipe = compView.purePipes.get(name);
if (!pipe) {
pipe = new CompilePipe(compView, meta);
compView.purePipes.set(name, pipe);
compView.pipes.push(pipe);
}
} else {
// Non pure pipes live on the view that called it
pipe = new CompilePipe(view, meta);
view.pipes.push(pipe);
}
return pipe._call(view, args);
}
instance: o.ReadPropExpr;
private _purePipeProxyCount = 0;
constructor(public view: CompileView, public meta: CompilePipeSummary) {
this.instance = o.THIS_EXPR.prop(`_pipe_${meta.name}_${view.pipeCount++}`);
const deps = this.meta.type.diDeps.map((diDep) => {
if (tokenReference(diDep.token) === resolveIdentifier(Identifiers.ChangeDetectorRef)) {
return getPropertyInView(o.THIS_EXPR.prop('ref'), this.view, this.view.componentView);
}
return injectFromViewParentInjector(view, diDep.token, false);
});
this.view.fields.push(new o.ClassField(this.instance.name, o.importType(this.meta.type)));
this.view.createMethod.resetDebugInfo(null, null);
this.view.createMethod.addStmt(o.THIS_EXPR.prop(this.instance.name)
.set(o.importExpr(this.meta.type).instantiate(deps))
.toStmt());
}
get pure(): boolean { return this.meta.pure; }
private _call(callingView: CompileView, args: o.Expression[]): o.Expression {
if (this.meta.pure) {
// PurePipeProxies live on the view that called them.
const purePipeProxyInstance =
o.THIS_EXPR.prop(`${this.instance.name}_${this._purePipeProxyCount++}`);
const pipeInstanceSeenFromPureProxy =
getPropertyInView(this.instance, callingView, this.view);
createPureProxy(
pipeInstanceSeenFromPureProxy.prop('transform')
.callMethod(o.BuiltinMethod.Bind, [pipeInstanceSeenFromPureProxy]),
args.length, purePipeProxyInstance,
{fields: callingView.fields, ctorStmts: callingView.createMethod});
return o.importExpr(createIdentifier(Identifiers.castByValue))
.callFn([purePipeProxyInstance, pipeInstanceSeenFromPureProxy.prop('transform')])
.callFn(args);
} else {
return getPropertyInView(this.instance, callingView, this.view).callMethod('transform', args);
}
}
}
function _findPipeMeta(view: CompileView, name: string): CompilePipeSummary {
let pipeMeta: CompilePipeSummary = null;
for (let i = view.pipeMetas.length - 1; i >= 0; i--) {
const localPipeMeta = view.pipeMetas[i];
if (localPipeMeta.name == name) {
pipeMeta = localPipeMeta;
break;
}
}
if (!pipeMeta) {
throw new Error(
`Illegal state: Could not find pipe ${name} although the parser should have detected this error!`);
}
return pipeMeta;
}

View File

@ -1,133 +0,0 @@
/**
* @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 {CompileQueryMetadata, tokenReference} from '../compile_metadata';
import {ListWrapper} from '../facade/collection';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {CompileElement} from './compile_element';
import {CompileMethod} from './compile_method';
import {CompileView} from './compile_view';
import {getPropertyInView} from './util';
class ViewQueryValues {
constructor(public view: CompileView, public values: Array<o.Expression|ViewQueryValues>) {}
}
export class CompileQuery {
private _values: ViewQueryValues;
constructor(
public meta: CompileQueryMetadata, public queryList: o.Expression,
public ownerDirectiveExpression: o.Expression, public view: CompileView) {
this._values = new ViewQueryValues(view, []);
}
addValue(value: o.Expression, view: CompileView) {
let currentView = view;
const elPath: CompileElement[] = [];
while (currentView && currentView !== this.view) {
const parentEl = currentView.declarationElement;
elPath.unshift(parentEl);
currentView = parentEl.view;
}
const queryListForDirtyExpr = getPropertyInView(this.queryList, view, this.view);
let viewValues = this._values;
elPath.forEach((el) => {
const last =
viewValues.values.length > 0 ? viewValues.values[viewValues.values.length - 1] : null;
if (last instanceof ViewQueryValues && last.view === el.embeddedView) {
viewValues = last;
} else {
const newViewValues = new ViewQueryValues(el.embeddedView, []);
viewValues.values.push(newViewValues);
viewValues = newViewValues;
}
});
viewValues.values.push(value);
if (elPath.length > 0) {
view.dirtyParentQueriesMethod.addStmt(
queryListForDirtyExpr.callMethod('setDirty', []).toStmt());
}
}
private _isStatic(): boolean {
return !this._values.values.some(value => value instanceof ViewQueryValues);
}
generateStatements(targetStaticMethod: CompileMethod, targetDynamicMethod: CompileMethod) {
const values = createQueryValues(this._values);
const updateStmts = [this.queryList.callMethod('reset', [o.literalArr(values)]).toStmt()];
if (this.ownerDirectiveExpression) {
const valueExpr = this.meta.first ? this.queryList.prop('first') : this.queryList;
updateStmts.push(
this.ownerDirectiveExpression.prop(this.meta.propertyName).set(valueExpr).toStmt());
}
if (!this.meta.first) {
updateStmts.push(this.queryList.callMethod('notifyOnChanges', []).toStmt());
}
if (this.meta.first && this._isStatic()) {
// for queries that don't change and the user asked for a single element,
// set it immediately. That is e.g. needed for querying for ViewContainerRefs, ...
// we don't do this for QueryLists for now as this would break the timing when
// we call QueryList listeners...
targetStaticMethod.addStmts(updateStmts);
} else {
targetDynamicMethod.addStmt(new o.IfStmt(this.queryList.prop('dirty'), updateStmts));
}
}
}
function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
return ListWrapper.flatten(viewValues.values.map((entry) => {
if (entry instanceof ViewQueryValues) {
return mapNestedViews(
entry.view.declarationElement.viewContainer, entry.view, createQueryValues(entry));
} else {
return <o.Expression>entry;
}
}));
}
function mapNestedViews(
viewContainer: o.Expression, view: CompileView, expressions: o.Expression[]): o.Expression {
const adjustedExpressions: o.Expression[] = expressions.map(
(expr) => o.replaceVarInExpression(o.THIS_EXPR.name, o.variable('nestedView'), expr));
return viewContainer.callMethod('mapNestedViews', [
o.variable(view.className),
o.fn(
[new o.FnParam('nestedView', view.classType)],
[new o.ReturnStatement(o.literalArr(adjustedExpressions))], o.DYNAMIC_TYPE)
]);
}
export function createQueryList(propertyName: string, compileView: CompileView): o.Expression {
compileView.fields.push(new o.ClassField(
propertyName, o.importType(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE])));
const expr = o.THIS_EXPR.prop(propertyName);
compileView.createMethod.addStmt(
o.THIS_EXPR.prop(propertyName)
.set(o.importExpr(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE]).instantiate([
]))
.toStmt());
return expr;
}
export function addQueryToTokenMap(map: Map<any, CompileQuery[]>, query: CompileQuery) {
query.meta.selectors.forEach((selector) => {
let entry = map.get(tokenReference(selector));
if (!entry) {
entry = [];
map.set(tokenReference(selector), entry);
}
entry.push(query);
});
}

View File

@ -1,176 +0,0 @@
/**
* @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 {ɵViewType as ViewType} from '@angular/core';
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenName, viewClassName} from '../compile_metadata';
import {EventHandlerVars, LegacyNameResolver} from '../compiler_util/expression_converter';
import {CompilerConfig} from '../config';
import {isPresent} from '../facade/lang';
import * as o from '../output/output_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileMethod} from './compile_method';
import {CompilePipe} from './compile_pipe';
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
import {getPropertyInView} from './util';
export enum CompileViewRootNodeType {
Node,
ViewContainer,
NgContent
}
export class CompileViewRootNode {
constructor(
public type: CompileViewRootNodeType, public expr: o.Expression,
public ngContentIndex?: number) {}
}
export class CompileView implements LegacyNameResolver {
public viewType: ViewType;
public viewQueries: Map<any, CompileQuery[]>;
public viewChildren: o.Expression[] = [];
public nodes: CompileNode[] = [];
public rootNodes: CompileViewRootNode[] = [];
public lastRenderNode: o.Expression = o.NULL_EXPR;
public viewContainers: o.Expression[] = [];
public createMethod: CompileMethod;
public animationBindingsMethod: CompileMethod;
public injectorGetMethod: CompileMethod;
public updateContentQueriesMethod: CompileMethod;
public dirtyParentQueriesMethod: CompileMethod;
public updateViewQueriesMethod: CompileMethod;
public detectChangesInInputsMethod: CompileMethod;
public detectChangesRenderPropertiesMethod: CompileMethod;
public afterContentLifecycleCallbacksMethod: CompileMethod;
public afterViewLifecycleCallbacksMethod: CompileMethod;
public destroyMethod: CompileMethod;
public detachMethod: CompileMethod;
public methods: o.ClassMethod[] = [];
public ctorStmts: o.Statement[] = [];
public fields: o.ClassField[] = [];
public getters: o.ClassGetter[] = [];
public disposables: o.Expression[] = [];
public componentView: CompileView;
public purePipes = new Map<string, CompilePipe>();
public pipes: CompilePipe[] = [];
public locals = new Map<string, o.Expression>();
public className: string;
public rendererTypeName: string;
public classType: o.Type;
public classExpr: o.ReadVarExpr;
public literalArrayCount = 0;
public literalMapCount = 0;
public pipeCount = 0;
public componentContext: o.Expression;
constructor(
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
public pipeMetas: CompilePipeSummary[], public styles: o.Expression,
public animations: AnimationEntryCompileResult[], public viewIndex: number,
public declarationElement: CompileElement, public templateVariableBindings: string[][],
public targetDependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {
this.createMethod = new CompileMethod(this);
this.animationBindingsMethod = new CompileMethod(this);
this.injectorGetMethod = new CompileMethod(this);
this.updateContentQueriesMethod = new CompileMethod(this);
this.dirtyParentQueriesMethod = new CompileMethod(this);
this.updateViewQueriesMethod = new CompileMethod(this);
this.detectChangesInInputsMethod = new CompileMethod(this);
this.detectChangesRenderPropertiesMethod = new CompileMethod(this);
this.afterContentLifecycleCallbacksMethod = new CompileMethod(this);
this.afterViewLifecycleCallbacksMethod = new CompileMethod(this);
this.destroyMethod = new CompileMethod(this);
this.detachMethod = new CompileMethod(this);
this.viewType = getViewType(component, viewIndex);
this.className = viewClassName(component.type.reference, viewIndex);
this.rendererTypeName = rendererTypeName(component.type.reference);
this.classType = o.expressionType(o.variable(this.className));
this.classExpr = o.variable(this.className);
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {
this.componentView = this;
} else {
this.componentView = this.declarationElement.view.componentView;
}
this.componentContext =
getPropertyInView(o.THIS_EXPR.prop('context'), this, this.componentView);
const viewQueries = new Map<any, CompileQuery[]>();
if (this.viewType === ViewType.COMPONENT) {
const directiveInstance = o.THIS_EXPR.prop('context');
this.component.viewQueries.forEach((queryMeta, queryIndex) => {
const propName = `_viewQuery_${tokenName(queryMeta.selectors[0])}_${queryIndex}`;
const queryList = createQueryList(propName, this);
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this);
addQueryToTokenMap(viewQueries, query);
});
}
this.viewQueries = viewQueries;
templateVariableBindings.forEach(
(entry) => { this.locals.set(entry[1], o.THIS_EXPR.prop('context').prop(entry[0])); });
if (!this.declarationElement.isNull()) {
this.declarationElement.setEmbeddedView(this);
}
}
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression {
return CompilePipe.call(this, name, [input].concat(args));
}
getLocal(name: string): o.Expression {
if (name == EventHandlerVars.event.name) {
return EventHandlerVars.event;
}
let currView: CompileView = this;
let result = currView.locals.get(name);
while (!result && isPresent(currView.declarationElement.view)) {
currView = currView.declarationElement.view;
result = currView.locals.get(name);
}
if (isPresent(result)) {
return getPropertyInView(result, this, currView);
} else {
return null;
}
}
finish() {
Array.from(this.viewQueries.values())
.forEach(
queries => queries.forEach(
q => q.generateStatements(this.createMethod, this.updateViewQueriesMethod)));
}
}
function getViewType(component: CompileDirectiveMetadata, embeddedTemplateIndex: number): ViewType {
if (embeddedTemplateIndex > 0) {
return ViewType.EMBEDDED;
}
if (component.isHost) {
return ViewType.HOST;
}
return ViewType.COMPONENT;
}

View File

@ -1,49 +0,0 @@
/**
* @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 {ChangeDetectionStrategy, ViewEncapsulation, ɵViewType as ViewType} from '@angular/core';
import {createEnumExpression} from '../compiler_util/identifier_util';
import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
export class ViewTypeEnum {
static fromValue(value: ViewType): o.Expression {
return createEnumExpression(Identifiers.ViewType, value);
}
}
export class ViewEncapsulationEnum {
static fromValue(value: ViewEncapsulation): o.Expression {
return createEnumExpression(Identifiers.ViewEncapsulation, value);
}
}
export class ChangeDetectorStatusEnum {
static fromValue(value: ChangeDetectorStatusEnum): o.Expression {
return createEnumExpression(Identifiers.ChangeDetectorStatus, value);
}
}
export class ViewConstructorVars {
static viewUtils = o.variable('viewUtils');
static parentView = o.variable('parentView');
static parentIndex = o.variable('parentIndex');
static parentElement = o.variable('parentElement');
}
export class ViewProperties {
static renderer = o.THIS_EXPR.prop('renderer');
static viewUtils = o.THIS_EXPR.prop('viewUtils');
static throwOnChange = o.THIS_EXPR.prop('throwOnChange');
}
export class InjectMethodVars {
static token = o.variable('token');
static requestNodeIndex = o.variable('requestNodeIndex');
static notFoundResult = o.variable('notFoundResult');
}

View File

@ -1,31 +0,0 @@
/**
* @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
*/
/**
* This is currently not read, but will probably be used in the future.
* We keep it as we already pass it through all the right places...
*/
export class ComponentViewDependency {
constructor(public compType: any) {}
}
/**
* This is currently not read, but will probably be used in the future.
* We keep it as we already pass it through all the right places...
*/
export class ComponentFactoryDependency {
constructor(public compType: any) {}
}
/**
* This is currently not read, but will probably be used in the future.
* We keep it as we already pass it through all the right places...
*/
export class DirectiveWrapperDependency {
constructor(public dirType: any) {}
}

View File

@ -1,135 +0,0 @@
/**
* @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 {EventHandlerVars, convertActionBinding} from '../compiler_util/expression_converter';
import {createInlineArray} from '../compiler_util/identifier_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
import {CompileElement} from './compile_element';
import {CompileMethod} from './compile_method';
import {getHandleEventMethodName} from './util';
export function bindOutputs(
boundEvents: BoundEventAst[], directives: DirectiveAst[], compileElement: CompileElement,
bindToRenderer: boolean): boolean {
const usedEvents = collectEvents(boundEvents, directives);
if (!usedEvents.size) {
return false;
}
if (bindToRenderer) {
subscribeToRenderEvents(usedEvents, compileElement);
}
subscribeToDirectiveEvents(usedEvents, directives, compileElement);
generateHandleEventMethod(boundEvents, directives, compileElement);
return true;
}
function collectEvents(
boundEvents: BoundEventAst[], directives: DirectiveAst[]): Map<string, EventSummary> {
const usedEvents = new Map<string, EventSummary>();
boundEvents.forEach((event) => { usedEvents.set(event.fullName, event); });
directives.forEach((dirAst) => {
dirAst.hostEvents.forEach((event) => { usedEvents.set(event.fullName, event); });
});
return usedEvents;
}
function subscribeToRenderEvents(
usedEvents: Map<string, EventSummary>, compileElement: CompileElement) {
const eventAndTargetExprs: o.Expression[] = [];
usedEvents.forEach((event) => {
if (!event.phase) {
eventAndTargetExprs.push(o.literal(event.name), o.literal(event.target));
}
});
if (eventAndTargetExprs.length) {
const disposableVar = o.variable(`disposable_${compileElement.view.disposables.length}`);
compileElement.view.disposables.push(disposableVar);
compileElement.view.createMethod.addStmt(
disposableVar
.set(o.importExpr(createIdentifier(Identifiers.subscribeToRenderElement)).callFn([
o.THIS_EXPR, compileElement.renderNode, createInlineArray(eventAndTargetExprs),
handleEventExpr(compileElement)
]))
.toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
}
}
function subscribeToDirectiveEvents(
usedEvents: Map<string, EventSummary>, directives: DirectiveAst[],
compileElement: CompileElement) {
const usedEventNames = Array.from(usedEvents.keys());
directives.forEach((dirAst) => {
const dirWrapper = compileElement.directiveWrapperInstance.get(dirAst.directive.type.reference);
compileElement.view.createMethod.addStmts(DirectiveWrapperExpressions.subscribe(
dirAst.directive, dirAst.hostProperties, usedEventNames, dirWrapper, o.THIS_EXPR,
handleEventExpr(compileElement)));
});
}
function generateHandleEventMethod(
boundEvents: BoundEventAst[], directives: DirectiveAst[], compileElement: CompileElement) {
const hasComponentHostListener =
directives.some((dirAst) => dirAst.hostEvents.some((event) => dirAst.directive.isComponent));
const markPathToRootStart = hasComponentHostListener ? compileElement.compViewExpr : o.THIS_EXPR;
const handleEventStmts = new CompileMethod(compileElement.view);
handleEventStmts.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
handleEventStmts.push(markPathToRootStart.callMethod('markPathToRootAsCheckOnce', []).toStmt());
const eventNameVar = o.variable('eventName');
const resultVar = o.variable('result');
handleEventStmts.push(resultVar.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE));
directives.forEach((dirAst, dirIdx) => {
const dirWrapper = compileElement.directiveWrapperInstance.get(dirAst.directive.type.reference);
if (dirAst.hostEvents.length > 0) {
handleEventStmts.push(
resultVar
.set(DirectiveWrapperExpressions
.handleEvent(
dirAst.hostEvents, dirWrapper, eventNameVar, EventHandlerVars.event)
.and(resultVar))
.toStmt());
}
});
boundEvents.forEach((renderEvent, renderEventIdx) => {
const evalResult = convertActionBinding(
compileElement.view, compileElement.view.componentContext, renderEvent.handler,
`sub_${renderEventIdx}`);
const trueStmts = evalResult.stmts;
if (evalResult.allowDefault) {
trueStmts.push(resultVar.set(evalResult.allowDefault.and(resultVar)).toStmt());
}
// TODO(tbosch): convert this into a `switch` once our OutputAst supports it.
handleEventStmts.push(
new o.IfStmt(eventNameVar.equals(o.literal(renderEvent.fullName)), trueStmts));
});
handleEventStmts.push(new o.ReturnStatement(resultVar));
compileElement.view.methods.push(new o.ClassMethod(
getHandleEventMethodName(compileElement.nodeIndex),
[
new o.FnParam(eventNameVar.name, o.STRING_TYPE),
new o.FnParam(EventHandlerVars.event.name, o.DYNAMIC_TYPE)
],
handleEventStmts.finish(), o.BOOL_TYPE));
}
function handleEventExpr(compileElement: CompileElement) {
const handleEventMethodName = getHandleEventMethodName(compileElement.nodeIndex);
return o.THIS_EXPR.callMethod('eventHandler', [o.THIS_EXPR.prop(handleEventMethodName)]);
}
type EventSummary = {
name: string,
target: string,
phase: string
};

View File

@ -1,85 +0,0 @@
/**
* @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 {ɵLifecycleHooks as LifecycleHooks} from '@angular/core';
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
import {isFirstViewCheck} from '../compiler_util/binding_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import * as o from '../output/output_ast';
import {DirectiveAst, ProviderAst, ProviderAstType} from '../template_parser/template_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
export function bindDirectiveAfterContentLifecycleCallbacks(
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
compileElement: CompileElement) {
const view = compileElement.view;
const lifecycleHooks = directiveMeta.type.lifecycleHooks;
const afterContentLifecycleCallbacksMethod = view.afterContentLifecycleCallbacksMethod;
afterContentLifecycleCallbacksMethod.resetDebugInfo(
compileElement.nodeIndex, compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentInit) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(new o.IfStmt(
isFirstViewCheck(o.THIS_EXPR),
[directiveInstance.callMethod('ngAfterContentInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentChecked) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(
directiveInstance.callMethod('ngAfterContentChecked', []).toStmt());
}
}
export function bindDirectiveAfterViewLifecycleCallbacks(
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
compileElement: CompileElement) {
const view = compileElement.view;
const lifecycleHooks = directiveMeta.type.lifecycleHooks;
const afterViewLifecycleCallbacksMethod = view.afterViewLifecycleCallbacksMethod;
afterViewLifecycleCallbacksMethod.resetDebugInfo(
compileElement.nodeIndex, compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewInit) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(new o.IfStmt(
isFirstViewCheck(o.THIS_EXPR),
[directiveInstance.callMethod('ngAfterViewInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewChecked) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(
directiveInstance.callMethod('ngAfterViewChecked', []).toStmt());
}
}
export function bindDirectiveWrapperLifecycleCallbacks(
dir: DirectiveAst, directiveWrapperIntance: o.Expression, compileElement: CompileElement) {
compileElement.view.destroyMethod.addStmts(
DirectiveWrapperExpressions.ngOnDestroy(dir.directive, directiveWrapperIntance));
compileElement.view.detachMethod.addStmts(DirectiveWrapperExpressions.ngOnDetach(
dir.hostProperties, directiveWrapperIntance, o.THIS_EXPR,
compileElement.compViewExpr || o.THIS_EXPR, compileElement.renderNode));
}
export function bindInjectableDestroyLifecycleCallbacks(
provider: ProviderAst, providerInstance: o.Expression, compileElement: CompileElement) {
const onDestroyMethod = compileElement.view.destroyMethod;
onDestroyMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
if (provider.providerType !== ProviderAstType.Directive &&
provider.providerType !== ProviderAstType.Component &&
provider.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
onDestroyMethod.addStmt(providerInstance.callMethod('ngOnDestroy', []).toStmt());
}
}
export function bindPipeDestroyLifecycleCallbacks(
pipeMeta: CompilePipeSummary, pipeInstance: o.Expression, view: CompileView) {
const onDestroyMethod = view.destroyMethod;
if (pipeMeta.type.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
onDestroyMethod.addStmt(pipeInstance.callMethod('ngOnDestroy', []).toStmt());
}
}

View File

@ -1,146 +0,0 @@
/**
* @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 {SecurityContext, ɵisDefaultChangeDetectionStrategy as isDefaultChangeDetectionStrategy} from '@angular/core';
import {createCheckBindingField} from '../compiler_util/binding_util';
import {legacyConvertPropertyBinding} from '../compiler_util/expression_converter';
import {createEnumExpression} from '../compiler_util/identifier_util';
import {createCheckAnimationBindingStmts, createCheckRenderBindingStmt} from '../compiler_util/render_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, PropertyBindingType} from '../template_parser/template_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView} from './compile_view';
import {getHandleEventMethodName} from './util';
export function bindRenderText(
boundText: BoundTextAst, compileNode: CompileNode, view: CompileView): void {
const valueField = createCheckBindingField(view);
const evalResult = legacyConvertPropertyBinding(
view, view, view.componentContext, boundText.value, valueField.bindingId);
if (!evalResult) {
return null;
}
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileNode.nodeIndex, boundText);
view.detectChangesRenderPropertiesMethod.addStmts(evalResult.stmts);
view.detectChangesRenderPropertiesMethod.addStmt(
o.importExpr(createIdentifier(Identifiers.checkRenderText))
.callFn([
o.THIS_EXPR, compileNode.renderNode, valueField.expression,
valueField.expression.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false)
])
.toStmt());
}
export function bindRenderInputs(
boundProps: BoundElementPropertyAst[], boundOutputs: BoundEventAst[], hasEvents: boolean,
compileElement: CompileElement) {
const view = compileElement.view;
const renderNode = compileElement.renderNode;
boundProps.forEach((boundProp) => {
const bindingField = createCheckBindingField(view);
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileElement.nodeIndex, boundProp);
const evalResult = legacyConvertPropertyBinding(
view, view, compileElement.view.componentContext, boundProp.value, bindingField.bindingId);
if (!evalResult) {
return;
}
let compileMethod = view.detectChangesRenderPropertiesMethod;
switch (boundProp.type) {
case PropertyBindingType.Property:
case PropertyBindingType.Attribute:
case PropertyBindingType.Class:
case PropertyBindingType.Style:
compileMethod.addStmts(createCheckRenderBindingStmt(
o.THIS_EXPR, renderNode, boundProp, bindingField.expression, evalResult));
break;
case PropertyBindingType.Animation:
compileMethod = view.animationBindingsMethod;
const {checkUpdateStmts, checkDetachStmts} = createCheckAnimationBindingStmts(
o.THIS_EXPR, o.THIS_EXPR, boundProp, boundOutputs,
(hasEvents ? o.THIS_EXPR.prop(getHandleEventMethodName(compileElement.nodeIndex)) :
o.importExpr(createIdentifier(Identifiers.noop)))
.callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR]),
compileElement.renderNode, bindingField.expression, evalResult);
view.detachMethod.addStmts(checkDetachStmts);
compileMethod.addStmts(checkUpdateStmts);
break;
}
});
}
export function bindDirectiveHostProps(
directiveAst: DirectiveAst, directiveWrapperInstance: o.Expression,
compileElement: CompileElement, elementName: string,
schemaRegistry: ElementSchemaRegistry): void {
// We need to provide the SecurityContext for properties that could need sanitization.
const runtimeSecurityCtxExprs =
directiveAst.hostProperties.filter(boundProp => boundProp.needsRuntimeSecurityContext)
.map((boundProp) => {
let ctx: SecurityContext;
switch (boundProp.type) {
case PropertyBindingType.Property:
ctx = schemaRegistry.securityContext(elementName, boundProp.name, false);
break;
case PropertyBindingType.Attribute:
ctx = schemaRegistry.securityContext(elementName, boundProp.name, true);
break;
default:
throw new Error(
`Illegal state: Only property / attribute bindings can have an unknown security context! Binding ${boundProp.name}`);
}
return createEnumExpression(Identifiers.SecurityContext, ctx);
});
compileElement.view.detectChangesRenderPropertiesMethod.addStmts(
DirectiveWrapperExpressions.checkHost(
directiveAst.hostProperties, directiveWrapperInstance, o.THIS_EXPR,
compileElement.compViewExpr || o.THIS_EXPR, compileElement.renderNode,
runtimeSecurityCtxExprs));
}
export function bindDirectiveInputs(
directiveAst: DirectiveAst, directiveWrapperInstance: o.Expression, dirIndex: number,
compileElement: CompileElement) {
const view = compileElement.view;
const detectChangesInInputsMethod = view.detectChangesInInputsMethod;
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, compileElement.sourceAst);
directiveAst.inputs.forEach((input, inputIdx) => {
// Note: We can't use `fields.length` here, as we are not adding a field!
const bindingId = `${compileElement.nodeIndex}_${dirIndex}_${inputIdx}`;
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, input);
const evalResult =
legacyConvertPropertyBinding(view, view, view.componentContext, input.value, bindingId);
if (!evalResult) {
return;
}
detectChangesInInputsMethod.addStmts(evalResult.stmts);
detectChangesInInputsMethod.addStmt(
directiveWrapperInstance
.callMethod(
`check_${input.directiveName}`,
[o.THIS_EXPR, evalResult.currValExpr, evalResult.forceUpdate || o.literal(false)])
.toStmt());
});
const isOnPushComp = directiveAst.directive.isComponent &&
!isDefaultChangeDetectionStrategy(directiveAst.directive.changeDetection);
const directiveDetectChangesExpr = DirectiveWrapperExpressions.ngDoCheck(
directiveWrapperInstance, o.THIS_EXPR, compileElement.renderNode);
const directiveDetectChangesStmt = isOnPushComp ?
new o.IfStmt(
directiveDetectChangesExpr,
[compileElement.compViewExpr.callMethod('markAsCheckOnce', []).toStmt()]) :
directiveDetectChangesExpr.toStmt();
detectChangesInInputsMethod.addStmt(directiveDetectChangesStmt);
}

View File

@ -1,57 +0,0 @@
/**
* @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 {CompileTokenMetadata, tokenReference} from '../compile_metadata';
import * as o from '../output/output_ast';
import {CompileElement} from './compile_element';
import {CompileQuery} from './compile_query';
// Note: We can't do this when we create the CompileElements already,
// as we create embedded views before the <ng-template> elements themselves.
export function bindQueryValues(ce: CompileElement) {
const queriesWithReads: _QueryWithRead[] = [];
ce.getProviderTokens().forEach((token) => {
const queriesForProvider = ce.getQueriesFor(token);
queriesWithReads.push(...queriesForProvider.map(query => new _QueryWithRead(query, token)));
});
Object.keys(ce.referenceTokens).forEach(varName => {
const varToken = {value: varName};
queriesWithReads.push(
...ce.getQueriesFor(varToken).map(query => new _QueryWithRead(query, varToken)));
});
queriesWithReads.forEach((queryWithRead) => {
let value: o.Expression;
if (queryWithRead.read.identifier) {
// query for an identifier
value = ce.instances.get(tokenReference(queryWithRead.read));
} else {
// query for a reference
const token = ce.referenceTokens[queryWithRead.read.value];
if (token) {
value = ce.instances.get(tokenReference(token));
} else {
value = ce.elementRef;
}
}
if (value) {
queryWithRead.query.addValue(value, ce.view);
}
});
}
class _QueryWithRead {
public read: CompileTokenMetadata;
constructor(public query: CompileQuery, match: CompileTokenMetadata) {
this.read = query.meta.read || match;
}
}

View File

@ -1,75 +0,0 @@
/**
* @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 {ɵViewType as ViewType} from '@angular/core';
import {CompileTokenMetadata} from '../compile_metadata';
import {createDiTokenExpression} from '../compiler_util/identifier_util';
import * as o from '../output/output_ast';
import {CompileView} from './compile_view';
export function getPropertyInView(
property: o.Expression, callingView: CompileView, definedView: CompileView): o.Expression {
if (callingView === definedView) {
return property;
} else {
let viewProp: o.Expression = o.THIS_EXPR;
let currView: CompileView = callingView;
while (currView !== definedView && currView.declarationElement.view) {
currView = currView.declarationElement.view;
viewProp = viewProp.prop('parentView');
}
if (currView !== definedView) {
throw new Error(
`Internal error: Could not calculate a property in a parent view: ${property}`);
}
return property.visitExpression(new _ReplaceViewTransformer(viewProp, definedView), null);
}
}
class _ReplaceViewTransformer extends o.ExpressionTransformer {
constructor(private _viewExpr: o.Expression, private _view: CompileView) { super(); }
private _isThis(expr: o.Expression): boolean {
return expr instanceof o.ReadVarExpr && expr.builtin === o.BuiltinVar.This;
}
visitReadVarExpr(ast: o.ReadVarExpr, context: any): any {
return this._isThis(ast) ? this._viewExpr : ast;
}
visitReadPropExpr(ast: o.ReadPropExpr, context: any): any {
if (this._isThis(ast.receiver)) {
// Note: Don't cast for members of the AppView base class...
if (this._view.fields.some((field) => field.name == ast.name) ||
this._view.getters.some((field) => field.name == ast.name)) {
return this._viewExpr.cast(this._view.classType).prop(ast.name);
}
}
return super.visitReadPropExpr(ast, context);
}
}
export function injectFromViewParentInjector(
view: CompileView, token: CompileTokenMetadata, optional: boolean): o.Expression {
let viewExpr: o.Expression;
if (view.viewType === ViewType.HOST) {
viewExpr = o.THIS_EXPR;
} else {
viewExpr = o.THIS_EXPR.prop('parentView');
}
const args = [createDiTokenExpression(token), o.THIS_EXPR.prop('parentIndex')];
if (optional) {
args.push(o.NULL_EXPR);
}
return viewExpr.callMethod('injectorGet', args);
}
export function getHandleEventMethodName(elementIndex: number): string {
return `handleEvent_${elementIndex}`;
}

View File

@ -1,113 +0,0 @@
/**
* @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 {tokenReference} from '../compile_metadata';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
import {bindOutputs} from './event_binder';
import {bindDirectiveAfterContentLifecycleCallbacks, bindDirectiveAfterViewLifecycleCallbacks, bindDirectiveWrapperLifecycleCallbacks, bindInjectableDestroyLifecycleCallbacks, bindPipeDestroyLifecycleCallbacks} from './lifecycle_binder';
import {bindDirectiveHostProps, bindDirectiveInputs, bindRenderInputs, bindRenderText} from './property_binder';
import {bindQueryValues} from './query_binder';
export function bindView(
view: CompileView, parsedTemplate: TemplateAst[], schemaRegistry: ElementSchemaRegistry): void {
const visitor = new ViewBinderVisitor(view, schemaRegistry);
templateVisitAll(visitor, parsedTemplate);
view.pipes.forEach(
(pipe) => { bindPipeDestroyLifecycleCallbacks(pipe.meta, pipe.instance, pipe.view); });
}
class ViewBinderVisitor implements TemplateAstVisitor {
private _nodeIndex: number = 0;
constructor(public view: CompileView, private _schemaRegistry: ElementSchemaRegistry) {}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
const node = this.view.nodes[this._nodeIndex++];
bindRenderText(ast, node, this.view);
return null;
}
visitText(ast: TextAst, parent: CompileElement): any {
this._nodeIndex++;
return null;
}
visitNgContent(ast: NgContentAst, parent: CompileElement): any { return null; }
visitElement(ast: ElementAst, parent: CompileElement): any {
const compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
bindQueryValues(compileElement);
const hasEvents = bindOutputs(ast.outputs, ast.directives, compileElement, true);
bindRenderInputs(ast.inputs, ast.outputs, hasEvents, compileElement);
ast.directives.forEach((directiveAst, dirIndex) => {
const directiveWrapperInstance =
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
bindDirectiveInputs(directiveAst, directiveWrapperInstance, dirIndex, compileElement);
bindDirectiveHostProps(
directiveAst, directiveWrapperInstance, compileElement, ast.name, this._schemaRegistry);
});
templateVisitAll(this, ast.children, compileElement);
// afterContent and afterView lifecycles need to be called bottom up
// so that children are notified before parents
ast.directives.forEach((directiveAst) => {
const directiveInstance = compileElement.instances.get(directiveAst.directive.type.reference);
const directiveWrapperInstance =
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
bindDirectiveAfterContentLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveAfterViewLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveWrapperLifecycleCallbacks(
directiveAst, directiveWrapperInstance, compileElement);
});
ast.providers.forEach((providerAst) => {
const providerInstance = compileElement.instances.get(tokenReference(providerAst.token));
bindInjectableDestroyLifecycleCallbacks(providerAst, providerInstance, compileElement);
});
return null;
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: CompileElement): any {
const compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
bindQueryValues(compileElement);
bindOutputs(ast.outputs, ast.directives, compileElement, false);
ast.directives.forEach((directiveAst, dirIndex) => {
const directiveInstance = compileElement.instances.get(directiveAst.directive.type.reference);
const directiveWrapperInstance =
compileElement.directiveWrapperInstance.get(directiveAst.directive.type.reference);
bindDirectiveInputs(directiveAst, directiveWrapperInstance, dirIndex, compileElement);
bindDirectiveAfterContentLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveAfterViewLifecycleCallbacks(
directiveAst.directive, directiveInstance, compileElement);
bindDirectiveWrapperLifecycleCallbacks(
directiveAst, directiveWrapperInstance, compileElement);
});
ast.providers.forEach((providerAst) => {
const providerInstance = compileElement.instances.get(tokenReference(providerAst.token));
bindInjectableDestroyLifecycleCallbacks(providerAst, providerInstance, compileElement);
});
bindView(compileElement.embeddedView, ast.children, this._schemaRegistry);
return null;
}
visitAttr(ast: AttrAst, ctx: any): any { return null; }
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
return null;
}
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
visitVariable(ast: VariableAst, ctx: any): any { return null; }
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
}

View File

@ -1,697 +0,0 @@
/**
* @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 {ViewEncapsulation, ɵChangeDetectorStatus as ChangeDetectorStatus, ɵViewType as ViewType, ɵisDefaultChangeDetectionStrategy as isDefaultChangeDetectionStrategy} from '@angular/core';
import {CompileDirectiveSummary, identifierModuleUrl, identifierName} from '../compile_metadata';
import {legacyCreateSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
import {createDiTokenExpression, createInlineArray} from '../compiler_util/identifier_util';
import {isPresent} from '../facade/lang';
import {Identifiers, createIdentifier, identifierToken} from '../identifiers';
import {createClassStmt} from '../output/class_builder';
import * as o from '../output/output_ast';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView, CompileViewRootNode, CompileViewRootNodeType} from './compile_view';
import {ChangeDetectorStatusEnum, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const CLASS_ATTR = 'class';
const STYLE_ATTR = 'style';
const NG_CONTAINER_TAG = 'ng-container';
const parentRenderNodeVar = o.variable('parentRenderNode');
const rootSelectorVar = o.variable('rootSelector');
export function buildView(
view: CompileView, template: TemplateAst[],
targetDependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>):
number {
const builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
const parentEl =
view.declarationElement.isNull() ? view.declarationElement : view.declarationElement.parent;
templateVisitAll(builderVisitor, template, parentEl);
if (view.viewType === ViewType.EMBEDDED || view.viewType === ViewType.HOST) {
view.lastRenderNode = builderVisitor.getOrCreateLastRenderNode();
}
return builderVisitor.nestedViewCount;
}
export function finishView(view: CompileView, targetStatements: o.Statement[]) {
view.nodes.forEach((node) => {
if (node instanceof CompileElement) {
node.finish();
if (node.hasEmbeddedView) {
finishView(node.embeddedView, targetStatements);
}
}
});
view.finish();
createViewTopLevelStmts(view, targetStatements);
}
class ViewBuilderVisitor implements TemplateAstVisitor {
nestedViewCount: number = 0;
constructor(
public view: CompileView,
public targetDependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
private _addRootNodeAndProject(node: CompileNode) {
const projectedNode = _getOuterContainerOrSelf(node);
const parent = projectedNode.parent;
const ngContentIndex = (<any>projectedNode.sourceAst).ngContentIndex;
const viewContainer =
(node instanceof CompileElement && node.hasViewContainer) ? node.viewContainer : null;
if (this._isRootNode(parent)) {
if (this.view.viewType !== ViewType.COMPONENT) {
this.view.rootNodes.push(new CompileViewRootNode(
viewContainer ? CompileViewRootNodeType.ViewContainer : CompileViewRootNodeType.Node,
viewContainer || node.renderNode));
}
} else if (isPresent(parent.component) && isPresent(ngContentIndex)) {
parent.addContentNode(
ngContentIndex,
new CompileViewRootNode(
viewContainer ? CompileViewRootNodeType.ViewContainer : CompileViewRootNodeType.Node,
viewContainer || node.renderNode));
}
}
private _getParentRenderNode(parent: CompileElement): o.Expression {
parent = _getOuterContainerParentOrSelf(parent);
if (this._isRootNode(parent)) {
if (this.view.viewType === ViewType.COMPONENT) {
return parentRenderNodeVar;
} else {
// root node of an embedded/host view
return o.NULL_EXPR;
}
} else {
return isPresent(parent.component) &&
parent.component.template.encapsulation !== ViewEncapsulation.Native ?
o.NULL_EXPR :
parent.renderNode;
}
}
getOrCreateLastRenderNode(): o.Expression {
const view = this.view;
if (view.rootNodes.length === 0 ||
view.rootNodes[view.rootNodes.length - 1].type !== CompileViewRootNodeType.Node) {
const fieldName = `_el_${view.nodes.length}`;
view.fields.push(
new o.ClassField(fieldName, o.importType(view.genConfig.renderTypes.renderElement)));
view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createTemplateAnchor', [o.NULL_EXPR, o.NULL_EXPR]))
.toStmt());
view.rootNodes.push(
new CompileViewRootNode(CompileViewRootNodeType.Node, o.THIS_EXPR.prop(fieldName)));
}
return view.rootNodes[view.rootNodes.length - 1].expr;
}
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
return this._visitText(ast, '', parent);
}
visitText(ast: TextAst, parent: CompileElement): any {
return this._visitText(ast, ast.value, parent);
}
private _visitText(ast: TemplateAst, value: string, parent: CompileElement): o.Expression {
const fieldName = `_text_${this.view.nodes.length}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderText)));
const renderNode = o.THIS_EXPR.prop(fieldName);
const compileNode = new CompileNode(parent, this.view, this.view.nodes.length, renderNode, ast);
const createRenderNode =
o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createText',
[
this._getParentRenderNode(parent), o.literal(value),
this.view.createMethod.resetDebugInfoExpr(this.view.nodes.length, ast)
]))
.toStmt();
this.view.nodes.push(compileNode);
this.view.createMethod.addStmt(createRenderNode);
this._addRootNodeAndProject(compileNode);
return renderNode;
}
visitNgContent(ast: NgContentAst, parent: CompileElement): any {
// the projected nodes originate from a different view, so we don't
// have debug information for them...
this.view.createMethod.resetDebugInfo(null, ast);
const parentRenderNode = this._getParentRenderNode(parent);
if (parentRenderNode !== o.NULL_EXPR) {
this.view.createMethod.addStmt(
o.THIS_EXPR.callMethod('projectNodes', [parentRenderNode, o.literal(ast.index)])
.toStmt());
} else if (this._isRootNode(parent)) {
if (this.view.viewType !== ViewType.COMPONENT) {
// store root nodes only for embedded/host views
this.view.rootNodes.push(
new CompileViewRootNode(CompileViewRootNodeType.NgContent, null, ast.index));
}
} else {
if (isPresent(parent.component) && isPresent(ast.ngContentIndex)) {
parent.addContentNode(
ast.ngContentIndex,
new CompileViewRootNode(CompileViewRootNodeType.NgContent, null, ast.index));
}
}
return null;
}
visitElement(ast: ElementAst, parent: CompileElement): any {
const nodeIndex = this.view.nodes.length;
let createRenderNodeExpr: o.Expression;
const debugContextExpr = this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast);
const directives = ast.directives.map(directiveAst => directiveAst.directive);
const component = directives.find(directive => directive.isComponent);
if (ast.name === NG_CONTAINER_TAG) {
createRenderNodeExpr = ViewProperties.renderer.callMethod(
'createTemplateAnchor', [this._getParentRenderNode(parent), debugContextExpr]);
} else {
const htmlAttrs = _readHtmlAttrs(ast.attrs);
const attrNameAndValues = createInlineArray(
_mergeHtmlAndDirectiveAttrs(htmlAttrs, directives).map(v => o.literal(v)));
if (nodeIndex === 0 && this.view.viewType === ViewType.HOST) {
createRenderNodeExpr =
o.importExpr(createIdentifier(Identifiers.selectOrCreateRenderHostElement)).callFn([
ViewProperties.renderer, o.literal(ast.name), attrNameAndValues, rootSelectorVar,
debugContextExpr
]);
} else {
createRenderNodeExpr =
o.importExpr(createIdentifier(Identifiers.createRenderElement)).callFn([
ViewProperties.renderer, this._getParentRenderNode(parent), o.literal(ast.name),
attrNameAndValues, debugContextExpr
]);
}
}
const fieldName = `_el_${nodeIndex}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement)));
this.view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt());
const renderNode = o.THIS_EXPR.prop(fieldName);
const compileElement = new CompileElement(
parent, this.view, nodeIndex, renderNode, ast, component, directives, ast.providers,
ast.hasViewContainer, false, ast.references);
this.view.nodes.push(compileElement);
let compViewExpr: o.ReadPropExpr = null;
if (isPresent(component)) {
this.targetDependencies.push(new ComponentViewDependency(component.type.reference));
compViewExpr = o.THIS_EXPR.prop(`compView_${nodeIndex}`); // fix highlighting: `
this.view.fields.push(new o.ClassField(
compViewExpr.name,
o.importType(createIdentifier(Identifiers.AppView), [o.importType(component.type)])));
this.view.viewChildren.push(compViewExpr);
compileElement.setComponentView(compViewExpr);
this.view.createMethod.addStmt(
compViewExpr
.set(o.importExpr({reference: component.componentViewType}).instantiate([
ViewProperties.viewUtils, o.THIS_EXPR, o.literal(nodeIndex), renderNode
]))
.toStmt());
}
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement);
templateVisitAll(this, ast.children, compileElement);
compileElement.afterChildren(this.view.nodes.length - nodeIndex - 1);
if (isPresent(compViewExpr)) {
this.view.createMethod.addStmt(
compViewExpr.callMethod('create', [compileElement.getComponent()]).toStmt());
}
return null;
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: CompileElement): any {
const nodeIndex = this.view.nodes.length;
const fieldName = `_anchor_${nodeIndex}`;
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment)));
this.view.createMethod.addStmt(
o.THIS_EXPR.prop(fieldName)
.set(ViewProperties.renderer.callMethod(
'createTemplateAnchor',
[
this._getParentRenderNode(parent),
this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
]))
.toStmt());
const renderNode = o.THIS_EXPR.prop(fieldName);
const templateVariableBindings = ast.variables.map(
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
const directives = ast.directives.map(directiveAst => directiveAst.directive);
const compileElement = new CompileElement(
parent, this.view, nodeIndex, renderNode, ast, null, directives, ast.providers,
ast.hasViewContainer, true, ast.references);
this.view.nodes.push(compileElement);
this.nestedViewCount++;
const embeddedView = new CompileView(
this.view.component, this.view.genConfig, this.view.pipeMetas, o.NULL_EXPR,
this.view.animations, this.view.viewIndex + this.nestedViewCount, compileElement,
templateVariableBindings, this.targetDependencies);
this.nestedViewCount += buildView(embeddedView, ast.children, this.targetDependencies);
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement);
compileElement.afterChildren(0);
return null;
}
visitAttr(ast: AttrAst, ctx: any): any { return null; }
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
return null;
}
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
visitVariable(ast: VariableAst, ctx: any): any { return null; }
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
}
/**
* Walks up the nodes while the direct parent is a container.
*
* Returns the outer container or the node itself when it is not a direct child of a container.
*
* @internal
*/
function _getOuterContainerOrSelf(node: CompileNode): CompileNode {
const view = node.view;
while (_isNgContainer(node.parent, view)) {
node = node.parent;
}
return node;
}
/**
* Walks up the nodes while they are container and returns the first parent which is not.
*
* Returns the parent of the outer container or the node itself when it is not a container.
*
* @internal
*/
function _getOuterContainerParentOrSelf(el: CompileElement): CompileElement {
const view = el.view;
while (_isNgContainer(el, view)) {
el = el.parent;
}
return el;
}
function _isNgContainer(node: CompileNode, view: CompileView): boolean {
return !node.isNull() && (<ElementAst>node.sourceAst).name === NG_CONTAINER_TAG &&
node.view === view;
}
function _mergeHtmlAndDirectiveAttrs(
declaredHtmlAttrs: {[key: string]: string}, directives: CompileDirectiveSummary[]): string[] {
const mapResult: {[key: string]: string} = {};
Object.keys(declaredHtmlAttrs).forEach(key => { mapResult[key] = declaredHtmlAttrs[key]; });
directives.forEach(directiveMeta => {
Object.keys(directiveMeta.hostAttributes).forEach(name => {
const value = directiveMeta.hostAttributes[name];
const prevValue = mapResult[name];
mapResult[name] = isPresent(prevValue) ? mergeAttributeValue(name, prevValue, value) : value;
});
});
const arrResult: string[] = [];
// Note: We need to sort to get a defined output order
// for tests and for caching generated artifacts...
Object.keys(mapResult).sort().forEach(
(attrName) => { arrResult.push(attrName, mapResult[attrName]); });
return arrResult;
}
function _readHtmlAttrs(attrs: AttrAst[]): {[key: string]: string} {
const htmlAttrs: {[key: string]: string} = {};
attrs.forEach((ast) => { htmlAttrs[ast.name] = ast.value; });
return htmlAttrs;
}
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
return `${attrValue1} ${attrValue2}`;
} else {
return attrValue2;
}
}
function createViewTopLevelStmts(view: CompileView, targetStatements: o.Statement[]) {
let nodeDebugInfosVar: o.Expression = o.NULL_EXPR;
if (view.genConfig.genDebugInfo) {
nodeDebugInfosVar = o.variable(
`nodeDebugInfos_${identifierName(view.component.type)}${view.viewIndex}`); // fix
// highlighting:
// `
targetStatements.push(
(<o.ReadVarExpr>nodeDebugInfosVar)
.set(o.literalArr(
view.nodes.map(createStaticNodeDebugInfo),
new o.ArrayType(
o.importType(createIdentifier(Identifiers.StaticNodeDebugInfo)),
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
}
const renderCompTypeVar: o.ReadVarExpr =
o.variable(view.rendererTypeName); // fix highlighting: `
if (view.viewIndex === 0) {
let templateUrlInfo: string;
if (view.component.template.templateUrl == identifierModuleUrl(view.component.type)) {
templateUrlInfo =
`${identifierModuleUrl(view.component.type)} class ${identifierName(view.component.type)} - inline template`;
} else {
templateUrlInfo = view.component.template.templateUrl;
}
targetStatements.push(
renderCompTypeVar
.set(o.importExpr(createIdentifier(Identifiers.createRenderComponentType)).callFn([
view.genConfig.genDebugInfo ? o.literal(templateUrlInfo) : o.literal(''),
o.literal(view.component.template.ngContentSelectors.length),
ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
view.styles,
o.literalMap(
view.animations.map((entry): [string, o.Expression] => [entry.name, entry.fnExp]),
null, true),
]))
.toDeclStmt(o.importType(createIdentifier(Identifiers.RenderComponentType))));
}
const viewClass = createViewClass(view, renderCompTypeVar, nodeDebugInfosVar);
targetStatements.push(viewClass);
}
function createStaticNodeDebugInfo(node: CompileNode): o.Expression {
const compileElement = node instanceof CompileElement ? node : null;
let providerTokens: o.Expression[] = [];
let componentToken: o.Expression = o.NULL_EXPR;
const varTokenEntries: any[] = [];
if (isPresent(compileElement)) {
providerTokens =
compileElement.getProviderTokens().map((token) => createDiTokenExpression(token));
if (isPresent(compileElement.component)) {
componentToken = createDiTokenExpression(identifierToken(compileElement.component.type));
}
Object.keys(compileElement.referenceTokens).forEach(varName => {
const token = compileElement.referenceTokens[varName];
varTokenEntries.push(
[varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
});
}
return o.importExpr(createIdentifier(Identifiers.StaticNodeDebugInfo))
.instantiate(
[
o.literalArr(providerTokens, new o.ArrayType(o.DYNAMIC_TYPE, [o.TypeModifier.Const])),
componentToken,
o.literalMap(varTokenEntries, new o.MapType(o.DYNAMIC_TYPE, [o.TypeModifier.Const]))
],
o.importType(
createIdentifier(Identifiers.StaticNodeDebugInfo), null, [o.TypeModifier.Const]));
}
function createViewClass(
view: CompileView, renderCompTypeVar: o.ReadVarExpr,
nodeDebugInfosVar: o.Expression): o.ClassStmt {
const viewConstructorArgs = [
new o.FnParam(
ViewConstructorVars.viewUtils.name, o.importType(createIdentifier(Identifiers.ViewUtils))),
new o.FnParam(
ViewConstructorVars.parentView.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(ViewConstructorVars.parentIndex.name, o.NUMBER_TYPE),
new o.FnParam(ViewConstructorVars.parentElement.name, o.DYNAMIC_TYPE)
];
const superConstructorArgs = [
o.variable(view.className), renderCompTypeVar, ViewTypeEnum.fromValue(view.viewType),
ViewConstructorVars.viewUtils, ViewConstructorVars.parentView, ViewConstructorVars.parentIndex,
ViewConstructorVars.parentElement,
ChangeDetectorStatusEnum.fromValue(getChangeDetectionMode(view))
];
if (view.genConfig.genDebugInfo) {
superConstructorArgs.push(nodeDebugInfosVar);
}
if (view.viewType === ViewType.EMBEDDED) {
viewConstructorArgs.push(new o.FnParam(
'declaredViewContainer', o.importType(createIdentifier(Identifiers.ViewContainer))));
superConstructorArgs.push(o.variable('declaredViewContainer'));
}
const viewMethods = [
new o.ClassMethod(
'createInternal', [new o.FnParam(rootSelectorVar.name, o.STRING_TYPE)],
generateCreateMethod(view),
o.importType(createIdentifier(Identifiers.ComponentRef), [o.DYNAMIC_TYPE])),
new o.ClassMethod(
'injectorGetInternal',
[
new o.FnParam(InjectMethodVars.token.name, o.DYNAMIC_TYPE),
// Note: Can't use o.INT_TYPE here as the method in AppView uses number
new o.FnParam(InjectMethodVars.requestNodeIndex.name, o.NUMBER_TYPE),
new o.FnParam(InjectMethodVars.notFoundResult.name, o.DYNAMIC_TYPE)
],
addReturnValuefNotEmpty(view.injectorGetMethod.finish(), InjectMethodVars.notFoundResult),
o.DYNAMIC_TYPE),
new o.ClassMethod('detectChangesInternal', [], generateDetectChangesMethod(view)),
new o.ClassMethod('dirtyParentQueriesInternal', [], view.dirtyParentQueriesMethod.finish()),
new o.ClassMethod('destroyInternal', [], generateDestroyMethod(view)),
new o.ClassMethod('detachInternal', [], view.detachMethod.finish()),
generateVisitRootNodesMethod(view), generateVisitProjectableNodesMethod(view),
generateCreateEmbeddedViewsMethod(view)
].filter((method) => method.body.length > 0);
const superClass = view.genConfig.genDebugInfo ? Identifiers.DebugAppView : Identifiers.AppView;
const viewClass = createClassStmt({
name: view.className,
parent: o.importExpr(createIdentifier(superClass), [getContextType(view)]),
parentArgs: superConstructorArgs,
ctorParams: viewConstructorArgs,
builders: [{methods: viewMethods}, view]
});
return viewClass;
}
function generateDestroyMethod(view: CompileView): o.Statement[] {
const stmts: o.Statement[] = [];
view.viewContainers.forEach((viewContainer) => {
stmts.push(viewContainer.callMethod('destroyNestedViews', []).toStmt());
});
view.viewChildren.forEach(
(viewChild) => { stmts.push(viewChild.callMethod('destroy', []).toStmt()); });
stmts.push(...view.destroyMethod.finish());
return stmts;
}
function generateCreateMethod(view: CompileView): o.Statement[] {
let parentRenderNodeExpr: o.Expression = o.NULL_EXPR;
let parentRenderNodeStmts: any[] = [];
if (view.viewType === ViewType.COMPONENT) {
parentRenderNodeExpr =
ViewProperties.renderer.callMethod('createViewRoot', [o.THIS_EXPR.prop('parentElement')]);
parentRenderNodeStmts =
[parentRenderNodeVar.set(parentRenderNodeExpr)
.toDeclStmt(
o.importType(view.genConfig.renderTypes.renderNode), [o.StmtModifier.Final])];
}
let resultExpr: o.Expression;
if (view.viewType === ViewType.HOST) {
const hostEl = <CompileElement>view.nodes[0];
resultExpr =
o.importExpr(createIdentifier(Identifiers.ComponentRef_), [o.DYNAMIC_TYPE]).instantiate([
o.literal(hostEl.nodeIndex), o.THIS_EXPR, hostEl.renderNode, hostEl.getComponent()
]);
} else {
resultExpr = o.NULL_EXPR;
}
const allNodesExpr: o.Expression =
ViewProperties.renderer.cast(o.DYNAMIC_TYPE)
.prop('directRenderer')
.conditional(o.NULL_EXPR, o.literalArr(view.nodes.map(node => node.renderNode)));
return parentRenderNodeStmts.concat(view.createMethod.finish(), [
o.THIS_EXPR
.callMethod(
'init',
[
view.lastRenderNode,
allNodesExpr,
view.disposables.length ? o.literalArr(view.disposables) : o.NULL_EXPR,
])
.toStmt(),
new o.ReturnStatement(resultExpr)
]);
}
function generateDetectChangesMethod(view: CompileView): o.Statement[] {
const stmts: any[] = [];
if (view.animationBindingsMethod.isEmpty() && view.detectChangesInInputsMethod.isEmpty() &&
view.updateContentQueriesMethod.isEmpty() &&
view.afterContentLifecycleCallbacksMethod.isEmpty() &&
view.detectChangesRenderPropertiesMethod.isEmpty() &&
view.updateViewQueriesMethod.isEmpty() && view.afterViewLifecycleCallbacksMethod.isEmpty() &&
view.viewContainers.length === 0 && view.viewChildren.length === 0) {
return stmts;
}
stmts.push(...view.animationBindingsMethod.finish());
stmts.push(...view.detectChangesInInputsMethod.finish());
view.viewContainers.forEach((viewContainer) => {
stmts.push(
viewContainer.callMethod('detectChangesInNestedViews', [ViewProperties.throwOnChange])
.toStmt());
});
const afterContentStmts = view.updateContentQueriesMethod.finish().concat(
view.afterContentLifecycleCallbacksMethod.finish());
if (afterContentStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(ViewProperties.throwOnChange), afterContentStmts));
}
stmts.push(...view.detectChangesRenderPropertiesMethod.finish());
view.viewChildren.forEach((viewChild) => {
stmts.push(
viewChild.callMethod('internalDetectChanges', [ViewProperties.throwOnChange]).toStmt());
});
const afterViewStmts =
view.updateViewQueriesMethod.finish().concat(view.afterViewLifecycleCallbacksMethod.finish());
if (afterViewStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(ViewProperties.throwOnChange), afterViewStmts));
}
const varStmts = legacyCreateSharedBindingVariablesIfNeeded(stmts);
return varStmts.concat(stmts);
}
function addReturnValuefNotEmpty(statements: o.Statement[], value: o.Expression): o.Statement[] {
if (statements.length > 0) {
return statements.concat([new o.ReturnStatement(value)]);
} else {
return statements;
}
}
function getContextType(view: CompileView): o.Type {
if (view.viewType === ViewType.COMPONENT) {
return o.importType(view.component.type);
}
return o.DYNAMIC_TYPE;
}
function getChangeDetectionMode(view: CompileView): ChangeDetectorStatus {
let mode: ChangeDetectorStatus;
if (view.viewType === ViewType.COMPONENT) {
mode = isDefaultChangeDetectionStrategy(view.component.changeDetection) ?
ChangeDetectorStatus.CheckAlways :
ChangeDetectorStatus.CheckOnce;
} else {
mode = ChangeDetectorStatus.CheckAlways;
}
return mode;
}
function generateVisitRootNodesMethod(view: CompileView): o.ClassMethod {
const cbVar = o.variable('cb');
const ctxVar = o.variable('ctx');
const stmts: o.Statement[] = generateVisitNodesStmts(view.rootNodes, cbVar, ctxVar);
return new o.ClassMethod(
'visitRootNodesInternal',
[new o.FnParam(cbVar.name, o.DYNAMIC_TYPE), new o.FnParam(ctxVar.name, o.DYNAMIC_TYPE)],
stmts);
}
function generateVisitProjectableNodesMethod(view: CompileView): o.ClassMethod {
const nodeIndexVar = o.variable('nodeIndex');
const ngContentIndexVar = o.variable('ngContentIndex');
const cbVar = o.variable('cb');
const ctxVar = o.variable('ctx');
const stmts: o.Statement[] = [];
view.nodes.forEach((node) => {
if (node instanceof CompileElement && node.component) {
node.contentNodesByNgContentIndex.forEach((projectedNodes, ngContentIndex) => {
stmts.push(new o.IfStmt(
nodeIndexVar.equals(o.literal(node.nodeIndex))
.and(ngContentIndexVar.equals(o.literal(ngContentIndex))),
generateVisitNodesStmts(projectedNodes, cbVar, ctxVar)));
});
}
});
return new o.ClassMethod(
'visitProjectableNodesInternal',
[
new o.FnParam(nodeIndexVar.name, o.NUMBER_TYPE),
new o.FnParam(ngContentIndexVar.name, o.NUMBER_TYPE),
new o.FnParam(cbVar.name, o.DYNAMIC_TYPE), new o.FnParam(ctxVar.name, o.DYNAMIC_TYPE)
],
stmts);
}
function generateVisitNodesStmts(
nodes: CompileViewRootNode[], cb: o.Expression, ctx: o.Expression): o.Statement[] {
const stmts: o.Statement[] = [];
nodes.forEach((node) => {
switch (node.type) {
case CompileViewRootNodeType.Node:
stmts.push(cb.callFn([node.expr, ctx]).toStmt());
break;
case CompileViewRootNodeType.ViewContainer:
stmts.push(cb.callFn([node.expr.prop('nativeElement'), ctx]).toStmt());
stmts.push(node.expr.callMethod('visitNestedViewRootNodes', [cb, ctx]).toStmt());
break;
case CompileViewRootNodeType.NgContent:
stmts.push(
o.THIS_EXPR.callMethod('visitProjectedNodes', [o.literal(node.ngContentIndex), cb, ctx])
.toStmt());
break;
}
});
return stmts;
}
function generateCreateEmbeddedViewsMethod(view: CompileView): o.ClassMethod {
const nodeIndexVar = o.variable('nodeIndex');
const stmts: o.Statement[] = [];
view.nodes.forEach((node) => {
if (node instanceof CompileElement) {
if (node.embeddedView) {
stmts.push(new o.IfStmt(
nodeIndexVar.equals(o.literal(node.nodeIndex)),
[new o.ReturnStatement(node.embeddedView.classExpr.instantiate([
ViewProperties.viewUtils, o.THIS_EXPR, o.literal(node.nodeIndex), node.renderNode,
node.viewContainer
]))]));
}
}
});
if (stmts.length > 0) {
stmts.push(new o.ReturnStatement(o.NULL_EXPR));
}
return new o.ClassMethod(
'createEmbeddedViewInternal', [new o.FnParam(nodeIndexVar.name, o.NUMBER_TYPE)], stmts,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE]));
}

File diff suppressed because it is too large Load Diff