feat(core): add @Component.precompile and ComponentFactoryResolver

Part to #9467
Closes #9543
This commit is contained in:
Tobias Bosch
2016-06-22 14:06:23 -07:00
parent 9ed8f2d26e
commit 6c5b653593
23 changed files with 419 additions and 110 deletions

View File

@ -91,6 +91,28 @@ export class CompileElement extends CompileNode {
this._instances.add(identifierToken(Identifiers.AppElement), this.appElement);
}
public createComponentFactoryResolver(precompileComponent: CompileIdentifierMetadata[]) {
if (!precompileComponent || precompileComponent.length === 0) {
return;
}
var createComponentFactoryResolverExpr =
o.importExpr(Identifiers.CodegenComponentFactoryResolver).instantiate([
o.literalArr(precompileComponent.map(
(precompiledComponent) => o.importExpr(precompiledComponent))),
injectFromViewParentInjector(identifierToken(Identifiers.ComponentFactoryResolver), false)
]);
var provider = new CompileProviderMetadata({
token: identifierToken(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 =
@ -167,21 +189,20 @@ export class CompileElement extends CompileNode {
queriesWithReads,
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
});
StringMapWrapper.forEach(
this.referenceTokens, (_: any /** TODO #9100 */, varName: any /** TODO #9100 */) => {
var token = this.referenceTokens[varName];
var varValue: any /** TODO #9100 */;
if (isPresent(token)) {
varValue = this._instances.get(token);
} else {
varValue = this.renderNode;
}
this.view.locals.set(varName, varValue);
var varToken = new CompileTokenMetadata({value: varName});
ListWrapper.addAll(
queriesWithReads,
this._getQueriesFor(varToken).map(query => new _QueryWithRead(query, varToken)));
});
StringMapWrapper.forEach(this.referenceTokens, (_: CompileTokenMetadata, varName: string) => {
var token = this.referenceTokens[varName];
var varValue: o.Expression;
if (isPresent(token)) {
varValue = this._instances.get(token);
} else {
varValue = this.renderNode;
}
this.view.locals.set(varName, varValue);
var varToken = new CompileTokenMetadata({value: varName});
ListWrapper.addAll(
queriesWithReads,
this._getQueriesFor(varToken).map(query => new _QueryWithRead(query, varToken)));
});
queriesWithReads.forEach((queryWithRead) => {
var value: o.Expression;
if (isPresent(queryWithRead.read.identifier)) {
@ -285,7 +306,7 @@ export class CompileElement extends CompileNode {
private _getLocalDependency(
requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata): o.Expression {
var result: any /** TODO #9100 */ = null;
var result: o.Expression = null;
// constructor content query
if (isBlank(result) && isPresent(dep.query)) {
result = this._addQuery(dep.query, null).queryList;
@ -330,7 +351,7 @@ export class CompileElement extends CompileNode {
private _getDependency(requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata):
o.Expression {
var currElement: CompileElement = this;
var result: any /** TODO #9100 */ = null;
var result: o.Expression = null;
if (dep.isValue) {
result = o.literal(dep.value);
}
@ -357,7 +378,7 @@ export class CompileElement extends CompileNode {
function createInjectInternalCondition(
nodeIndex: number, childNodeCount: number, provider: ProviderAst,
providerExpr: o.Expression): o.Statement {
var indexCondition: any /** TODO #9100 */;
var indexCondition: o.Expression;
if (childNodeCount > 0) {
indexCondition = o.literal(nodeIndex)
.lowerEquals(InjectMethodVars.requestNodeIndex)
@ -375,8 +396,8 @@ function createProviderProperty(
propName: string, provider: ProviderAst, providerValueExpressions: o.Expression[],
isMulti: boolean, isEager: boolean, compileElement: CompileElement): o.Expression {
var view = compileElement.view;
var resolvedProviderValueExpr: any /** TODO #9100 */;
var type: any /** TODO #9100 */;
var resolvedProviderValueExpr: o.Expression;
var type: o.Type;
if (isMulti) {
resolvedProviderValueExpr = o.literalArr(providerValueExpressions);
type = new o.ArrayType(o.DYNAMIC_TYPE);
@ -421,8 +442,8 @@ class _ValueOutputAstTransformer extends ValueTransformer {
return o.literalArr(arr.map(value => visitValue(value, this, context)));
}
visitStringMap(map: {[key: string]: any}, context: any): o.Expression {
var entries: any[] /** TODO #9100 */ = [];
StringMapWrapper.forEach(map, (value: any /** TODO #9100 */, key: any /** TODO #9100 */) => {
var entries: Array<string|o.Expression>[] = [];
StringMapWrapper.forEach(map, (value: any, key: string) => {
entries.push([key, visitValue(value, this, context)]);
});
return o.literalMap(entries);

View File

@ -9,22 +9,18 @@
import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {ViewType, isDefaultChangeDetectionStrategy} from '../../core_private';
import {AnimationCompiler} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata, CompileTypeMetadata} from '../compile_metadata';
import {ListWrapper, SetWrapper, StringMapWrapper} from '../facade/collection';
import {StringWrapper, isPresent} from '../facade/lang';
import {Identifiers, identifierToken} from '../identifiers';
import * as o from '../output/output_ast';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ProviderAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView} from './compile_view';
import {ChangeDetectionStrategyEnum, DetectChangesVars, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
import {TemplateAst, TemplateAstVisitor, NgContentAst, EmbeddedTemplateAst, ElementAst, ReferenceAst, VariableAst, BoundEventAst, BoundElementPropertyAst, AttrAst, BoundTextAst, TextAst, DirectiveAst, BoundDirectivePropertyAst, templateVisitAll,} from '../template_ast';
import {getViewFactoryName, createFlatArray, createDiTokenExpression} from './util';
import {CompileIdentifierMetadata, CompileDirectiveMetadata, CompileTokenMetadata} from '../compile_metadata';
import {AnimationCompiler} from '../animation/animation_compiler';
import {createDiTokenExpression, createFlatArray, getViewFactoryName} from './util';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const CLASS_ATTR = 'class';
@ -34,15 +30,20 @@ const NG_CONTAINER_TAG = 'ng-container';
var parentRenderNodeVar = o.variable('parentRenderNode');
var rootSelectorVar = o.variable('rootSelector');
export class ViewCompileDependency {
export class ViewFactoryDependency {
constructor(
public comp: CompileDirectiveMetadata, public factoryPlaceholder: CompileIdentifierMetadata) {
}
public comp: CompileDirectiveMetadata, public placeholder: CompileIdentifierMetadata) {}
}
export class ComponentFactoryDependency {
constructor(
public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
}
export function buildView(
view: CompileView, template: TemplateAst[],
targetDependencies: ViewCompileDependency[]): number {
targetDependencies: Array<ViewFactoryDependency|ComponentFactoryDependency>): number {
var builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
templateVisitAll(
builderVisitor, template,
@ -65,7 +66,9 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
private _animationCompiler = new AnimationCompiler();
constructor(public view: CompileView, public targetDependencies: ViewCompileDependency[]) {}
constructor(
public view: CompileView,
public targetDependencies: Array<ViewFactoryDependency|ComponentFactoryDependency>) {}
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
@ -203,9 +206,17 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
this.view.nodes.push(compileElement);
var compViewExpr: o.ReadVarExpr = null;
if (isPresent(component)) {
var nestedComponentIdentifier =
let nestedComponentIdentifier =
new CompileIdentifierMetadata({name: getViewFactoryName(component, 0)});
this.targetDependencies.push(new ViewCompileDependency(component, nestedComponentIdentifier));
this.targetDependencies.push(new ViewFactoryDependency(component, nestedComponentIdentifier));
let precompileComponentIdentifiers =
component.precompile.map((precompileComp: CompileIdentifierMetadata) => {
var id = new CompileIdentifierMetadata({name: precompileComp.name});
this.targetDependencies.push(new ComponentFactoryDependency(precompileComp, id));
return id;
});
compileElement.createComponentFactoryResolver(precompileComponentIdentifiers);
compViewExpr = o.variable(`compView_${nodeIndex}`); // fix highlighting: `
compileElement.setComponentView(compViewExpr);
this.view.createMethod.addStmt(

View File

@ -17,12 +17,14 @@ import {TemplateAst} from '../template_ast';
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
import {bindView} from './view_binder';
import {ViewCompileDependency, buildView, finishView} from './view_builder';
import {ComponentFactoryDependency, ViewFactoryDependency, buildView, finishView} from './view_builder';
export {ComponentFactoryDependency, ViewFactoryDependency} from './view_builder';
export class ViewCompileResult {
constructor(
public statements: o.Statement[], public viewFactoryVar: string,
public dependencies: ViewCompileDependency[]) {}
public dependencies: Array<ViewFactoryDependency|ComponentFactoryDependency>) {}
}
@Injectable()
@ -33,9 +35,9 @@ export class ViewCompiler {
compileComponent(
component: CompileDirectiveMetadata, template: TemplateAst[], styles: o.Expression,
pipes: CompilePipeMetadata[]): ViewCompileResult {
var dependencies: any[] /** TODO #9100 */ = [];
var dependencies: Array<ViewFactoryDependency|ComponentFactoryDependency> = [];
var compiledAnimations = this._animationCompiler.compileComponent(component);
var statements: any[] /** TODO #9100 */ = [];
var statements: o.Statement[] = [];
compiledAnimations.map(entry => {
statements.push(entry.statesMapStatement);
statements.push(entry.fnStatement);