feat(core): introduce @AppModule

Main part for #9726
Closes #9730
This commit is contained in:
Tobias Bosch
2016-06-28 09:54:42 -07:00
parent 1608d91728
commit 17e4cfc748
52 changed files with 2085 additions and 851 deletions

View File

@ -0,0 +1,215 @@
/**
* @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 {Injectable} from '@angular/core';
import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
import {isBlank, isPresent} from './facade/lang';
import {Identifiers, identifierToken} from './identifiers';
import * as o from './output/output_ast';
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
import {AppModuleProviderParser} from './provider_parser';
import {ProviderAst, ProviderAstType} from './template_ast';
import {createDiTokenExpression} from './util';
export class ComponentFactoryDependency {
constructor(
public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
}
export class AppModuleCompileResult {
constructor(
public statements: o.Statement[], public appModuleFactoryVar: string,
public dependencies: ComponentFactoryDependency[]) {}
}
@Injectable()
export class AppModuleCompiler {
compile(appModuleMeta: CompileAppModuleMetadata): AppModuleCompileResult {
var sourceFileName = isPresent(appModuleMeta.type.moduleUrl) ?
`in AppModule ${appModuleMeta.type.name} in ${appModuleMeta.type.moduleUrl}` :
`in AppModule ${appModuleMeta.type.name}`;
var sourceFile = new ParseSourceFile('', sourceFileName);
var sourceSpan = new ParseSourceSpan(
new ParseLocation(sourceFile, null, null, null),
new ParseLocation(sourceFile, null, null, null));
var deps: ComponentFactoryDependency[] = [];
var precompileComponents = appModuleMeta.precompile.map((precompileComp) => {
var id = new CompileIdentifierMetadata({name: precompileComp.name});
deps.push(new ComponentFactoryDependency(precompileComp, id));
return id;
});
var builder = new _InjectorBuilder(appModuleMeta, precompileComponents, sourceSpan);
var providerParser = new AppModuleProviderParser(appModuleMeta, sourceSpan);
providerParser.parse().forEach((provider) => builder.addProvider(provider));
var injectorClass = builder.build();
var appModuleFactoryVar = `${appModuleMeta.type.name}NgFactory`;
var appModuleFactoryStmt =
o.variable(appModuleFactoryVar)
.set(o.importExpr(Identifiers.AppModuleFactory)
.instantiate(
[o.variable(injectorClass.name), o.importExpr(appModuleMeta.type)],
o.importType(
Identifiers.AppModuleFactory, [o.importType(appModuleMeta.type)],
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]);
return new AppModuleCompileResult(
[injectorClass, appModuleFactoryStmt], appModuleFactoryVar, deps);
}
}
class _InjectorBuilder {
private _instances = new CompileTokenMap<o.Expression>();
private _fields: o.ClassField[] = [];
private _createStmts: o.Statement[] = [];
private _getters: o.ClassGetter[] = [];
constructor(
private _appModuleMeta: CompileAppModuleMetadata,
private _precompileComponents: CompileIdentifierMetadata[],
private _sourceSpan: ParseSourceSpan) {}
addProvider(resolvedProvider: ProviderAst) {
var providerValueExpressions =
resolvedProvider.providers.map((provider) => this._getProviderValue(provider));
var propName = `_${resolvedProvider.token.name}_${this._instances.size}`;
var instance = this._createProviderProperty(
propName, resolvedProvider, providerValueExpressions, resolvedProvider.multiProvider,
resolvedProvider.eager);
this._instances.add(resolvedProvider.token, instance);
}
build(): o.ClassStmt {
let getMethodStmts: o.Statement[] = this._instances.keys().map((token) => {
var providerExpr = this._instances.get(token);
return new o.IfStmt(
InjectMethodVars.token.identical(createDiTokenExpression(token)),
[new o.ReturnStatement(providerExpr)]);
});
var methods = [
new o.ClassMethod(
'createInternal', [], this._createStmts.concat(
new o.ReturnStatement(this._instances.get(identifierToken(this._appModuleMeta.type)))
), o.importType(this._appModuleMeta.type)
),
new o.ClassMethod(
'getInternal',
[
new o.FnParam(InjectMethodVars.token.name, o.DYNAMIC_TYPE),
new o.FnParam(InjectMethodVars.notFoundResult.name, o.DYNAMIC_TYPE)
],
getMethodStmts.concat([new o.ReturnStatement(InjectMethodVars.notFoundResult)]),
o.DYNAMIC_TYPE)
];
var ctor = new o.ClassMethod(
null, [new o.FnParam(InjectorProps.parent.name, o.importType(Identifiers.Injector))],
[o.SUPER_EXPR
.callFn([
o.variable(InjectorProps.parent.name),
o.literalArr(this._precompileComponents.map(
(precompiledComponent) => o.importExpr(precompiledComponent)))
])
.toStmt()]);
var injClassName = `${this._appModuleMeta.type.name}Injector`;
return new o.ClassStmt(
injClassName,
o.importExpr(Identifiers.AppModuleInjector, [o.importType(this._appModuleMeta.type)]),
this._fields, this._getters, ctor, methods);
}
private _getProviderValue(provider: CompileProviderMetadata): o.Expression {
var result: o.Expression;
if (isPresent(provider.useExisting)) {
result = this._getDependency(new CompileDiDependencyMetadata({token: provider.useExisting}));
} else if (isPresent(provider.useFactory)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useFactory.diDeps;
var depsExpr = deps.map((dep) => this._getDependency(dep));
result = o.importExpr(provider.useFactory).callFn(depsExpr);
} else if (isPresent(provider.useClass)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useClass.diDeps;
var depsExpr = deps.map((dep) => this._getDependency(dep));
result =
o.importExpr(provider.useClass).instantiate(depsExpr, o.importType(provider.useClass));
} else {
result = o.literal(provider.useValue);
}
return result;
}
private _createProviderProperty(
propName: string, provider: ProviderAst, providerValueExpressions: o.Expression[],
isMulti: boolean, isEager: boolean): o.Expression {
var resolvedProviderValueExpr: o.Expression;
var 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 (isBlank(type)) {
type = o.DYNAMIC_TYPE;
}
if (isEager) {
this._fields.push(new o.ClassField(propName, type));
this._createStmts.push(o.THIS_EXPR.prop(propName).set(resolvedProviderValueExpr).toStmt());
} else {
var internalField = `_${propName}`;
this._fields.push(new o.ClassField(internalField, type));
// Note: Equals is important for JS so that it also checks the undefined case!
var getterStmts = [
new o.IfStmt(
o.THIS_EXPR.prop(internalField).isBlank(),
[o.THIS_EXPR.prop(internalField).set(resolvedProviderValueExpr).toStmt()]),
new o.ReturnStatement(o.THIS_EXPR.prop(internalField))
];
this._getters.push(new o.ClassGetter(propName, getterStmts, type));
}
return o.THIS_EXPR.prop(propName);
}
private _getDependency(dep: CompileDiDependencyMetadata): o.Expression {
var result: o.Expression = null;
if (dep.isValue) {
result = o.literal(dep.value);
}
if (!dep.isSkipSelf) {
if (dep.token &&
(dep.token.equalsTo(identifierToken(Identifiers.Injector)) ||
dep.token.equalsTo(identifierToken(Identifiers.ComponentFactoryResolver)))) {
result = o.THIS_EXPR;
}
if (isBlank(result)) {
result = this._instances.get(dep.token);
}
}
if (isBlank(result)) {
var args = [createDiTokenExpression(dep.token)];
if (dep.isOptional) {
args.push(o.NULL_EXPR);
}
result = InjectorProps.parent.callMethod('get', args);
}
return result;
}
}
class InjectorProps {
static parent = o.THIS_EXPR.prop('parent');
}
class InjectMethodVars {
static token = o.variable('token');
static notFoundResult = o.variable('notFoundResult');
}

View File

@ -11,13 +11,14 @@ import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {CHANGE_DETECTION_STRATEGY_VALUES, LIFECYCLE_HOOKS_VALUES, LifecycleHooks, VIEW_ENCAPSULATION_VALUES, reflector} from '../core_private';
import {ListWrapper, StringMapWrapper} from '../src/facade/collection';
import {BaseException, unimplemented} from '../src/facade/exceptions';
import {NumberWrapper, RegExpWrapper, Type, isArray, isBlank, isBoolean, isNumber, isPresent, isString, normalizeBlank, normalizeBool, serializeEnum} from '../src/facade/lang';
import {NumberWrapper, RegExpWrapper, Type, isArray, isBlank, isBoolean, isNumber, isPresent, isString, isStringMap, normalizeBlank, normalizeBool, serializeEnum} from '../src/facade/lang';
import {CssSelector} from './selector';
import {getUrlScheme} from './url_resolver';
import {sanitizeIdentifier, splitAtColon} from './util';
// group 2: "event" from "(event)"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
@ -468,12 +469,14 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
export class CompileTokenMap<VALUE> {
private _valueMap = new Map<any, VALUE>();
private _values: VALUE[] = [];
private _tokens: CompileTokenMetadata[] = [];
add(token: CompileTokenMetadata, value: VALUE) {
var existing = this.get(token);
if (isPresent(existing)) {
throw new BaseException(`Can only add to a TokenMap! Token: ${token.name}`);
}
this._tokens.push(token);
this._values.push(value);
var rk = token.runtimeCacheKey;
if (isPresent(rk)) {
@ -496,6 +499,7 @@ export class CompileTokenMap<VALUE> {
}
return result;
}
keys(): CompileTokenMetadata[] { return this._tokens; }
values(): VALUE[] { return this._values; }
get size(): number { return this._values.length; }
}
@ -966,7 +970,61 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
}
}
/**
* Metadata regarding compilation of a directive.
*/
export class CompileAppModuleMetadata implements CompileMetadataWithType {
type: CompileTypeMetadata;
providers: CompileProviderMetadata[];
directives: CompileTypeMetadata[];
pipes: CompileTypeMetadata[];
precompile: CompileTypeMetadata[];
modules: CompileTypeMetadata[];
constructor({type, providers, directives, pipes, precompile, modules}: {
type?: CompileTypeMetadata,
providers?: Array<CompileProviderMetadata|CompileTypeMetadata|CompileIdentifierMetadata|any[]>,
directives?: CompileTypeMetadata[],
pipes?: CompileTypeMetadata[],
precompile?: CompileTypeMetadata[],
modules?: CompileTypeMetadata[]
} = {}) {
this.type = type;
this.directives = _normalizeArray(directives);
this.pipes = _normalizeArray(pipes);
this.providers = _normalizeArray(providers);
this.precompile = _normalizeArray(precompile);
this.modules = _normalizeArray(modules);
}
get identifier(): CompileIdentifierMetadata { return this.type; }
static fromJson(data: {[key: string]: any}): CompileAppModuleMetadata {
return new CompileAppModuleMetadata({
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
providers: _arrayFromJson(data['providers'], metadataFromJson),
directives: _arrayFromJson(data['directives'], metadataFromJson),
pipes: _arrayFromJson(data['pipes'], metadataFromJson),
precompile: _arrayFromJson(data['precompile'], CompileTypeMetadata.fromJson),
modules: _arrayFromJson(data['modules'], CompileTypeMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'class': 'AppModule',
'type': isPresent(this.type) ? this.type.toJson() : this.type,
'providers': _arrayToJson(this.providers),
'directives': _arrayToJson(this.directives),
'pipes': _arrayToJson(this.pipes),
'precompile': _arrayToJson(this.precompile),
'modules': _arrayToJson(this.modules)
};
}
}
var _COMPILE_METADATA_FROM_JSON = {
'AppModule': CompileAppModuleMetadata.fromJson,
'Directive': CompileDirectiveMetadata.fromJson,
'Pipe': CompilePipeMetadata.fromJson,
'Type': CompileTypeMetadata.fromJson,
@ -1006,3 +1064,12 @@ function _objToJson(obj: any): string|{[key: string]: any} {
function _normalizeArray(obj: any[]): any[] {
return isPresent(obj) ? obj : [];
}
export function isStaticSymbol(value: any): value is StaticSymbol {
return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']);
}
export interface StaticSymbol {
name: string;
filePath: string;
}

View File

@ -27,6 +27,7 @@ import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver';
import {StyleCompiler} from './style_compiler';
import {ViewCompiler} from './view_compiler/view_compiler';
import {AppModuleCompiler} from './app_module_compiler';
import {CompilerConfig} from './config';
import {RuntimeCompiler} from './runtime_compiler';
import {ElementSchemaRegistry} from './schema/element_schema_registry';
@ -44,13 +45,24 @@ import {PipeResolver} from './pipe_resolver';
*/
export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
/*@ts2dart_const*/[
Lexer, Parser, HtmlParser, TemplateParser, DirectiveNormalizer, CompileMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER, StyleCompiler, ViewCompiler,
Lexer,
Parser,
HtmlParser,
TemplateParser,
DirectiveNormalizer,
CompileMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
ViewCompiler,
AppModuleCompiler,
/*@ts2dart_Provider*/ {provide: CompilerConfig, useValue: new CompilerConfig()},
RuntimeCompiler,
/*@ts2dart_Provider*/ {provide: ComponentResolver, useExisting: RuntimeCompiler},
/*@ts2dart_Provider*/ {provide: Compiler, useExisting: RuntimeCompiler},
DomElementSchemaRegistry,
/*@ts2dart_Provider*/ {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
UrlResolver, ViewResolver, DirectiveResolver, PipeResolver
UrlResolver,
ViewResolver,
DirectiveResolver,
PipeResolver
];

View File

@ -20,14 +20,9 @@ import {HtmlParser} from './html_parser';
import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver';
import {PreparsedElementType, preparseElement} from './template_preparser';
import {UrlResolver} from './url_resolver';
import {SyncAsyncResult} from './util';
import {XHR} from './xhr';
export class NormalizeDirectiveResult {
constructor(
public syncResult: CompileDirectiveMetadata,
public asyncResult: Promise<CompileDirectiveMetadata>) {}
}
@Injectable()
export class DirectiveNormalizer {
private _xhrCache = new Map<string, Promise<string>>();
@ -56,10 +51,11 @@ export class DirectiveNormalizer {
return result;
}
normalizeDirective(directive: CompileDirectiveMetadata): NormalizeDirectiveResult {
normalizeDirective(directive: CompileDirectiveMetadata):
SyncAsyncResult<CompileDirectiveMetadata> {
if (!directive.isComponent) {
// For non components there is nothing to be normalized yet.
return new NormalizeDirectiveResult(directive, Promise.resolve(directive));
return new SyncAsyncResult(directive, Promise.resolve(directive));
}
let normalizedTemplateSync: CompileTemplateMetadata = null;
let normalizedTemplateAsync: Promise<CompileTemplateMetadata>;
@ -74,11 +70,10 @@ export class DirectiveNormalizer {
if (normalizedTemplateSync && normalizedTemplateSync.styleUrls.length === 0) {
// sync case
let normalizedDirective = _cloneDirectiveWithTemplate(directive, normalizedTemplateSync);
return new NormalizeDirectiveResult(
normalizedDirective, Promise.resolve(normalizedDirective));
return new SyncAsyncResult(normalizedDirective, Promise.resolve(normalizedDirective));
} else {
// async case
return new NormalizeDirectiveResult(
return new SyncAsyncResult(
null,
normalizedTemplateAsync
.then((normalizedTemplate) => this.normalizeExternalStylesheets(normalizedTemplate))

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {AppModuleFactory, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NoOpAnimationPlayer as NoOpAnimationPlayer_, SecurityContext, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes as impBalanceAnimationKeyframes, castByValue, checkBinding, clearStyles as impClearStyles, collectAndResolveStyles as impCollectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles as impBalanceAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, renderStyles as impRenderStyles, uninitialized} from '../core_private';
import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppModuleInjector, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NoOpAnimationPlayer as NoOpAnimationPlayer_, SecurityContext, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes as impBalanceAnimationKeyframes, castByValue, checkBinding, clearStyles as impClearStyles, collectAndResolveStyles as impCollectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles as impBalanceAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, renderStyles as impRenderStyles, uninitialized} from '../core_private';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {assetUrl} from './util';
@ -108,6 +108,21 @@ export class Identifiers {
moduleUrl: assetUrl('core', 'linker/component_factory_resolver'),
runtime: ComponentFactoryResolver
});
static ComponentFactory = new CompileIdentifierMetadata({
name: 'ComponentFactory',
runtime: ComponentFactory,
moduleUrl: assetUrl('core', 'linker/component_factory')
});
static AppModuleFactory = new CompileIdentifierMetadata({
name: 'AppModuleFactory',
runtime: AppModuleFactory,
moduleUrl: assetUrl('core', 'linker/app_module_factory')
});
static AppModuleInjector = new CompileIdentifierMetadata({
name: 'AppModuleInjector',
runtime: AppModuleInjector,
moduleUrl: assetUrl('core', 'linker/app_module_factory')
});
static ValueUnwrapper = new CompileIdentifierMetadata(
{name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper});
static Injector = new CompileIdentifierMetadata(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AttributeMetadata, ComponentMetadata, HostMetadata, Inject, InjectMetadata, Injectable, Optional, OptionalMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewMetadata, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AppModuleMetadata, AttributeMetadata, ComponentMetadata, HostMetadata, Inject, InjectMetadata, Injectable, Optional, OptionalMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewMetadata, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
import {LIFECYCLE_HOOKS_VALUES, ReflectorReader, createProvider, isProviderLiteral, reflector} from '../core_private';
import {StringMapWrapper} from '../src/facade/collection';
@ -27,6 +27,7 @@ import {ViewResolver} from './view_resolver';
export class CompileMetadataResolver {
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
private _appModuleCache = new Map<Type, cpl.CompileAppModuleMetadata>();
private _anonymousTypes = new Map<Object, number>();
private _anonymousTypeIndex = 0;
@ -49,14 +50,16 @@ export class CompileMetadataResolver {
return sanitizeIdentifier(identifier);
}
clearCacheFor(compType: Type) {
this._directiveCache.delete(compType);
this._pipeCache.delete(compType);
clearCacheFor(type: Type) {
this._directiveCache.delete(type);
this._pipeCache.delete(type);
this._appModuleCache.delete(type);
}
clearCache() {
this._directiveCache.clear();
this._pipeCache.clear();
this._appModuleCache.clear();
}
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
@ -102,6 +105,7 @@ export class CompileMetadataResolver {
}
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
directiveType = resolveForwardRef(directiveType);
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
@ -176,6 +180,72 @@ export class CompileMetadataResolver {
return meta;
}
getAppModuleMetadata(moduleType: any, meta: AppModuleMetadata = null):
cpl.CompileAppModuleMetadata {
// Only cache if we read the metadata via the reflector,
// as we use the moduleType as cache key.
let useCache = !meta;
moduleType = resolveForwardRef(moduleType);
var compileMeta = this._appModuleCache.get(moduleType);
if (isBlank(compileMeta) || !useCache) {
if (!meta) {
meta = this._reflector.annotations(moduleType)
.find((meta) => meta instanceof AppModuleMetadata);
}
if (!meta) {
throw new BaseException(
`Could not compile '${stringify(moduleType)}' because it is not an AppModule.`);
}
let providers: any[] = [];
if (meta.providers) {
providers.push(...this.getProvidersMetadata(meta.providers));
}
let directives: cpl.CompileTypeMetadata[] = [];
if (meta.directives) {
directives.push(...flattenArray(meta.directives)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
let pipes: cpl.CompileTypeMetadata[] = [];
if (meta.pipes) {
pipes.push(...flattenArray(meta.pipes)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
let precompile: cpl.CompileTypeMetadata[] = [];
if (meta.precompile) {
precompile.push(...flattenArray(meta.precompile)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
let modules: cpl.CompileTypeMetadata[] = [];
if (meta.modules) {
flattenArray(meta.modules).forEach((moduleType) => {
var meta = this.getAppModuleMetadata(moduleType);
providers.push(...meta.providers);
directives.push(...meta.directives);
pipes.push(...meta.pipes);
precompile.push(...meta.precompile);
modules.push(meta.type);
modules.push(...meta.modules);
});
}
compileMeta = new cpl.CompileAppModuleMetadata({
type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)),
providers: providers,
directives: directives,
pipes: pipes,
precompile: precompile,
modules: modules
});
if (useCache) {
this._appModuleCache.set(moduleType, compileMeta);
}
}
return compileMeta;
}
/**
* @param someType a symbol which may or may not be a directive type
* @returns {cpl.CompileDirectiveMetadata} if possible, otherwise null.
@ -193,6 +263,7 @@ export class CompileMetadataResolver {
getTypeMetadata(type: Type, moduleUrl: string, dependencies: any[] = null):
cpl.CompileTypeMetadata {
type = resolveForwardRef(type);
return new cpl.CompileTypeMetadata({
name: this.sanitizeTokenName(type),
moduleUrl: moduleUrl,
@ -203,6 +274,7 @@ export class CompileMetadataResolver {
getFactoryMetadata(factory: Function, moduleUrl: string, dependencies: any[] = null):
cpl.CompileFactoryMetadata {
factory = resolveForwardRef(factory);
return new cpl.CompileFactoryMetadata({
name: this.sanitizeTokenName(factory),
moduleUrl: moduleUrl,
@ -212,6 +284,7 @@ export class CompileMetadataResolver {
}
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata {
pipeType = resolveForwardRef(pipeType);
var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType);
@ -349,8 +422,11 @@ export class CompileMetadataResolver {
return this.getProviderMetadata(provider);
} else if (isProviderLiteral(provider)) {
return this.getProviderMetadata(createProvider(provider));
} else {
} else if (isValidType(provider)) {
return this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
} else {
throw new BaseException(
`Invalid provider - only instances of Provider and Type are allowed, got: ${stringify(provider)}`);
}
});
}
@ -468,21 +544,17 @@ function verifyNonBlankProviders(
return providersTree;
}
function isStaticType(value: any): boolean {
return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']);
}
function isValidType(value: any): boolean {
return isStaticType(value) || (value instanceof Type);
return cpl.isStaticSymbol(value) || (value instanceof Type);
}
function staticTypeModuleUrl(value: any): string {
return isStaticType(value) ? value['filePath'] : null;
return cpl.isStaticSymbol(value) ? value.filePath : null;
}
function componentModuleUrl(
reflector: ReflectorReader, type: any, cmpMetadata: ComponentMetadata): string {
if (isStaticType(type)) {
if (cpl.isStaticSymbol(type)) {
return staticTypeModuleUrl(type);
}
@ -503,9 +575,8 @@ function convertToCompileValue(value: any): any {
class _CompileValueConverter extends ValueTransformer {
visitOther(value: any, context: any): any {
if (isStaticType(value)) {
return new cpl.CompileIdentifierMetadata(
{name: value['name'], moduleUrl: staticTypeModuleUrl(value)});
if (cpl.isStaticSymbol(value)) {
return new cpl.CompileIdentifierMetadata({name: value.name, moduleUrl: value.filePath});
} else {
return new cpl.CompileIdentifierMetadata({runtime: value});
}

View File

@ -6,12 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ComponentFactory} from '@angular/core';
import {AppModuleMetadata, ComponentMetadata} from '@angular/core';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, createHostComponentMeta} from './compile_metadata';
import {AppModuleCompiler} from './app_module_compiler';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
import {DirectiveNormalizer} from './directive_normalizer';
import {ListWrapper} from './facade/collection';
import {BaseException} from './facade/exceptions';
import {Identifiers} from './identifiers';
import {CompileMetadataResolver} from './metadata_resolver';
import {OutputEmitter} from './output/abstract_emitter';
import * as o from './output/output_ast';
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
@ -20,79 +23,164 @@ import {assetUrl} from './util';
import {ComponentFactoryDependency, ViewCompileResult, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
import {XHR} from './xhr';
var _COMPONENT_FACTORY_IDENTIFIER = new CompileIdentifierMetadata({
name: 'ComponentFactory',
runtime: ComponentFactory,
moduleUrl: assetUrl('core', 'linker/component_factory')
});
export class SourceModule {
constructor(public moduleUrl: string, public source: string) {}
}
export class StyleSheetSourceWithImports {
constructor(public source: SourceModule, public importedUrls: string[]) {}
}
export class AppModulesSummary {
private _compAppModule = new Map<string, StaticSymbol>();
private _hashKey(type: StaticSymbol) { return `${type.filePath}#${type.name}`; }
export class NormalizedComponentWithViewDirectives {
constructor(
public component: CompileDirectiveMetadata, public directives: CompileDirectiveMetadata[],
public pipes: CompilePipeMetadata[]) {}
}
export class OfflineCompiler {
constructor(
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _outputEmitter: OutputEmitter) {}
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
Promise<CompileDirectiveMetadata> {
return this._directiveNormalizer.normalizeDirective(directive).asyncResult;
hasComponent(component: StaticSymbol): boolean {
return this._compAppModule.has(this._hashKey(component));
}
compileTemplates(components: NormalizedComponentWithViewDirectives[]): SourceModule[] {
if (components.length === 0) {
throw new BaseException('No components given');
}
var statements: o.DeclareVarStmt[] = [];
var exportedVars: string[] = [];
var moduleUrl = _ngfactoryModuleUrl(components[0].component.type);
var outputSourceModules: SourceModule[] = [];
components.forEach(componentWithDirs => {
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
_assertComponent(compMeta);
var fileSuffix = _splitLastSuffix(compMeta.type.moduleUrl)[1];
var stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
});
addComponent(module: StaticSymbol, component: StaticSymbol) {
this._compAppModule.set(this._hashKey(component), module);
}
var compViewFactoryVar = this._compileComponent(
compMeta, componentWithDirs.directives, componentWithDirs.pipes,
stylesCompileResults.componentStylesheet, fileSuffix, statements);
exportedVars.push(compViewFactoryVar);
getModule(comp: StaticSymbol): StaticSymbol {
return this._compAppModule.get(this._hashKey(comp));
}
}
export class OfflineCompiler {
constructor(
private _metadataResolver: CompileMetadataResolver,
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _appModuleCompiler: AppModuleCompiler, private _outputEmitter: OutputEmitter) {}
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
var hostViewFactoryVar =
this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, statements);
var compFactoryVar = _componentFactoryName(compMeta.type);
statements.push(
o.variable(compFactoryVar)
.set(o.importExpr(_COMPONENT_FACTORY_IDENTIFIER, [o.importType(compMeta.type)])
.instantiate(
[
o.literal(compMeta.selector), o.variable(hostViewFactoryVar),
o.importExpr(compMeta.type)
],
o.importType(
_COMPONENT_FACTORY_IDENTIFIER, [o.importType(compMeta.type)],
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
exportedVars.push(compFactoryVar);
analyzeModules(appModules: StaticSymbol[]): AppModulesSummary {
let result = new AppModulesSummary();
appModules.forEach((appModule) => {
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModule);
appModuleMeta.precompile.forEach(
(precompileComp) =>
this._getTransitiveComponents(appModule, <any>precompileComp.runtime, result));
});
outputSourceModules.unshift(this._codegenSourceModule(moduleUrl, statements, exportedVars));
return outputSourceModules;
return result;
}
private _getTransitiveComponents(
appModule: StaticSymbol, component: StaticSymbol,
target: AppModulesSummary = new AppModulesSummary()): AppModulesSummary {
var compMeta = this._metadataResolver.getDirectiveMetadata(<any>component);
// TODO(tbosch): preserve all modules per component, not just one.
// Then run the template parser with the union and the intersection of the modules (regarding
// directives/pipes)
// and report an error if some directives/pipes are only matched with the union but not with the
// intersection!
// -> this means that a component is used in the wrong way!
if (!compMeta.isComponent || target.hasComponent(component)) {
return target;
}
target.addComponent(appModule, component);
this._metadataResolver.getViewDirectivesMetadata(<any>component).forEach((dirMeta) => {
this._getTransitiveComponents(appModule, <any>dirMeta.type.runtime);
});
compMeta.precompile.forEach((precompileComp) => {
this._getTransitiveComponents(appModule, <any>precompileComp.type.runtime);
});
return target;
}
clearCache() {
this._directiveNormalizer.clearCache();
this._metadataResolver.clearCache();
}
compile(
moduleUrl: string, appModulesSummary: AppModulesSummary, components: StaticSymbol[],
appModules: StaticSymbol[]): Promise<SourceModule[]> {
let fileSuffix = _splitLastSuffix(moduleUrl)[1];
let statements: o.Statement[] = [];
let exportedVars: string[] = [];
let outputSourceModules: SourceModule[] = [];
// compile app modules
exportedVars.push(
...appModules.map((appModule) => this._compileAppModule(appModule, statements)));
// compile components
return Promise
.all(components.map((compType) => {
let appModule = appModulesSummary.getModule(compType);
let appModuleDirectives: CompileDirectiveMetadata[] = [];
let appModulePipes: CompilePipeMetadata[] = [];
if (appModule) {
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModule);
appModuleDirectives.push(...appModuleMeta.directives.map(
type => this._metadataResolver.getDirectiveMetadata(type.runtime)));
appModulePipes.push(...appModuleMeta.pipes.map(
type => this._metadataResolver.getPipeMetadata(type.runtime)));
}
return Promise
.all([
this._metadataResolver.getDirectiveMetadata(<any>compType), ...appModuleDirectives,
...this._metadataResolver.getViewDirectivesMetadata(<any>compType)
].map(dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
.then((normalizedCompWithDirectives) => {
let compMeta = normalizedCompWithDirectives[0];
let dirMetas = normalizedCompWithDirectives.slice(1);
_assertComponent(compMeta);
// compile styles
let stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
});
// compile components
exportedVars.push(this._compileComponentFactory(compMeta, fileSuffix, statements));
let pipeMetas = [
...appModulePipes,
...this._metadataResolver.getViewPipesMetadata(compMeta.type.runtime)
];
exportedVars.push(this._compileComponent(
compMeta, dirMetas, pipeMetas, stylesCompileResults.componentStylesheet,
fileSuffix, statements));
});
}))
.then(() => {
if (statements.length > 0) {
outputSourceModules.unshift(this._codegenSourceModule(
_ngfactoryModuleUrl(moduleUrl), statements, exportedVars));
}
return outputSourceModules;
});
}
private _compileAppModule(appModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModuleType);
let appCompileResult = this._appModuleCompiler.compile(appModuleMeta);
appCompileResult.dependencies.forEach((dep) => {
dep.placeholder.name = _componentFactoryName(dep.comp);
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp.moduleUrl);
});
targetStatements.push(...appCompileResult.statements);
return appCompileResult.appModuleFactoryVar;
}
private _compileComponentFactory(
compMeta: CompileDirectiveMetadata, fileSuffix: string,
targetStatements: o.Statement[]): string {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
var hostViewFactoryVar =
this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, targetStatements);
var compFactoryVar = _componentFactoryName(compMeta.type);
targetStatements.push(
o.variable(compFactoryVar)
.set(o.importExpr(Identifiers.ComponentFactory, [o.importType(compMeta.type)])
.instantiate(
[
o.literal(compMeta.selector), o.variable(hostViewFactoryVar),
o.importExpr(compMeta.type)
],
o.importType(
Identifiers.ComponentFactory, [o.importType(compMeta.type)],
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]));
return compFactoryVar;
}
private _compileComponent(
@ -130,11 +218,11 @@ function _resolveViewStatements(compileResult: ViewCompileResult): o.Statement[]
compileResult.dependencies.forEach((dep) => {
if (dep instanceof ViewFactoryDependency) {
let vfd = <ViewFactoryDependency>dep;
vfd.placeholder.moduleUrl = _ngfactoryModuleUrl(vfd.comp);
vfd.placeholder.moduleUrl = _ngfactoryModuleUrl(vfd.comp.moduleUrl);
} else if (dep instanceof ComponentFactoryDependency) {
let cfd = <ComponentFactoryDependency>dep;
cfd.placeholder.name = _componentFactoryName(cfd.comp);
cfd.placeholder.moduleUrl = _ngfactoryModuleUrl(cfd.comp);
cfd.placeholder.moduleUrl = _ngfactoryModuleUrl(cfd.comp.moduleUrl);
}
});
return compileResult.statements;
@ -149,8 +237,8 @@ function _resolveStyleStatements(
return compileResult.statements;
}
function _ngfactoryModuleUrl(comp: CompileIdentifierMetadata): string {
var urlWithSuffix = _splitLastSuffix(comp.moduleUrl);
function _ngfactoryModuleUrl(compUrl: string): string {
var urlWithSuffix = _splitLastSuffix(compUrl);
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
}

View File

@ -1,86 +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 {AppElement, AppView, DebugAppView} from '../../core_private';
import {BaseException} from '../facade/exceptions';
import {isPresent} from '../facade/lang';
import {DynamicInstance, InstanceFactory} from './output_interpreter';
export class InterpretiveAppViewInstanceFactory implements InstanceFactory {
createInstance(
superClass: any, clazz: any, args: any[], props: Map<string, any>,
getters: Map<string, Function>, methods: Map<string, Function>): any {
if (superClass === AppView) {
// We are always using DebugAppView as parent.
// However, in prod mode we generate a constructor call that does
// not have the argument for the debugNodeInfos.
args = args.concat([null]);
return new _InterpretiveAppView(args, props, getters, methods);
} else if (superClass === DebugAppView) {
return new _InterpretiveAppView(args, props, getters, methods);
}
throw new BaseException(`Can't instantiate class ${superClass} in interpretative mode`);
}
}
class _InterpretiveAppView extends DebugAppView<any> implements DynamicInstance {
constructor(
args: any[], public props: Map<string, any>, public getters: Map<string, Function>,
public methods: Map<string, Function>) {
super(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
}
createInternal(rootSelector: string|any): AppElement {
var m = this.methods.get('createInternal');
if (isPresent(m)) {
return m(rootSelector);
} else {
return super.createInternal(rootSelector);
}
}
injectorGetInternal(token: any, nodeIndex: number, notFoundResult: any): any {
var m = this.methods.get('injectorGetInternal');
if (isPresent(m)) {
return m(token, nodeIndex, notFoundResult);
} else {
return super.injectorGet(token, nodeIndex, notFoundResult);
}
}
detachInternal(): void {
var m = this.methods.get('detachInternal');
if (isPresent(m)) {
return m();
} else {
return super.detachInternal();
}
}
destroyInternal(): void {
var m = this.methods.get('destroyInternal');
if (isPresent(m)) {
return m();
} else {
return super.destroyInternal();
}
}
dirtyParentQueriesInternal(): void {
var m = this.methods.get('dirtyParentQueriesInternal');
if (isPresent(m)) {
return m();
} else {
return super.dirtyParentQueriesInternal();
}
}
detectChangesInternal(throwOnChange: boolean): void {
var m = this.methods.get('detectChangesInternal');
if (isPresent(m)) {
return m(throwOnChange);
} else {
return super.detectChangesInternal(throwOnChange);
}
}
}

View File

@ -7,7 +7,11 @@
*/
import {CompileIdentifierMetadata} from '../compile_metadata';
import {StringMapWrapper} from '../facade/collection';
import {BaseException} from '../facade/exceptions';
import {isBlank, isPresent, isString} from '../facade/lang';
import {ValueTransformer, visitValue} from '../util';
//// Types
@ -875,10 +879,6 @@ export function importType(
return isPresent(id) ? new ExternalType(id, typeParams, typeModifiers) : null;
}
export function literal(value: any, type: Type = null): LiteralExpr {
return new LiteralExpr(value, type);
}
export function literalArr(values: Expression[], type: Type = null): LiteralArrayExpr {
return new LiteralArrayExpr(values, type);
}
@ -895,3 +895,30 @@ export function not(expr: Expression): NotExpr {
export function fn(params: FnParam[], body: Statement[], type: Type = null): FunctionExpr {
return new FunctionExpr(params, body, type);
}
export function literal(value: any, type: Type = null): Expression {
return visitValue(value, new _ValueOutputAstTransformer(), type);
}
class _ValueOutputAstTransformer implements ValueTransformer {
visitArray(arr: any[], type: Type): Expression {
return literalArr(arr.map(value => visitValue(value, this, null)), type);
}
visitStringMap(map: {[key: string]: any}, type: MapType): Expression {
var entries: Array<string|Expression>[] = [];
StringMapWrapper.forEach(map, (value: any, key: string) => {
entries.push([key, visitValue(value, this, null)]);
});
return literalMap(entries, type);
}
visitPrimitive(value: any, type: Type): Expression { return new LiteralExpr(value, type); }
visitOther(value: any, type: Type): Expression {
if (value instanceof CompileIdentifierMetadata) {
return importExpr(value);
} else if (value instanceof Expression) {
return value;
} else {
throw new BaseException(`Illegal state: Don't now how to compile value ${value}`);
}
}
}

View File

@ -6,49 +6,23 @@
* found in the LICENSE file at https://angular.io/license
*/
import {reflector} from '../../core_private';
import {ObservableWrapper} from '../facade/async';
import {ListWrapper} from '../facade/collection';
import {BaseException, unimplemented} from '../facade/exceptions';
import {FunctionWrapper, IS_DART, isPresent} from '../facade/lang';
import {IS_DART, isPresent} from '../facade/lang';
import {debugOutputAstAsDart} from './dart_emitter';
import * as o from './output_ast';
import {debugOutputAstAsTypeScript} from './ts_emitter';
export function interpretStatements(
statements: o.Statement[], resultVar: string, instanceFactory: InstanceFactory): any {
export function interpretStatements(statements: o.Statement[], resultVar: string): any {
var stmtsWithReturn = statements.concat([new o.ReturnStatement(o.variable(resultVar))]);
var ctx = new _ExecutionContext(
null, null, null, null, new Map<string, any>(), new Map<string, any>(),
new Map<string, Function>(), new Map<string, Function>(), instanceFactory);
var ctx = new _ExecutionContext(null, null, null, new Map<string, any>());
var visitor = new StatementInterpreter();
var result = visitor.visitAllStatements(stmtsWithReturn, ctx);
return isPresent(result) ? result.value : null;
}
export interface InstanceFactory {
createInstance(
superClass: any, clazz: any, constructorArgs: any[], props: Map<string, any>,
getters: Map<string, Function>, methods: Map<string, Function>): DynamicInstance;
}
export abstract class DynamicInstance {
get props(): Map<string, any> { return unimplemented(); }
get getters(): Map<string, Function> { return unimplemented(); }
get methods(): Map<string, any> { return unimplemented(); }
get clazz(): any { return unimplemented(); }
}
function isDynamicInstance(instance: any): any {
if (IS_DART) {
return instance instanceof DynamicInstance;
} else {
return isPresent(instance) && isPresent(instance.props) && isPresent(instance.getters) &&
isPresent(instance.methods);
}
}
function _executeFunctionStatements(
varNames: string[], varValues: any[], statements: o.Statement[], ctx: _ExecutionContext,
visitor: StatementInterpreter): any {
@ -62,15 +36,11 @@ function _executeFunctionStatements(
class _ExecutionContext {
constructor(
public parent: _ExecutionContext, public superClass: any, public superInstance: any,
public className: string, public vars: Map<string, any>, public props: Map<string, any>,
public getters: Map<string, Function>, public methods: Map<string, Function>,
public instanceFactory: InstanceFactory) {}
public parent: _ExecutionContext, public instance: any, public className: string,
public vars: Map<string, any>) {}
createChildWihtLocalVars(): _ExecutionContext {
return new _ExecutionContext(
this, this.superClass, this.superInstance, this.className, new Map<string, any>(),
this.props, this.getters, this.methods, this.instanceFactory);
return new _ExecutionContext(this, this.instance, this.className, new Map<string, any>());
}
}
@ -78,38 +48,44 @@ class ReturnValue {
constructor(public value: any) {}
}
class _DynamicClass {
constructor(
private _classStmt: o.ClassStmt, private _ctx: _ExecutionContext,
private _visitor: StatementInterpreter) {}
function createDynamicClass(
_classStmt: o.ClassStmt, _ctx: _ExecutionContext, _visitor: StatementInterpreter): Function {
let propertyDescriptors: {[key: string]: any} = {};
instantiate(args: any[]): DynamicInstance {
var props = new Map<string, any>();
var getters = new Map<string, Function>();
var methods = new Map<string, Function>();
var superClass = this._classStmt.parent.visitExpression(this._visitor, this._ctx);
var instanceCtx = new _ExecutionContext(
this._ctx, superClass, null, this._classStmt.name, this._ctx.vars, props, getters, methods,
this._ctx.instanceFactory);
_classStmt.getters.forEach((getter: o.ClassGetter) => {
// Note: use `function` instead of arrow function to capture `this`
propertyDescriptors[getter.name] = {
configurable: false,
get: function() {
let instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
return _executeFunctionStatements([], [], getter.body, instanceCtx, _visitor);
}
};
});
_classStmt.methods.forEach(function(method: o.ClassMethod) {
var paramNames = method.params.map(param => param.name);
// Note: use `function` instead of arrow function to capture `this`
propertyDescriptors[method.name] = {
writable: false,
configurable: false,
value: function(...args: any[]) {
let instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
return _executeFunctionStatements(paramNames, args, method.body, instanceCtx, _visitor);
}
};
});
this._classStmt.fields.forEach((field: o.ClassField) => { props.set(field.name, null); });
this._classStmt.getters.forEach((getter: o.ClassGetter) => {
getters.set(
getter.name,
() => _executeFunctionStatements([], [], getter.body, instanceCtx, this._visitor));
});
this._classStmt.methods.forEach((method: o.ClassMethod) => {
var paramNames = method.params.map(param => param.name);
methods.set(method.name, _declareFn(paramNames, method.body, instanceCtx, this._visitor));
});
var ctorParamNames = this._classStmt.constructorMethod.params.map(param => param.name);
var ctorParamNames = _classStmt.constructorMethod.params.map(param => param.name);
// Note: use `function` instead of arrow function to capture `this`
var ctor = function(...args: any[]) {
let instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
_classStmt.fields.forEach((field) => { this[field.name] = undefined; });
_executeFunctionStatements(
ctorParamNames, args, this._classStmt.constructorMethod.body, instanceCtx, this._visitor);
return instanceCtx.superInstance;
}
debugAst(): string { return this._visitor.debugAst(this._classStmt); }
ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
};
var superClass = _classStmt.parent.visitExpression(_visitor, _ctx);
ctor.prototype = Object.create(superClass.prototype, propertyDescriptors);
return ctor;
}
class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
@ -138,8 +114,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
if (isPresent(ast.builtin)) {
switch (ast.builtin) {
case o.BuiltinVar.Super:
return ctx.instance.__proto__;
case o.BuiltinVar.This:
return ctx.superInstance;
return ctx.instance;
case o.BuiltinVar.CatchError:
varName = CATCH_ERROR_VAR;
break;
@ -169,23 +146,14 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
visitWritePropExpr(expr: o.WritePropExpr, ctx: _ExecutionContext): any {
var receiver = expr.receiver.visitExpression(this, ctx);
var value = expr.value.visitExpression(this, ctx);
if (isDynamicInstance(receiver)) {
var di = <DynamicInstance>receiver;
if (di.props.has(expr.name)) {
di.props.set(expr.name, value);
} else {
reflector.setter(expr.name)(receiver, value);
}
} else {
reflector.setter(expr.name)(receiver, value);
}
receiver[expr.name] = value;
return value;
}
visitInvokeMethodExpr(expr: o.InvokeMethodExpr, ctx: _ExecutionContext): any {
var receiver = expr.receiver.visitExpression(this, ctx);
var args = this.visitAllExpressions(expr.args, ctx);
var result: any /** TODO #9100 */;
var result: any;
if (isPresent(expr.builtin)) {
switch (expr.builtin) {
case o.BuiltinMethod.ConcatArray:
@ -204,15 +172,8 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
default:
throw new BaseException(`Unknown builtin method ${expr.builtin}`);
}
} else if (isDynamicInstance(receiver)) {
var di = <DynamicInstance>receiver;
if (di.methods.has(expr.name)) {
result = FunctionWrapper.apply(di.methods.get(expr.name), args);
} else {
result = reflector.method(expr.name)(receiver, args);
}
} else {
result = reflector.method(expr.name)(receiver, args);
result = receiver[expr.name].apply(receiver, args);
}
return result;
}
@ -220,20 +181,18 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
var args = this.visitAllExpressions(stmt.args, ctx);
var fnExpr = stmt.fn;
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
ctx.superInstance = ctx.instanceFactory.createInstance(
ctx.superClass, ctx.className, args, ctx.props, ctx.getters, ctx.methods);
ctx.parent.superInstance = ctx.superInstance;
ctx.instance.constructor.prototype.constructor.apply(ctx.instance, args);
return null;
} else {
var fn = stmt.fn.visitExpression(this, ctx);
return FunctionWrapper.apply(fn, args);
return fn.apply(null, args);
}
}
visitReturnStmt(stmt: o.ReturnStatement, ctx: _ExecutionContext): any {
return new ReturnValue(stmt.value.visitExpression(this, ctx));
}
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: _ExecutionContext): any {
var clazz = new _DynamicClass(stmt, ctx, this);
var clazz = createDynamicClass(stmt, ctx, this);
ctx.vars.set(stmt.name, clazz);
return null;
}
@ -266,11 +225,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any {
var args = this.visitAllExpressions(ast.args, ctx);
var clazz = ast.classExpr.visitExpression(this, ctx);
if (clazz instanceof _DynamicClass) {
return clazz.instantiate(args);
} else {
return FunctionWrapper.apply(reflector.factory(clazz), args);
}
return new clazz(...args);
}
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; }
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any { return ast.value.runtime; }
@ -337,22 +292,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
}
}
visitReadPropExpr(ast: o.ReadPropExpr, ctx: _ExecutionContext): any {
var result: any /** TODO #9100 */;
var result: any;
var receiver = ast.receiver.visitExpression(this, ctx);
if (isDynamicInstance(receiver)) {
var di = <DynamicInstance>receiver;
if (di.props.has(ast.name)) {
result = di.props.get(ast.name);
} else if (di.getters.has(ast.name)) {
result = di.getters.get(ast.name)();
} else if (di.methods.has(ast.name)) {
result = di.methods.get(ast.name);
} else {
result = reflector.getter(ast.name)(receiver);
}
} else {
result = reflector.getter(ast.name)(receiver);
}
result = receiver[ast.name];
return result;
}
visitReadKeyExpr(ast: o.ReadKeyExpr, ctx: _ExecutionContext): any {
@ -366,7 +308,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: _ExecutionContext): any {
var result = {};
ast.entries.forEach(
(entry) => (result as any /** TODO #9100 */)[<string>entry[0]] =
(entry) => (result as any)[<string>entry[0]] =
(<o.Expression>entry[1]).visitExpression(this, ctx));
return result;
}
@ -390,61 +332,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
function _declareFn(
varNames: string[], statements: o.Statement[], ctx: _ExecutionContext,
visitor: StatementInterpreter): Function {
switch (varNames.length) {
case 0:
return () => _executeFunctionStatements(varNames, [], statements, ctx, visitor);
case 1:
return (d0: any /** TODO #9100 */) =>
_executeFunctionStatements(varNames, [d0], statements, ctx, visitor);
case 2:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */) =>
_executeFunctionStatements(varNames, [d0, d1], statements, ctx, visitor);
case 3:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */) =>
_executeFunctionStatements(varNames, [d0, d1, d2], statements, ctx, visitor);
case 4:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */) =>
_executeFunctionStatements(varNames, [d0, d1, d2, d3], statements, ctx, visitor);
case 5:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */, d4: any /** TODO #9100 */) =>
_executeFunctionStatements(
varNames, [d0, d1, d2, d3, d4], statements, ctx, visitor);
case 6:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */, d4: any /** TODO #9100 */, d5: any /** TODO #9100 */) =>
_executeFunctionStatements(
varNames, [d0, d1, d2, d3, d4, d5], statements, ctx, visitor);
case 7:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */, d4: any /** TODO #9100 */, d5: any /** TODO #9100 */,
d6: any /** TODO #9100 */) =>
_executeFunctionStatements(
varNames, [d0, d1, d2, d3, d4, d5, d6], statements, ctx, visitor);
case 8:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */, d4: any /** TODO #9100 */, d5: any /** TODO #9100 */,
d6: any /** TODO #9100 */, d7: any /** TODO #9100 */) =>
_executeFunctionStatements(
varNames, [d0, d1, d2, d3, d4, d5, d6, d7], statements, ctx, visitor);
case 9:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */, d4: any /** TODO #9100 */, d5: any /** TODO #9100 */,
d6: any /** TODO #9100 */, d7: any /** TODO #9100 */, d8: any /** TODO #9100 */) =>
_executeFunctionStatements(
varNames, [d0, d1, d2, d3, d4, d5, d6, d7, d8], statements, ctx, visitor);
case 10:
return (d0: any /** TODO #9100 */, d1: any /** TODO #9100 */, d2: any /** TODO #9100 */,
d3: any /** TODO #9100 */, d4: any /** TODO #9100 */, d5: any /** TODO #9100 */,
d6: any /** TODO #9100 */, d7: any /** TODO #9100 */, d8: any /** TODO #9100 */,
d9: any /** TODO #9100 */) =>
_executeFunctionStatements(
varNames, [d0, d1, d2, d3, d4, d5, d6, d7, d8, d9], statements, ctx, visitor);
default:
throw new BaseException(
'Declaring functions with more than 10 arguments is not supported right now');
}
return (...args: any[]) => _executeFunctionStatements(varNames, args, statements, ctx, visitor);
}
var CATCH_ERROR_VAR = 'error';

View File

@ -5,13 +5,16 @@
* 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 {isPresent} from './facade/lang';
export class ParseLocation {
constructor(
public file: ParseSourceFile, public offset: number, public line: number,
public col: number) {}
toString(): string { return `${this.file.url}@${this.line}:${this.col}`; }
toString(): string {
return isPresent(this.offset) ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
}
}
export class ParseSourceFile {
@ -39,38 +42,41 @@ export abstract class ParseError {
toString(): string {
var source = this.span.start.file.content;
var ctxStart = this.span.start.offset;
if (ctxStart > source.length - 1) {
ctxStart = source.length - 1;
}
var ctxEnd = ctxStart;
var ctxLen = 0;
var ctxLines = 0;
var contextStr = '';
if (isPresent(ctxStart)) {
if (ctxStart > source.length - 1) {
ctxStart = source.length - 1;
}
var ctxEnd = ctxStart;
var ctxLen = 0;
var ctxLines = 0;
while (ctxLen < 100 && ctxStart > 0) {
ctxStart--;
ctxLen++;
if (source[ctxStart] == '\n') {
if (++ctxLines == 3) {
break;
while (ctxLen < 100 && ctxStart > 0) {
ctxStart--;
ctxLen++;
if (source[ctxStart] == '\n') {
if (++ctxLines == 3) {
break;
}
}
}
}
ctxLen = 0;
ctxLines = 0;
while (ctxLen < 100 && ctxEnd < source.length - 1) {
ctxEnd++;
ctxLen++;
if (source[ctxEnd] == '\n') {
if (++ctxLines == 3) {
break;
ctxLen = 0;
ctxLines = 0;
while (ctxLen < 100 && ctxEnd < source.length - 1) {
ctxEnd++;
ctxLen++;
if (source[ctxEnd] == '\n') {
if (++ctxLines == 3) {
break;
}
}
}
let context = source.substring(ctxStart, this.span.start.offset) + '[ERROR ->]' +
source.substring(this.span.start.offset, ctxEnd + 1);
contextStr = ` ("${context}")`;
}
let context = source.substring(ctxStart, this.span.start.offset) + '[ERROR ->]' +
source.substring(this.span.start.offset, ctxEnd + 1);
return `${this.msg} ("${context}"): ${this.span.start}`;
return `${this.msg}${contextStr}: ${this.span.start}`;
}
}

View File

@ -7,9 +7,10 @@
*/
import {ListWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions';
import {isArray, isBlank, isPresent, normalizeBlank} from '../src/facade/lang';
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
import {Identifiers, identifierToken} from './identifiers';
import {ParseError, ParseSourceSpan} from './parse_util';
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst, VariableAst} from './template_ast';
@ -270,6 +271,115 @@ export class ProviderElementContext {
}
}
export class AppModuleProviderParser {
private _transformedProviders = new CompileTokenMap<ProviderAst>();
private _seenProviders = new CompileTokenMap<boolean>();
private _unparsedProviders: any[] = [];
private _allProviders: CompileTokenMap<ProviderAst>;
private _errors: ProviderError[] = [];
constructor(appModule: CompileAppModuleMetadata, sourceSpan: ParseSourceSpan) {
this._allProviders = new CompileTokenMap<ProviderAst>();
[appModule.type].concat(appModule.modules).forEach((appModuleType: CompileTypeMetadata) => {
var appModuleProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: appModuleType}), useClass: appModuleType});
_resolveProviders(
[appModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors,
this._allProviders);
});
_resolveProviders(
_normalizeProviders(appModule.providers, sourceSpan, this._errors),
ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders);
}
parse(): ProviderAst[] {
this._allProviders.values().forEach(
(provider) => { this._getOrCreateLocalProvider(provider.token, provider.eager); });
if (this._errors.length > 0) {
var errorString = this._errors.join('\n');
throw new BaseException(`Provider parse errors:\n${errorString}`);
}
return this._transformedProviders.values();
}
private _getOrCreateLocalProvider(token: CompileTokenMetadata, eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token);
if (isBlank(resolvedProvider)) {
return null;
}
var transformedProviderAst = this._transformedProviders.get(token);
if (isPresent(transformedProviderAst)) {
return transformedProviderAst;
}
if (isPresent(this._seenProviders.get(token))) {
this._errors.push(new ProviderError(
`Cannot instantiate cyclic dependency! ${token.name}`, resolvedProvider.sourceSpan));
return null;
}
this._seenProviders.add(token, true);
var transformedProviders = resolvedProvider.providers.map((provider) => {
var transformedUseValue = provider.useValue;
var transformedUseExisting = provider.useExisting;
var transformedDeps: CompileDiDependencyMetadata[];
if (isPresent(provider.useExisting)) {
var existingDiDep = this._getDependency(
new CompileDiDependencyMetadata({token: provider.useExisting}), eager,
resolvedProvider.sourceSpan);
if (isPresent(existingDiDep.token)) {
transformedUseExisting = existingDiDep.token;
} else {
transformedUseExisting = null;
transformedUseValue = existingDiDep.value;
}
} else if (isPresent(provider.useFactory)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useFactory.diDeps;
transformedDeps =
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
} else if (isPresent(provider.useClass)) {
var deps = isPresent(provider.deps) ? provider.deps : provider.useClass.diDeps;
transformedDeps =
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
}
return _transformProvider(provider, {
useExisting: transformedUseExisting,
useValue: transformedUseValue,
deps: transformedDeps
});
});
transformedProviderAst =
_transformProviderAst(resolvedProvider, {eager: eager, providers: transformedProviders});
this._transformedProviders.add(token, transformedProviderAst);
return transformedProviderAst;
}
private _getDependency(
dep: CompileDiDependencyMetadata, eager: boolean = null,
requestorSourceSpan: ParseSourceSpan): CompileDiDependencyMetadata {
var foundLocal = false;
if (!dep.isSkipSelf && isPresent(dep.token)) {
// access the injector
if (dep.token.equalsTo(identifierToken(Identifiers.Injector)) ||
dep.token.equalsTo(identifierToken(Identifiers.ComponentFactoryResolver))) {
foundLocal = true;
// access providers
} else if (isPresent(this._getOrCreateLocalProvider(dep.token, eager))) {
foundLocal = true;
}
}
var result: CompileDiDependencyMetadata = dep;
if (dep.isSelf && !foundLocal) {
if (dep.isOptional) {
result = new CompileDiDependencyMetadata({isValue: true, value: null});
} else {
this._errors.push(
new ProviderError(`No provider for ${dep.token.name}`, requestorSourceSpan));
}
}
return result;
}
}
function _transformProvider(
provider: CompileProviderMetadata,
{useExisting, useValue, deps}:

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Compiler, ComponentFactory, ComponentResolver, Injectable} from '@angular/core';
import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, Injectable} from '@angular/core';
import {BaseException} from '../src/facade/exceptions';
import {ConcreteType, IS_DART, Type, isBlank, isString, stringify} from '../src/facade/lang';
@ -17,14 +17,15 @@ import {createHostComponentMeta, CompileDirectiveMetadata, CompilePipeMetadata,
import {TemplateAst,} from './template_ast';
import {StyleCompiler, StylesCompileDependency, CompiledStylesheet} from './style_compiler';
import {ViewCompiler, ViewCompileResult, ViewFactoryDependency, ComponentFactoryDependency} from './view_compiler/view_compiler';
import {AppModuleCompiler} from './app_module_compiler';
import {TemplateParser} from './template_parser';
import {DirectiveNormalizer, NormalizeDirectiveResult} from './directive_normalizer';
import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver';
import {CompilerConfig} from './config';
import * as ir from './output/output_ast';
import {jitStatements} from './output/output_jit';
import {interpretStatements} from './output/output_interpreter';
import {InterpretiveAppViewInstanceFactory} from './output/interpretive_view';
import {SyncAsyncResult} from './util';
/**
* An internal module of the Angular compiler that begins with component types,
@ -37,14 +38,15 @@ import {InterpretiveAppViewInstanceFactory} from './output/interpretive_view';
*/
@Injectable()
export class RuntimeCompiler implements ComponentResolver, Compiler {
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
private _compiledHostTemplateCache = new Map<any, CompiledTemplate>();
private _compiledTemplateCache = new Map<Type, CompiledTemplate>();
private _compiledHostTemplateCache = new Map<Type, CompiledTemplate>();
private _compiledAppModuleCache = new Map<Type, AppModuleFactory<any>>();
constructor(
private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _genConfig: CompilerConfig) {}
private _appModuleCompiler: AppModuleCompiler, private _genConfig: CompilerConfig) {}
resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
if (isString(component)) {
@ -54,39 +56,101 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
return this.compileComponentAsync(<ConcreteType<any>>component);
}
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> {
var templates = this._getTransitiveCompiledTemplates(compType, true);
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
AppModuleFactory<T> {
return this._compileAppModule(moduleType, true, metadata).syncResult;
}
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
Promise<AppModuleFactory<T>> {
return this._compileAppModule(moduleType, false, metadata).asyncResult;
}
private _compileAppModule<T>(
moduleType: ConcreteType<T>, isSync: boolean,
metadata: AppModuleMetadata = null): SyncAsyncResult<AppModuleFactory<T>> {
// Only cache if we read the metadata via the reflector,
// as we use the moduleType as cache key.
let useCache = !metadata;
let appModuleFactory = this._compiledAppModuleCache.get(moduleType);
let componentCompilePromises: Promise<any>[] = [];
if (!appModuleFactory || !useCache) {
var compileModuleMeta = this._metadataResolver.getAppModuleMetadata(moduleType, metadata);
var compileResult = this._appModuleCompiler.compile(compileModuleMeta);
compileResult.dependencies.forEach((dep) => {
let compileResult = this._compileComponent(
dep.comp.runtime, isSync,
compileModuleMeta.directives.map(compileType => <any>compileType.runtime),
compileModuleMeta.pipes.map(compileType => <any>compileType.runtime));
dep.placeholder.runtime = compileResult.syncResult;
componentCompilePromises.push(compileResult.asyncResult);
dep.placeholder.name = `compFactory_${dep.comp.name}`;
});
if (IS_DART || !this._genConfig.useJit) {
appModuleFactory =
interpretStatements(compileResult.statements, compileResult.appModuleFactoryVar);
} else {
appModuleFactory = jitStatements(
`${compileModuleMeta.type.name}.ngfactory.js`, compileResult.statements,
compileResult.appModuleFactoryVar);
}
if (useCache) {
this._compiledAppModuleCache.set(moduleType, appModuleFactory);
}
}
return new SyncAsyncResult(
appModuleFactory, Promise.all(componentCompilePromises).then(() => appModuleFactory));
}
compileComponentAsync<T>(compType: ConcreteType<T>, {moduleDirectives = [], modulePipes = []}: {
moduleDirectives?: ConcreteType<any>[],
modulePipes?: ConcreteType<any>[]
} = {}): Promise<ComponentFactory<T>> {
return this._compileComponent(compType, false, moduleDirectives, modulePipes).asyncResult;
}
compileComponentSync<T>(compType: ConcreteType<T>, {moduleDirectives = [], modulePipes = []}: {
moduleDirectives?: ConcreteType<any>[],
modulePipes?: ConcreteType<any>[]
} = {}): ComponentFactory<T> {
return this._compileComponent(compType, true, moduleDirectives, modulePipes).syncResult;
}
private _compileComponent<T>(
compType: ConcreteType<T>, isSync: boolean, moduleDirectives: ConcreteType<any>[],
modulePipes: ConcreteType<any>[]): SyncAsyncResult<ComponentFactory<T>> {
var templates =
this._getTransitiveCompiledTemplates(compType, true, moduleDirectives, modulePipes);
var loadingPromises: Promise<any>[] = [];
templates.forEach((template) => {
if (template.loading) {
loadingPromises.push(template.loading);
if (isSync) {
throw new BaseException(
`Can't compile synchronously as ${template.compType.name} is still being loaded!`);
} else {
loadingPromises.push(template.loading);
}
}
});
return Promise.all(loadingPromises).then(() => {
templates.forEach((template) => { this._compileTemplate(template); });
return this._getCompiledHostTemplate(compType).proxyComponentFactory;
});
let compile = () => { templates.forEach((template) => { this._compileTemplate(template); }); };
if (isSync) {
compile();
}
let result = this._compiledHostTemplateCache.get(compType).proxyComponentFactory;
return new SyncAsyncResult(result, Promise.all(loadingPromises).then(() => {
compile();
return result;
}));
}
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> {
var templates = this._getTransitiveCompiledTemplates(compType, true);
templates.forEach((template) => {
if (template.loading) {
throw new BaseException(
`Can't compile synchronously as ${template.compType.name} is still being loaded!`);
}
});
templates.forEach((template) => { this._compileTemplate(template); });
return this._getCompiledHostTemplate(compType).proxyComponentFactory;
}
clearCacheFor(compType: Type) {
this._metadataResolver.clearCacheFor(compType);
this._compiledHostTemplateCache.delete(compType);
var compiledTemplate = this._compiledTemplateCache.get(compType);
clearCacheFor(type: Type) {
this._compiledAppModuleCache.delete(type);
this._metadataResolver.clearCacheFor(type);
this._compiledHostTemplateCache.delete(type);
var compiledTemplate = this._compiledTemplateCache.get(type);
if (compiledTemplate) {
this._templateNormalizer.clearCacheFor(compiledTemplate.normalizedCompMeta);
this._compiledTemplateCache.delete(compType);
this._compiledTemplateCache.delete(type);
}
}
@ -95,9 +159,10 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
this._compiledTemplateCache.clear();
this._compiledHostTemplateCache.clear();
this._templateNormalizer.clearCache();
this._compiledAppModuleCache.clear();
}
private _getCompiledHostTemplate(type: Type): CompiledTemplate {
private _createCompiledHostTemplate(type: Type): CompiledTemplate {
var compiledTemplate = this._compiledHostTemplateCache.get(type);
if (isBlank(compiledTemplate)) {
var compMeta = this._metadataResolver.getDirectiveMetadata(type);
@ -111,12 +176,16 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
return compiledTemplate;
}
private _getCompiledTemplate(type: Type): CompiledTemplate {
private _createCompiledTemplate(
type: Type, moduleDirectives: ConcreteType<any>[],
modulePipes: ConcreteType<any>[]): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(type);
if (isBlank(compiledTemplate)) {
var compMeta = this._metadataResolver.getDirectiveMetadata(type);
assertComponent(compMeta);
var viewDirectives: CompileDirectiveMetadata[] = [];
moduleDirectives.forEach(
(type) => viewDirectives.push(this._metadataResolver.getDirectiveMetadata(type)));
var viewComponentTypes: Type[] = [];
this._metadataResolver.getViewDirectivesMetadata(type).forEach(dirOrComp => {
if (dirOrComp.isComponent) {
@ -126,7 +195,10 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
}
});
var precompileComponentTypes = compMeta.precompile.map((typeMeta) => typeMeta.runtime);
var pipes = this._metadataResolver.getViewPipesMetadata(type);
var pipes = [
...modulePipes.map((type) => this._metadataResolver.getPipeMetadata(type)),
...this._metadataResolver.getViewPipesMetadata(type)
];
compiledTemplate = new CompiledTemplate(
false, compMeta.selector, compMeta.type, viewDirectives, viewComponentTypes,
precompileComponentTypes, pipes, this._templateNormalizer.normalizeDirective(compMeta));
@ -136,16 +208,20 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
}
private _getTransitiveCompiledTemplates(
compType: Type, isHost: boolean,
compType: Type, isHost: boolean, moduleDirectives: ConcreteType<any>[],
modulePipes: ConcreteType<any>[],
target: Set<CompiledTemplate> = new Set<CompiledTemplate>()): Set<CompiledTemplate> {
var template =
isHost ? this._getCompiledHostTemplate(compType) : this._getCompiledTemplate(compType);
var template = isHost ? this._createCompiledHostTemplate(compType) :
this._createCompiledTemplate(compType, moduleDirectives, modulePipes);
if (!target.has(template)) {
target.add(template);
template.viewComponentTypes.forEach(
(compType) => { this._getTransitiveCompiledTemplates(compType, false, target); });
template.precompileHostComponentTypes.forEach(
(compType) => { this._getTransitiveCompiledTemplates(compType, true, target); });
template.viewComponentTypes.forEach((compType) => {
this._getTransitiveCompiledTemplates(
compType, false, moduleDirectives, modulePipes, target);
});
template.precompileHostComponentTypes.forEach((compType) => {
this._getTransitiveCompiledTemplates(compType, true, moduleDirectives, modulePipes, target);
});
}
return target;
}
@ -162,7 +238,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
this._resolveStylesCompileResult(
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
var viewCompMetas = template.viewComponentTypes.map(
(compType) => this._getCompiledTemplate(compType).normalizedCompMeta);
(compType) => this._compiledTemplateCache.get(compType).normalizedCompMeta);
var parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas),
template.viewPipes, compMeta.type.name);
@ -173,12 +249,12 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
let depTemplate: CompiledTemplate;
if (dep instanceof ViewFactoryDependency) {
let vfd = <ViewFactoryDependency>dep;
depTemplate = this._getCompiledTemplate(vfd.comp.runtime);
depTemplate = this._compiledTemplateCache.get(vfd.comp.runtime);
vfd.placeholder.runtime = depTemplate.proxyViewFactory;
vfd.placeholder.name = `viewFactory_${vfd.comp.name}`;
} else if (dep instanceof ComponentFactoryDependency) {
let cfd = <ComponentFactoryDependency>dep;
depTemplate = this._getCompiledHostTemplate(cfd.comp.runtime);
depTemplate = this._compiledHostTemplateCache.get(cfd.comp.runtime);
cfd.placeholder.runtime = depTemplate.proxyComponentFactory;
cfd.placeholder.name = `compFactory_${cfd.comp.name}`;
}
@ -188,11 +264,10 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
var factory: any;
if (IS_DART || !this._genConfig.useJit) {
factory = interpretStatements(
statements, compileResult.viewFactoryVar, new InterpretiveAppViewInstanceFactory());
factory = interpretStatements(statements, compileResult.viewFactoryVar);
} else {
factory = jitStatements(
`${template.compType.name}.template.js`, statements, compileResult.viewFactoryVar);
`${template.compType.name}.ngfactory.js`, statements, compileResult.viewFactoryVar);
}
template.compiled(factory);
}
@ -213,8 +288,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
if (IS_DART || !this._genConfig.useJit) {
return interpretStatements(
result.statements, result.stylesVar, new InterpretiveAppViewInstanceFactory());
return interpretStatements(result.statements, result.stylesVar);
} else {
return jitStatements(`${result.meta.moduleUrl}.css.js`, result.statements, result.stylesVar);
}
@ -234,7 +308,7 @@ class CompiledTemplate {
public isHost: boolean, selector: string, public compType: CompileIdentifierMetadata,
public viewDirectives: CompileDirectiveMetadata[], public viewComponentTypes: Type[],
public precompileHostComponentTypes: Type[], public viewPipes: CompilePipeMetadata[],
private _normalizeResult: NormalizeDirectiveResult) {
_normalizeResult: SyncAsyncResult<CompileDirectiveMetadata>) {
this.proxyViewFactory = (...args: any[]) => this._viewFactory.apply(null, args);
this.proxyComponentFactory = isHost ?
new ComponentFactory<any>(selector, this.proxyViewFactory, compType.runtime) :

View File

@ -6,8 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CompileTokenMetadata} from './compile_metadata';
import {StringMapWrapper} from './facade/collection';
import {IS_DART, StringWrapper, isArray, isBlank, isPrimitive, isStrictStringMap} from './facade/lang';
import {IS_DART, StringWrapper, isArray, isBlank, isPresent, isPrimitive, isStrictStringMap} from './facade/lang';
import * as o from './output/output_ast';
export var MODULE_SUFFIX = IS_DART ? '.dart' : '';
@ -80,3 +82,22 @@ export function assetUrl(pkg: string, path: string = null, type: string = 'src')
}
}
}
export function createDiTokenExpression(token: CompileTokenMetadata): o.Expression {
if (isPresent(token.value)) {
return o.literal(token.value);
} else if (token.identifierIsInstance) {
return o.importExpr(token.identifier)
.instantiate([], o.importType(token.identifier, [], [o.TypeModifier.Const]));
} else {
return o.importExpr(token.identifier);
}
}
export class SyncAsyncResult<T> {
constructor(public syncResult: T, public asyncResult: Promise<T> = null) {
if (!asyncResult) {
asyncResult = Promise.resolve(syncResult);
}
}
}

View File

@ -18,10 +18,10 @@ import {CompileView} from './compile_view';
import {InjectMethodVars} from './constants';
import {CompileTokenMap, CompileDirectiveMetadata, CompileTokenMetadata, CompileQueryMetadata, CompileProviderMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata,} from '../compile_metadata';
import {getPropertyInView, createDiTokenExpression, injectFromViewParentInjector} from './util';
import {getPropertyInView, injectFromViewParentInjector} from './util';
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
import {CompileMethod} from './compile_method';
import {ValueTransformer, visitValue} from '../util';
import {createDiTokenExpression} from '../util';
export class CompileNode {
constructor(
@ -165,7 +165,7 @@ export class CompileElement extends CompileNode {
return o.importExpr(provider.useClass)
.instantiate(depsExpr, o.importType(provider.useClass));
} else {
return _convertValueToOutputAst(provider.useValue);
return o.literal(provider.useValue);
}
});
var propName = `_${resolvedProvider.token.name}_${this.nodeIndex}_${this._instances.size}`;
@ -432,30 +432,3 @@ class _QueryWithRead {
this.read = isPresent(query.meta.read) ? query.meta.read : match;
}
}
function _convertValueToOutputAst(value: any): o.Expression {
return visitValue(value, new _ValueOutputAstTransformer(), null);
}
class _ValueOutputAstTransformer extends ValueTransformer {
visitArray(arr: any[], context: any): o.Expression {
return o.literalArr(arr.map(value => visitValue(value, this, context)));
}
visitStringMap(map: {[key: string]: any}, context: any): o.Expression {
var entries: Array<string|o.Expression>[] = [];
StringMapWrapper.forEach(map, (value: any, key: string) => {
entries.push([key, visitValue(value, this, context)]);
});
return o.literalMap(entries);
}
visitPrimitive(value: any, context: any): o.Expression { return o.literal(value); }
visitOther(value: any, context: any): o.Expression {
if (value instanceof CompileIdentifierMetadata) {
return o.importExpr(value);
} else if (value instanceof o.Expression) {
return value;
} else {
throw new BaseException(`Illegal state: Don't now how to compile value ${value}`);
}
}
}

View File

@ -14,6 +14,7 @@ import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent} from '../facade/lang';
import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
import {createDiTokenExpression} from '../util';
import {CompileBinding} from './compile_binding';
import {CompileElement, CompileNode} from './compile_element';
@ -22,7 +23,7 @@ import {CompilePipe} from './compile_pipe';
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
import {EventHandlerVars} from './constants';
import {NameResolver} from './expression_converter';
import {createDiTokenExpression, createPureProxy, getPropertyInView, getViewFactoryName, injectFromViewParentInjector} from './util';
import {createPureProxy, getPropertyInView, getViewFactoryName, injectFromViewParentInjector} from './util';
export class CompileView implements NameResolver {
public viewType: ViewType;

View File

@ -13,6 +13,7 @@ import * as o from '../output/output_ast';
import {CompileTokenMetadata, CompileDirectiveMetadata,} from '../compile_metadata';
import {CompileView} from './compile_view';
import {Identifiers} from '../identifiers';
import {createDiTokenExpression} from '../util';
export function getPropertyInView(
property: o.Expression, callingView: CompileView, definedView: CompileView): o.Expression {
@ -55,18 +56,6 @@ export function getViewFactoryName(
return `viewFactory_${component.type.name}${embeddedTemplateIndex}`;
}
export function createDiTokenExpression(token: CompileTokenMetadata): o.Expression {
if (isPresent(token.value)) {
return o.literal(token.value);
} else if (token.identifierIsInstance) {
return o.importExpr(token.identifier)
.instantiate([], o.importType(token.identifier, [], [o.TypeModifier.Const]));
} else {
return o.importExpr(token.identifier);
}
}
export function createFlatArray(expressions: o.Expression[]): o.Expression {
var lastNonArrayExpressions: any[] /** TODO #9100 */ = [];
var result: o.Expression = o.literalArr([]);

View File

@ -16,11 +16,12 @@ 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 {createDiTokenExpression} from '../util';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView} from './compile_view';
import {ChangeDetectorStatusEnum, DetectChangesVars, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
import {createDiTokenExpression, createFlatArray, getViewFactoryName} from './util';
import {createFlatArray, getViewFactoryName} from './util';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
const CLASS_ATTR = 'class';