refactor(core): change module semantics

This contains major changes to the compiler, bootstrap of the platforms
and test environment initialization.

Main part of #10043
Closes #10164

BREAKING CHANGE:
- Semantics and name of `@AppModule` (now `@NgModule`) changed quite a bit.
  This is actually not breaking as `@AppModules` were not part of rc.4.
  We will have detailed docs on `@NgModule` separately.
- `coreLoadAndBootstrap` and `coreBootstrap` can't be used any more (without migration support).
  Use `bootstrapModule` / `bootstrapModuleFactory` instead.
- All Components listed in routes have to be part of the `declarations` of an NgModule.
  Either directly on the bootstrap module / lazy loaded module, or in an NgModule imported by them.
This commit is contained in:
Tobias Bosch
2016-07-18 03:50:31 -07:00
parent ca16fc29a6
commit 46b212706b
129 changed files with 3580 additions and 3366 deletions

View File

@ -22,139 +22,55 @@ import {sanitizeIdentifier, splitAtColon} from './util';
// group 1: "prop" from "[prop]"
// group 2: "event" from "(event)"
// group 3: "@trigger" from "@trigger"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/g;
const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/g;
const UNDEFINED = new Object();
export abstract class CompileMetadataWithIdentifier {
abstract toJson(): {[key: string]: any};
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
}
export abstract class CompileMetadataWithType extends CompileMetadataWithIdentifier {
abstract toJson(): {[key: string]: any};
get runtimeCacheKey(): any { return unimplemented(); }
get type(): CompileTypeMetadata { return <CompileTypeMetadata>unimplemented(); }
get assetCacheKey(): any { return unimplemented(); }
get identifier(): CompileIdentifierMetadata { return <CompileIdentifierMetadata>unimplemented(); }
}
export function metadataFromJson(data: {[key: string]: any}): any {
return (_COMPILE_METADATA_FROM_JSON as any)[data['class']](data);
equalsTo(id2: CompileMetadataWithIdentifier): boolean { return unimplemented(); }
}
export class CompileAnimationEntryMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationEntryMetadata {
var value = data['value'];
var defs = _arrayFromJson(value['definitions'], metadataFromJson);
return new CompileAnimationEntryMetadata(value['name'], defs);
}
constructor(
public name: string = null, public definitions: CompileAnimationStateMetadata[] = null) {}
toJson(): {[key: string]: any} {
return {
'class': 'AnimationEntryMetadata',
'value': {'name': this.name, 'definitions': _arrayToJson(this.definitions)}
};
}
}
export abstract class CompileAnimationStateMetadata {}
export class CompileAnimationStateDeclarationMetadata extends CompileAnimationStateMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationStateDeclarationMetadata {
var value = data['value'];
var styles = _objFromJson(value['styles'], metadataFromJson);
return new CompileAnimationStateDeclarationMetadata(value['stateNameExpr'], styles);
}
constructor(public stateNameExpr: string, public styles: CompileAnimationStyleMetadata) {
super();
}
toJson(): {[key: string]: any} {
return {
'class': 'AnimationStateDeclarationMetadata',
'value': {'stateNameExpr': this.stateNameExpr, 'styles': this.styles.toJson()}
};
}
}
export class CompileAnimationStateTransitionMetadata extends CompileAnimationStateMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationStateTransitionMetadata {
var value = data['value'];
var steps = _objFromJson(value['steps'], metadataFromJson);
return new CompileAnimationStateTransitionMetadata(value['stateChangeExpr'], steps);
}
constructor(public stateChangeExpr: string, public steps: CompileAnimationMetadata) { super(); }
toJson(): {[key: string]: any} {
return {
'class': 'AnimationStateTransitionMetadata',
'value': {'stateChangeExpr': this.stateChangeExpr, 'steps': this.steps.toJson()}
};
}
}
export abstract class CompileAnimationMetadata { abstract toJson(): {[key: string]: any}; }
export abstract class CompileAnimationMetadata {}
export class CompileAnimationKeyframesSequenceMetadata extends CompileAnimationMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationKeyframesSequenceMetadata {
var steps = _arrayFromJson(data['value'], metadataFromJson);
return new CompileAnimationKeyframesSequenceMetadata(<CompileAnimationStyleMetadata[]>steps);
}
constructor(public steps: CompileAnimationStyleMetadata[] = []) { super(); }
toJson(): {[key: string]: any} {
return {'class': 'AnimationKeyframesSequenceMetadata', 'value': _arrayToJson(this.steps)};
}
}
export class CompileAnimationStyleMetadata extends CompileAnimationMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationStyleMetadata {
var value = data['value'];
var offsetVal = value['offset'];
var offset = isPresent(offsetVal) ? NumberWrapper.parseFloat(offsetVal) : null;
var styles = <Array<string|{[key: string]: string | number}>>value['styles'];
return new CompileAnimationStyleMetadata(offset, styles);
}
constructor(
public offset: number, public styles: Array<string|{[key: string]: string | number}> = null) {
super();
}
toJson(): {[key: string]: any} {
return {
'class': 'AnimationStyleMetadata',
'value': {'offset': this.offset, 'styles': this.styles}
};
}
}
export class CompileAnimationAnimateMetadata extends CompileAnimationMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationAnimateMetadata {
var value = data['value'];
var timings = <string|number>value['timings'];
var styles = _objFromJson(value['styles'], metadataFromJson);
return new CompileAnimationAnimateMetadata(timings, styles);
}
constructor(
public timings: string|number = 0, public styles: CompileAnimationStyleMetadata|
CompileAnimationKeyframesSequenceMetadata = null) {
super();
}
toJson(): {[key: string]: any} {
return {
'class': 'AnimationAnimateMetadata',
'value': {'timings': this.timings, 'styles': _objToJson(this.styles)}
};
}
}
export abstract class CompileAnimationWithStepsMetadata extends CompileAnimationMetadata {
@ -162,29 +78,11 @@ export abstract class CompileAnimationWithStepsMetadata extends CompileAnimation
}
export class CompileAnimationSequenceMetadata extends CompileAnimationWithStepsMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationSequenceMetadata {
var steps = _arrayFromJson(data['value'], metadataFromJson);
return new CompileAnimationSequenceMetadata(steps);
}
constructor(steps: CompileAnimationMetadata[] = null) { super(steps); }
toJson(): {[key: string]: any} {
return {'class': 'AnimationSequenceMetadata', 'value': _arrayToJson(this.steps)};
}
}
export class CompileAnimationGroupMetadata extends CompileAnimationWithStepsMetadata {
static fromJson(data: {[key: string]: any}): CompileAnimationGroupMetadata {
var steps = _arrayFromJson(data['value'], metadataFromJson);
return new CompileAnimationGroupMetadata(steps);
}
constructor(steps: CompileAnimationMetadata[] = null) { super(steps); }
toJson(): {[key: string]: any} {
return {'class': 'AnimationGroupMetadata', 'value': _arrayToJson(this.steps)};
}
}
export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier {
@ -193,6 +91,7 @@ export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier
prefix: string;
moduleUrl: string;
value: any;
private _assetCacheKey: any = UNDEFINED;
constructor(
{runtime, name, moduleUrl, prefix, value}:
@ -204,26 +103,28 @@ export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier
this.value = value;
}
static fromJson(data: {[key: string]: any}): CompileIdentifierMetadata {
let value = isArray(data['value']) ? _arrayFromJson(data['value'], metadataFromJson) :
_objFromJson(data['value'], metadataFromJson);
return new CompileIdentifierMetadata(
{name: data['name'], prefix: data['prefix'], moduleUrl: data['moduleUrl'], value: value});
}
toJson(): {[key: string]: any} {
let value = isArray(this.value) ? _arrayToJson(this.value) : _objToJson(this.value);
return {
// Note: Runtime type can't be serialized...
'class': 'Identifier',
'name': this.name,
'moduleUrl': this.moduleUrl,
'prefix': this.prefix,
'value': value
};
}
get identifier(): CompileIdentifierMetadata { return this; }
get runtimeCacheKey(): any { return this.identifier.runtime; }
get assetCacheKey(): any {
if (this._assetCacheKey === UNDEFINED) {
if (isPresent(this.moduleUrl) && isPresent(getUrlScheme(this.moduleUrl))) {
var uri = reflector.importUri({'filePath': this.moduleUrl, 'name': this.name});
this._assetCacheKey = `${this.name}|${uri}`;
} else {
this._assetCacheKey = null;
}
}
return this._assetCacheKey;
}
equalsTo(id2: CompileIdentifierMetadata): boolean {
var rk = this.runtimeCacheKey;
var ak = this.assetCacheKey;
return (isPresent(rk) && rk == id2.runtimeCacheKey) ||
(isPresent(ak) && ak == id2.assetCacheKey);
}
}
export class CompileDiDependencyMetadata {
@ -263,36 +164,6 @@ export class CompileDiDependencyMetadata {
this.token = token;
this.value = value;
}
static fromJson(data: {[key: string]: any}): CompileDiDependencyMetadata {
return new CompileDiDependencyMetadata({
token: _objFromJson(data['token'], CompileTokenMetadata.fromJson),
query: _objFromJson(data['query'], CompileQueryMetadata.fromJson),
viewQuery: _objFromJson(data['viewQuery'], CompileQueryMetadata.fromJson),
value: data['value'],
isAttribute: data['isAttribute'],
isSelf: data['isSelf'],
isHost: data['isHost'],
isSkipSelf: data['isSkipSelf'],
isOptional: data['isOptional'],
isValue: data['isValue']
});
}
toJson(): {[key: string]: any} {
return {
'token': _objToJson(this.token),
'query': _objToJson(this.query),
'viewQuery': _objToJson(this.viewQuery),
'value': this.value,
'isAttribute': this.isAttribute,
'isSelf': this.isSelf,
'isHost': this.isHost,
'isSkipSelf': this.isSkipSelf,
'isOptional': this.isOptional,
'isValue': this.isValue
};
}
}
export class CompileProviderMetadata {
@ -321,41 +192,9 @@ export class CompileProviderMetadata {
this.deps = normalizeBlank(deps);
this.multi = normalizeBool(multi);
}
static fromJson(data: {[key: string]: any}): CompileProviderMetadata {
return new CompileProviderMetadata({
token: _objFromJson(data['token'], CompileTokenMetadata.fromJson),
useClass: _objFromJson(data['useClass'], CompileTypeMetadata.fromJson),
useExisting: _objFromJson(data['useExisting'], CompileTokenMetadata.fromJson),
useValue: _objFromJson(data['useValue'], CompileIdentifierMetadata.fromJson),
useFactory: _objFromJson(data['useFactory'], CompileFactoryMetadata.fromJson),
multi: data['multi'],
deps: _arrayFromJson(data['deps'], CompileDiDependencyMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'class': 'Provider',
'token': _objToJson(this.token),
'useClass': _objToJson(this.useClass),
'useExisting': _objToJson(this.useExisting),
'useValue': _objToJson(this.useValue),
'useFactory': _objToJson(this.useFactory),
'multi': this.multi,
'deps': _arrayToJson(this.deps)
};
}
}
export class CompileFactoryMetadata implements CompileIdentifierMetadata,
CompileMetadataWithIdentifier {
runtime: Function;
name: string;
prefix: string;
moduleUrl: string;
value: any;
export class CompileFactoryMetadata extends CompileIdentifierMetadata {
diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, diDeps, value}: {
@ -366,45 +205,15 @@ export class CompileFactoryMetadata implements CompileIdentifierMetadata,
value?: boolean,
diDeps?: CompileDiDependencyMetadata[]
}) {
this.runtime = runtime;
this.name = name;
this.prefix = prefix;
this.moduleUrl = moduleUrl;
super({runtime: runtime, name: name, prefix: prefix, moduleUrl: moduleUrl, value: value});
this.diDeps = _normalizeArray(diDeps);
this.value = value;
}
get identifier(): CompileIdentifierMetadata { return this; }
static fromJson(data: {[key: string]: any}): CompileFactoryMetadata {
return new CompileFactoryMetadata({
name: data['name'],
prefix: data['prefix'],
moduleUrl: data['moduleUrl'],
value: data['value'],
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'class': 'Factory',
'name': this.name,
'prefix': this.prefix,
'moduleUrl': this.moduleUrl,
'value': this.value,
'diDeps': _arrayToJson(this.diDeps)
};
}
}
var UNDEFINED = new Object();
export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
value: any;
identifier: CompileIdentifierMetadata;
identifierIsInstance: boolean;
private _assetCacheKey = UNDEFINED;
constructor(
{value, identifier, identifierIsInstance}:
@ -414,46 +223,20 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
this.identifierIsInstance = normalizeBool(identifierIsInstance);
}
static fromJson(data: {[key: string]: any}): CompileTokenMetadata {
return new CompileTokenMetadata({
value: data['value'],
identifier: _objFromJson(data['identifier'], CompileIdentifierMetadata.fromJson),
identifierIsInstance: data['identifierIsInstance']
});
}
toJson(): {[key: string]: any} {
return {
'value': this.value,
'identifier': _objToJson(this.identifier),
'identifierIsInstance': this.identifierIsInstance
};
}
get runtimeCacheKey(): any {
if (isPresent(this.identifier)) {
return this.identifier.runtime;
return this.identifier.runtimeCacheKey;
} else {
return this.value;
}
}
get assetCacheKey(): any {
if (this._assetCacheKey === UNDEFINED) {
if (isPresent(this.identifier)) {
if (isPresent(this.identifier.moduleUrl) &&
isPresent(getUrlScheme(this.identifier.moduleUrl))) {
var uri = reflector.importUri(
{'filePath': this.identifier.moduleUrl, 'name': this.identifier.name});
this._assetCacheKey = `${this.identifier.name}|${uri}|${this.identifierIsInstance}`;
} else {
this._assetCacheKey = null;
}
} else {
this._assetCacheKey = this.value;
}
if (isPresent(this.identifier)) {
return this.identifier.assetCacheKey;
} else {
return this.value;
}
return this._assetCacheKey;
}
equalsTo(token2: CompileTokenMetadata): boolean {
@ -468,15 +251,24 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier {
}
}
export class CompileTokenMap<VALUE> {
/**
* Note: We only need this in places where we need to support identifiers that
* don't have a `runtime` value given by the `StaticReflector`. E.g. see the `identifiers`
* file where we have some identifiers hard coded by name/module path.
*
* TODO(tbosch): Eventually, all of these places should go through the static reflector
* as well, providing them with a valid `StaticSymbol` that is again a singleton.
*/
export class CompileIdentifierMap<KEY extends CompileMetadataWithIdentifier, VALUE> {
private _valueMap = new Map<any, VALUE>();
private _values: VALUE[] = [];
private _tokens: CompileTokenMetadata[] = [];
private _tokens: KEY[] = [];
add(token: CompileTokenMetadata, value: VALUE) {
add(token: KEY, value: VALUE) {
var existing = this.get(token);
if (isPresent(existing)) {
throw new BaseException(`Can only add to a TokenMap! Token: ${token.name}`);
throw new BaseException(
`Cannot overwrite in a CompileIdentifierMap! Token: ${token.identifier.name}`);
}
this._tokens.push(token);
this._values.push(value);
@ -489,7 +281,7 @@ export class CompileTokenMap<VALUE> {
this._valueMap.set(ak, value);
}
}
get(token: CompileTokenMetadata): VALUE {
get(token: KEY): VALUE {
var rk = token.runtimeCacheKey;
var ak = token.assetCacheKey;
var result: VALUE;
@ -501,7 +293,7 @@ export class CompileTokenMap<VALUE> {
}
return result;
}
keys(): CompileTokenMetadata[] { return this._tokens; }
keys(): KEY[] { return this._tokens; }
values(): VALUE[] { return this._values; }
get size(): number { return this._values.length; }
}
@ -509,13 +301,8 @@ export class CompileTokenMap<VALUE> {
/**
* Metadata regarding compilation of a type.
*/
export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMetadataWithType {
runtime: Type;
name: string;
prefix: string;
moduleUrl: string;
export class CompileTypeMetadata extends CompileIdentifierMetadata {
isHost: boolean;
value: any;
diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, isHost, value, diDeps}: {
@ -527,41 +314,10 @@ export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMe
value?: any,
diDeps?: CompileDiDependencyMetadata[]
} = {}) {
this.runtime = runtime;
this.name = name;
this.moduleUrl = moduleUrl;
this.prefix = prefix;
super({runtime: runtime, name: name, moduleUrl: moduleUrl, prefix: prefix, value: value});
this.isHost = normalizeBool(isHost);
this.value = value;
this.diDeps = _normalizeArray(diDeps);
}
static fromJson(data: {[key: string]: any}): CompileTypeMetadata {
return new CompileTypeMetadata({
name: data['name'],
moduleUrl: data['moduleUrl'],
prefix: data['prefix'],
isHost: data['isHost'],
value: data['value'],
diDeps: _arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
});
}
get identifier(): CompileIdentifierMetadata { return this; }
get type(): CompileTypeMetadata { return this; }
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'class': 'Type',
'name': this.name,
'moduleUrl': this.moduleUrl,
'prefix': this.prefix,
'isHost': this.isHost,
'value': this.value,
'diDeps': _arrayToJson(this.diDeps)
};
}
}
export class CompileQueryMetadata {
@ -584,26 +340,6 @@ export class CompileQueryMetadata {
this.propertyName = propertyName;
this.read = read;
}
static fromJson(data: {[key: string]: any}): CompileQueryMetadata {
return new CompileQueryMetadata({
selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson),
descendants: data['descendants'],
first: data['first'],
propertyName: data['propertyName'],
read: _objFromJson(data['read'], CompileTokenMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
'selectors': _arrayToJson(this.selectors),
'descendants': this.descendants,
'first': this.first,
'propertyName': this.propertyName,
'read': _objToJson(this.read)
};
}
}
/**
@ -620,15 +356,6 @@ export class CompileStylesheetMetadata {
this.styles = _normalizeArray(styles);
this.styleUrls = _normalizeArray(styleUrls);
}
static fromJson(data: {[key: string]: any}): CompileStylesheetMetadata {
return new CompileStylesheetMetadata(
{moduleUrl: data['moduleUrl'], styles: data['styles'], styleUrls: data['styleUrls']});
}
toJson(): {[key: string]: any} {
return {'moduleUrl': this.moduleUrl, 'styles': this.styles, 'styleUrls': this.styleUrls};
}
}
/**
@ -670,46 +397,12 @@ export class CompileTemplateMetadata {
}
this.interpolation = interpolation;
}
static fromJson(data: {[key: string]: any}): CompileTemplateMetadata {
var animations =
<CompileAnimationEntryMetadata[]>_arrayFromJson(data['animations'], metadataFromJson);
return new CompileTemplateMetadata({
encapsulation: isPresent(data['encapsulation']) ?
VIEW_ENCAPSULATION_VALUES[data['encapsulation']] :
data['encapsulation'],
template: data['template'],
templateUrl: data['templateUrl'],
styles: data['styles'],
styleUrls: data['styleUrls'],
externalStylesheets:
_arrayFromJson(data['externalStylesheets'], CompileStylesheetMetadata.fromJson),
animations: animations,
ngContentSelectors: data['ngContentSelectors'],
interpolation: data['interpolation']
});
}
toJson(): {[key: string]: any} {
return {
'encapsulation': isPresent(this.encapsulation) ? serializeEnum(this.encapsulation) :
this.encapsulation,
'template': this.template,
'templateUrl': this.templateUrl,
'styles': this.styles,
'styleUrls': this.styleUrls,
'externalStylesheets': _objToJson(this.externalStylesheets),
'animations': _objToJson(this.animations),
'ngContentSelectors': this.ngContentSelectors,
'interpolation': this.interpolation
};
}
}
/**
* Metadata regarding compilation of a directive.
*/
export class CompileDirectiveMetadata implements CompileMetadataWithType {
export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
static create(
{type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
lifecycleHooks, providers, viewProviders, queries, viewQueries, precompile, template}: {
@ -796,6 +489,7 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[];
viewQueries: CompileQueryMetadata[];
// Note: Need to keep types here to prevent cycles!
precompile: CompileTypeMetadata[];
template: CompileTemplateMetadata;
@ -844,68 +538,26 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
get identifier(): CompileIdentifierMetadata { return this.type; }
static fromJson(data: {[key: string]: any}): CompileDirectiveMetadata {
return new CompileDirectiveMetadata({
isComponent: data['isComponent'],
selector: data['selector'],
exportAs: data['exportAs'],
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
changeDetection: isPresent(data['changeDetection']) ?
CHANGE_DETECTION_STRATEGY_VALUES[data['changeDetection']] :
data['changeDetection'],
inputs: data['inputs'],
outputs: data['outputs'],
hostListeners: data['hostListeners'],
hostProperties: data['hostProperties'],
hostAttributes: data['hostAttributes'],
lifecycleHooks:
(<any[]>data['lifecycleHooks']).map(hookValue => LIFECYCLE_HOOKS_VALUES[hookValue]),
template: isPresent(data['template']) ? CompileTemplateMetadata.fromJson(data['template']) :
data['template'],
providers: _arrayFromJson(data['providers'], metadataFromJson),
viewProviders: _arrayFromJson(data['viewProviders'], metadataFromJson),
queries: _arrayFromJson(data['queries'], CompileQueryMetadata.fromJson),
viewQueries: _arrayFromJson(data['viewQueries'], CompileQueryMetadata.fromJson),
precompile: _arrayFromJson(data['precompile'], CompileTypeMetadata.fromJson)
});
}
get runtimeCacheKey(): any { return this.type.runtimeCacheKey; }
toJson(): {[key: string]: any} {
return {
'class': 'Directive',
'isComponent': this.isComponent,
'selector': this.selector,
'exportAs': this.exportAs,
'type': isPresent(this.type) ? this.type.toJson() : this.type,
'changeDetection': isPresent(this.changeDetection) ? serializeEnum(this.changeDetection) :
this.changeDetection,
'inputs': this.inputs,
'outputs': this.outputs,
'hostListeners': this.hostListeners,
'hostProperties': this.hostProperties,
'hostAttributes': this.hostAttributes,
'lifecycleHooks': this.lifecycleHooks.map(hook => serializeEnum(hook)),
'template': isPresent(this.template) ? this.template.toJson() : this.template,
'providers': _arrayToJson(this.providers),
'viewProviders': _arrayToJson(this.viewProviders),
'queries': _arrayToJson(this.queries),
'viewQueries': _arrayToJson(this.viewQueries),
'precompile': _arrayToJson(this.precompile)
};
get assetCacheKey(): any { return this.type.assetCacheKey; }
equalsTo(other: CompileMetadataWithIdentifier): boolean {
return this.type.equalsTo(other.identifier);
}
}
/**
* Construct {@link CompileDirectiveMetadata} from {@link ComponentTypeMetadata} and a selector.
*/
export function createHostComponentMeta(
componentType: CompileTypeMetadata, componentSelector: string): CompileDirectiveMetadata {
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate();
export function createHostComponentMeta(compMeta: CompileDirectiveMetadata):
CompileDirectiveMetadata {
var template = CssSelector.parse(compMeta.selector)[0].getMatchingElementTemplate();
return CompileDirectiveMetadata.create({
type: new CompileTypeMetadata({
runtime: Object,
name: `${componentType.name}_Host`,
moduleUrl: componentType.moduleUrl,
name: `${compMeta.type.name}_Host`,
moduleUrl: compMeta.type.moduleUrl,
isHost: true
}),
template: new CompileTemplateMetadata({
@ -931,7 +583,7 @@ export function createHostComponentMeta(
}
export class CompilePipeMetadata implements CompileMetadataWithType {
export class CompilePipeMetadata implements CompileMetadataWithIdentifier {
type: CompileTypeMetadata;
name: string;
pure: boolean;
@ -949,114 +601,91 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
this.lifecycleHooks = _normalizeArray(lifecycleHooks);
}
get identifier(): CompileIdentifierMetadata { return this.type; }
get runtimeCacheKey(): any { return this.type.runtimeCacheKey; }
static fromJson(data: {[key: string]: any}): CompilePipeMetadata {
return new CompilePipeMetadata({
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
name: data['name'],
pure: data['pure']
});
}
get assetCacheKey(): any { return this.type.assetCacheKey; }
toJson(): {[key: string]: any} {
return {
'class': 'Pipe',
'type': isPresent(this.type) ? this.type.toJson() : null,
'name': this.name,
'pure': this.pure
};
equalsTo(other: CompileMetadataWithIdentifier): boolean {
return this.type.equalsTo(other.identifier);
}
}
/**
* Metadata regarding compilation of a directive.
*/
export class CompileAppModuleMetadata implements CompileMetadataWithType {
export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
type: CompileTypeMetadata;
providers: CompileProviderMetadata[];
directives: CompileTypeMetadata[];
pipes: CompileTypeMetadata[];
declaredDirectives: CompileDirectiveMetadata[];
exportedDirectives: CompileDirectiveMetadata[];
declaredPipes: CompilePipeMetadata[];
exportedPipes: CompilePipeMetadata[];
// Note: See CompileDirectiveMetadata.precompile why this has to be a type.
precompile: CompileTypeMetadata[];
modules: CompileTypeMetadata[];
providers: CompileProviderMetadata[];
constructor({type, providers, directives, pipes, precompile, modules}: {
type?: CompileTypeMetadata,
providers?: Array<CompileProviderMetadata|CompileTypeMetadata|CompileIdentifierMetadata|any[]>,
directives?: CompileTypeMetadata[],
pipes?: CompileTypeMetadata[],
precompile?: CompileTypeMetadata[],
modules?: CompileTypeMetadata[]
} = {}) {
importedModules: CompileNgModuleMetadata[];
exportedModules: CompileNgModuleMetadata[];
transitiveModule: TransitiveCompileNgModuleMetadata;
constructor(
{type, providers, declaredDirectives, exportedDirectives, declaredPipes, exportedPipes,
precompile, importedModules, exportedModules, transitiveModule}: {
type?: CompileTypeMetadata,
providers?:
Array<CompileProviderMetadata|CompileTypeMetadata|CompileIdentifierMetadata|any[]>,
declaredDirectives?: CompileDirectiveMetadata[],
exportedDirectives?: CompileDirectiveMetadata[],
declaredPipes?: CompilePipeMetadata[],
exportedPipes?: CompilePipeMetadata[],
precompile?: CompileTypeMetadata[],
importedModules?: CompileNgModuleMetadata[],
exportedModules?: CompileNgModuleMetadata[],
transitiveModule?: TransitiveCompileNgModuleMetadata
} = {}) {
this.type = type;
this.directives = _normalizeArray(directives);
this.pipes = _normalizeArray(pipes);
this.declaredDirectives = _normalizeArray(declaredDirectives);
this.exportedDirectives = _normalizeArray(exportedDirectives);
this.declaredPipes = _normalizeArray(declaredPipes);
this.exportedPipes = _normalizeArray(exportedPipes);
this.providers = _normalizeArray(providers);
this.precompile = _normalizeArray(precompile);
this.modules = _normalizeArray(modules);
this.importedModules = _normalizeArray(importedModules);
this.exportedModules = _normalizeArray(exportedModules);
this.transitiveModule = transitiveModule;
}
get identifier(): CompileIdentifierMetadata { return this.type; }
get runtimeCacheKey(): any { return this.type.runtimeCacheKey; }
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)
});
}
get assetCacheKey(): any { return this.type.assetCacheKey; }
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)
};
equalsTo(other: CompileMetadataWithIdentifier): boolean {
return this.type.equalsTo(other.identifier);
}
}
var _COMPILE_METADATA_FROM_JSON = {
'AppModule': CompileAppModuleMetadata.fromJson,
'Directive': CompileDirectiveMetadata.fromJson,
'Pipe': CompilePipeMetadata.fromJson,
'Type': CompileTypeMetadata.fromJson,
'Provider': CompileProviderMetadata.fromJson,
'Identifier': CompileIdentifierMetadata.fromJson,
'Factory': CompileFactoryMetadata.fromJson,
'AnimationEntryMetadata': CompileAnimationEntryMetadata.fromJson,
'AnimationStateDeclarationMetadata': CompileAnimationStateDeclarationMetadata.fromJson,
'AnimationStateTransitionMetadata': CompileAnimationStateTransitionMetadata.fromJson,
'AnimationSequenceMetadata': CompileAnimationSequenceMetadata.fromJson,
'AnimationGroupMetadata': CompileAnimationGroupMetadata.fromJson,
'AnimationAnimateMetadata': CompileAnimationAnimateMetadata.fromJson,
'AnimationStyleMetadata': CompileAnimationStyleMetadata.fromJson,
'AnimationKeyframesSequenceMetadata': CompileAnimationKeyframesSequenceMetadata.fromJson
};
function _arrayFromJson(obj: any[], fn: (a: {[key: string]: any}) => any): any {
return isBlank(obj) ? null : obj.map(o => _objFromJson(o, fn));
export class TransitiveCompileNgModuleMetadata {
directivesSet = new Set<Type>();
pipesSet = new Set<Type>();
constructor(
public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
public precompile: CompileTypeMetadata[], public directives: CompileDirectiveMetadata[],
public pipes: CompilePipeMetadata[]) {
directives.forEach(dir => this.directivesSet.add(dir.type.runtime));
pipes.forEach(pipe => this.pipesSet.add(pipe.type.runtime));
}
}
function _arrayToJson(obj: any[]): string|{[key: string]: any} {
return isBlank(obj) ? null : obj.map(_objToJson);
}
function _objFromJson(obj: any, fn: (a: {[key: string]: any}) => any): any {
if (isArray(obj)) return _arrayFromJson(obj, fn);
if (isString(obj) || isBlank(obj) || isBoolean(obj) || isNumber(obj)) return obj;
return fn(obj);
}
function _objToJson(obj: any): string|{[key: string]: any} {
if (isArray(obj)) return _arrayToJson(obj);
if (isString(obj) || isBlank(obj) || isBoolean(obj) || isNumber(obj)) return obj;
return obj.toJson();
export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifier>(items: T[]):
T[] {
const map = new CompileIdentifierMap<T, T>();
items.forEach((item) => {
if (!map.get(item)) {
map.add(item, item);
}
});
return map.keys();
}
function _normalizeArray(obj: any[]): any[] {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Compiler, CompilerFactory, CompilerOptions, ComponentResolver, Injectable, PLATFORM_DIRECTIVES, PLATFORM_PIPES, ReflectiveInjector, Type, ViewEncapsulation, isDevMode} from '@angular/core';
import {Compiler, CompilerFactory, CompilerOptions, Component, ComponentResolver, Inject, Injectable, NgModule, PLATFORM_DIRECTIVES, PLATFORM_INITIALIZER, PLATFORM_PIPES, PlatformRef, ReflectiveInjector, Type, ViewEncapsulation, corePlatform, createPlatformFactory, disposePlatform, isDevMode} from '@angular/core';
export * from './template_ast';
export {TEMPLATE_TRANSFORMS} from './template_parser';
@ -20,14 +20,17 @@ export * from './xhr';
export {ViewResolver} from './view_resolver';
export {DirectiveResolver} from './directive_resolver';
export {PipeResolver} from './pipe_resolver';
export {NgModuleResolver} from './ng_module_resolver';
import {stringify} from './facade/lang';
import {ListWrapper} from './facade/collection';
import {TemplateParser} from './template_parser';
import {HtmlParser} from './html_parser';
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 {NgModuleCompiler} from './ng_module_compiler';
import {CompilerConfig} from './config';
import {RuntimeCompiler} from './runtime_compiler';
import {ElementSchemaRegistry} from './schema/element_schema_registry';
@ -38,19 +41,24 @@ import {Lexer} from './expression_parser/lexer';
import {ViewResolver} from './view_resolver';
import {DirectiveResolver} from './directive_resolver';
import {PipeResolver} from './pipe_resolver';
import {Console, Reflector, reflector, ReflectorReader} from '../core_private';
import {NgModuleResolver} from './ng_module_resolver';
import {Console, Reflector, reflector, ReflectorReader, ReflectionCapabilities} from '../core_private';
import {XHR} from './xhr';
const _NO_XHR: XHR = {
get(url: string): Promise<string>{
throw new Error(`No XHR implementation has been provided. Can't read the url "${url}"`);}
};
/**
* A set of providers that provide `RuntimeCompiler` and its dependencies to use for
* template compilation.
*/
export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
/*@ts2dart_const*/[
{provide: PLATFORM_DIRECTIVES, useValue: [], multi: true},
{provide: PLATFORM_PIPES, useValue: [], multi: true},
{provide: Reflector, useValue: reflector},
{provide: ReflectorReader, useExisting: Reflector},
{provide: XHR, useValue: _NO_XHR},
Console,
Lexer,
Parser,
@ -61,112 +69,153 @@ export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
ViewCompiler,
AppModuleCompiler,
NgModuleCompiler,
/*@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
PipeResolver,
NgModuleResolver
];
export function analyzeAppProvidersForDeprecatedConfiguration(appProviders: any[] = []):
{compilerOptions: CompilerOptions, moduleDeclarations: Type[], deprecationMessages: string[]} {
let platformDirectives: any[] = [];
let platformPipes: any[] = [];
let compilerProviders: any[] = [];
let useDebug: boolean;
let useJit: boolean;
let defaultEncapsulation: ViewEncapsulation;
const deprecationMessages: string[] = [];
// Note: This is a hack to still support the old way
// of configuring platform directives / pipes and the compiler xhr.
// This will soon be deprecated!
const tempInj = ReflectiveInjector.resolveAndCreate(appProviders);
const compilerConfig: CompilerConfig = tempInj.get(CompilerConfig, null);
if (compilerConfig) {
platformDirectives = compilerConfig.platformDirectives;
platformPipes = compilerConfig.platformPipes;
useJit = compilerConfig.useJit;
useDebug = compilerConfig.genDebugInfo;
defaultEncapsulation = compilerConfig.defaultEncapsulation;
deprecationMessages.push(
`Passing CompilerConfig as a regular provider is deprecated. Use the "compilerOptions" parameter of "bootstrap()" or use a custom "CompilerFactory" platform provider instead.`);
} else {
// If nobody provided a CompilerConfig, use the
// PLATFORM_DIRECTIVES / PLATFORM_PIPES values directly if existing
platformDirectives = tempInj.get(PLATFORM_DIRECTIVES, []);
platformPipes = tempInj.get(PLATFORM_PIPES, []);
}
platformDirectives = ListWrapper.flatten(platformDirectives);
platformPipes = ListWrapper.flatten(platformPipes);
const xhr = tempInj.get(XHR, null);
if (xhr) {
compilerProviders.push([{provide: XHR, useValue: xhr}]);
deprecationMessages.push(
`Passing XHR as regular provider is deprecated. Pass the provider via "compilerOptions" instead.`);
}
if (platformDirectives.length > 0) {
deprecationMessages.push(
`The PLATFORM_DIRECTIVES provider and CompilerConfig.platformDirectives is deprecated. Add the directives to an NgModule instead! ` +
`(Directives: ${platformDirectives.map(type => stringify(type))})`);
}
if (platformPipes.length > 0) {
deprecationMessages.push(
`The PLATFORM_PIPES provider and CompilerConfig.platformPipes is deprecated. Add the pipes to an NgModule instead! ` +
`(Pipes: ${platformPipes.map(type => stringify(type))})`);
}
const compilerOptions: CompilerOptions = {
useJit: useJit,
useDebug: useDebug,
defaultEncapsulation: defaultEncapsulation,
providers: compilerProviders
};
// Declare a component that uses @Component.directives / pipes as these
// will be added to the module declarations only if they are not already
// imported by other modules.
@Component({directives: platformDirectives, pipes: platformPipes, template: ''})
class DynamicComponent {
}
return {
compilerOptions,
moduleDeclarations: [DynamicComponent],
deprecationMessages: deprecationMessages
};
}
@Injectable()
export class _RuntimeCompilerFactory extends CompilerFactory {
createCompiler(options: CompilerOptions): Compiler {
const deprecationMessages: string[] = [];
let platformDirectivesFromAppProviders: any[] = [];
let platformPipesFromAppProviders: any[] = [];
let compilerProvidersFromAppProviders: any[] = [];
let useDebugFromAppProviders: boolean;
let useJitFromAppProviders: boolean;
let defaultEncapsulationFromAppProviders: ViewEncapsulation;
if (options.deprecatedAppProviders && options.deprecatedAppProviders.length > 0) {
// Note: This is a hack to still support the old way
// of configuring platform directives / pipes and the compiler xhr.
// This will soon be deprecated!
const inj = ReflectiveInjector.resolveAndCreate(options.deprecatedAppProviders);
const compilerConfig: CompilerConfig = inj.get(CompilerConfig, null);
if (compilerConfig) {
platformDirectivesFromAppProviders = compilerConfig.deprecatedPlatformDirectives;
platformPipesFromAppProviders = compilerConfig.deprecatedPlatformPipes;
useJitFromAppProviders = compilerConfig.useJit;
useDebugFromAppProviders = compilerConfig.genDebugInfo;
defaultEncapsulationFromAppProviders = compilerConfig.defaultEncapsulation;
deprecationMessages.push(
`Passing a CompilerConfig to "bootstrap()" as provider is deprecated. Pass the provider via the new parameter "compilerOptions" of "bootstrap()" instead.`);
} else {
// If nobody provided a CompilerConfig, use the
// PLATFORM_DIRECTIVES / PLATFORM_PIPES values directly if existing
platformDirectivesFromAppProviders = inj.get(PLATFORM_DIRECTIVES, []);
if (platformDirectivesFromAppProviders.length > 0) {
deprecationMessages.push(
`Passing PLATFORM_DIRECTIVES to "bootstrap()" as provider is deprecated. Use the new parameter "directives" of "bootstrap()" instead.`);
}
platformPipesFromAppProviders = inj.get(PLATFORM_PIPES, []);
if (platformPipesFromAppProviders.length > 0) {
deprecationMessages.push(
`Passing PLATFORM_PIPES to "bootstrap()" as provider is deprecated. Use the new parameter "pipes" of "bootstrap()" instead.`);
}
}
const xhr = inj.get(XHR, null);
if (xhr) {
compilerProvidersFromAppProviders.push([{provide: XHR, useValue: xhr}]);
deprecationMessages.push(
`Passing an instance of XHR to "bootstrap()" as provider is deprecated. Pass the provider via the new parameter "compilerOptions" of "bootstrap()" instead.`);
}
// Need to copy console from deprecatedAppProviders to compiler providers
// as well so that we can test the above deprecation messages in old style bootstrap
// where we only have app providers!
const console = inj.get(Console, null);
if (console) {
compilerProvidersFromAppProviders.push([{provide: Console, useValue: console}]);
}
}
export class RuntimeCompilerFactory implements CompilerFactory {
private _defaultOptions: CompilerOptions[];
constructor(@Inject(CompilerOptions) defaultOptions: CompilerOptions[]) {
this._defaultOptions = [<CompilerOptions>{
useDebug: isDevMode(),
useJit: true,
defaultEncapsulation: ViewEncapsulation.Emulated
}].concat(defaultOptions);
}
createCompiler(options: CompilerOptions[] = []): Compiler {
const mergedOptions = _mergeOptions(this._defaultOptions.concat(options));
const injector = ReflectiveInjector.resolveAndCreate([
COMPILER_PROVIDERS, {
provide: CompilerConfig,
useFactory: (platformDirectives: any[], platformPipes: any[]) => {
useFactory: () => {
return new CompilerConfig({
deprecatedPlatformDirectives:
_mergeArrays(platformDirectivesFromAppProviders, platformDirectives),
deprecatedPlatformPipes: _mergeArrays(platformPipesFromAppProviders, platformPipes),
// let explicit values from the compiler options overwrite options
// from the app providers. E.g. important for the testing platform.
genDebugInfo: _firstDefined(options.useDebug, useDebugFromAppProviders, isDevMode()),
genDebugInfo: mergedOptions.useDebug,
// let explicit values from the compiler options overwrite options
// from the app providers
useJit: _firstDefined(options.useJit, useJitFromAppProviders, true),
useJit: mergedOptions.useJit,
// let explicit values from the compiler options overwrite options
// from the app providers
defaultEncapsulation: _firstDefined(
options.defaultEncapsulation, defaultEncapsulationFromAppProviders,
ViewEncapsulation.Emulated)
defaultEncapsulation: mergedOptions.defaultEncapsulation,
logBindingUpdate: mergedOptions.useDebug
});
},
deps: [PLATFORM_DIRECTIVES, PLATFORM_PIPES]
deps: []
},
// options.providers will always contain a provider for XHR as well
// (added by platforms). So allow compilerProvidersFromAppProviders to overwrite this
_mergeArrays(options.providers, compilerProvidersFromAppProviders)
mergedOptions.providers
]);
const console: Console = injector.get(Console);
deprecationMessages.forEach((msg) => { console.warn(msg); });
return injector.get(Compiler);
}
}
function _initReflector() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
}
export const RUNTIME_COMPILER_FACTORY = new _RuntimeCompilerFactory();
/**
* A platform that included corePlatform and the compiler.
*
* @experimental
*/
export const coreDynamicPlatform = createPlatformFactory(corePlatform, 'coreDynamic', [
{provide: CompilerOptions, useValue: {}, multi: true},
{provide: CompilerFactory, useClass: RuntimeCompilerFactory},
{provide: PLATFORM_INITIALIZER, useValue: _initReflector, multi: true},
]);
function _firstDefined<T>(...args: T[]): T {
for (var i = 0; i < args.length; i++) {
function _mergeOptions(optionsArr: CompilerOptions[]): CompilerOptions {
return {
useDebug: _lastDefined(optionsArr.map(options => options.useDebug)),
useJit: _lastDefined(optionsArr.map(options => options.useJit)),
defaultEncapsulation: _lastDefined(optionsArr.map(options => options.defaultEncapsulation)),
providers: _mergeArrays(optionsArr.map(options => options.providers))
};
}
function _lastDefined<T>(args: T[]): T {
for (var i = args.length - 1; i >= 0; i--) {
if (args[i] !== undefined) {
return args[i];
}
@ -174,7 +223,7 @@ function _firstDefined<T>(...args: T[]): T {
return undefined;
}
function _mergeArrays(...parts: any[][]): any[] {
function _mergeArrays(parts: any[][]): any[] {
let result: any[] = [];
parts.forEach((part) => result.push(...part));
return result;

View File

@ -20,17 +20,15 @@ export class CompilerConfig {
private _logBindingUpdate: boolean;
public useJit: boolean;
/**
* @deprecated Providing platform directives via the {@link CompilerConfig} deprecated. Provide
* platform
* directives via an {@link AppModule} instead.
* @deprecated Providing platform directives via the {@link CompilerConfig} is deprecated. Provide
* platform directives via an {@link NgModule} instead.
*/
public deprecatedPlatformDirectives: any[];
public platformDirectives: any[];
/**
* @deprecated Providing platform pipes via the {@link CompilerConfig} deprecated. Provide
* platform pipes
* via an {@link AppModule} instead.
* @deprecated Providing platform pipes via the {@link CompilerConfig} is deprecated. Provide
* platform pipes via an {@link NgModule} instead.
*/
public deprecatedPlatformPipes: any[];
public platformPipes: any[];
constructor(
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
@ -49,8 +47,8 @@ export class CompilerConfig {
this._genDebugInfo = genDebugInfo;
this._logBindingUpdate = logBindingUpdate;
this.useJit = useJit;
this.deprecatedPlatformDirectives = deprecatedPlatformDirectives;
this.deprecatedPlatformPipes = deprecatedPlatformPipes;
this.platformDirectives = deprecatedPlatformDirectives;
this.platformPipes = deprecatedPlatformPipes;
}
get genDebugInfo(): boolean {

View File

@ -33,7 +33,7 @@ export class DirectiveResolver {
/**
* Return {@link DirectiveMetadata} for a given `Type`.
*/
resolve(type: Type): DirectiveMetadata {
resolve(type: Type, throwIfNotFound = true): DirectiveMetadata {
var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
if (isPresent(typeMetadata)) {
var metadata = typeMetadata.find(_isDirectiveMetadata);
@ -42,8 +42,10 @@ export class DirectiveResolver {
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
}
}
throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
if (throwIfNotFound) {
throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
}
return null;
}
private _mergeWithPropertyMetadata(

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ANALYZE_FOR_PRECOMPILE, AppModuleFactory, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {ANALYZE_FOR_PRECOMPILE, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
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_, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, 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} from '../core_private';
import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NgModuleInjector, NoOpAnimationPlayer as NoOpAnimationPlayer_, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, 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} from '../core_private';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
import {assetUrl} from './util';
@ -118,15 +118,15 @@ export class Identifiers {
runtime: ComponentFactory,
moduleUrl: assetUrl('core', 'linker/component_factory')
});
static AppModuleFactory = new CompileIdentifierMetadata({
name: 'AppModuleFactory',
runtime: AppModuleFactory,
moduleUrl: assetUrl('core', 'linker/app_module_factory')
static NgModuleFactory = new CompileIdentifierMetadata({
name: 'NgModuleFactory',
runtime: NgModuleFactory,
moduleUrl: assetUrl('core', 'linker/ng_module_factory')
});
static AppModuleInjector = new CompileIdentifierMetadata({
name: 'AppModuleInjector',
runtime: AppModuleInjector,
moduleUrl: assetUrl('core', 'linker/app_module_factory')
static NgModuleInjector = new CompileIdentifierMetadata({
name: 'NgModuleInjector',
runtime: NgModuleInjector,
moduleUrl: assetUrl('core', 'linker/ng_module_factory')
});
static ValueUnwrapper = new CompileIdentifierMetadata(
{name: 'ValueUnwrapper', moduleUrl: CD_MODULE_URL, runtime: impValueUnwrapper});

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AppModuleMetadata, AttributeMetadata, ChangeDetectionStrategy, 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, AttributeMetadata, ChangeDetectionStrategy, ComponentMetadata, HostMetadata, Inject, InjectMetadata, Injectable, NgModule, NgModuleMetadata, 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';
import {Console, LIFECYCLE_HOOKS_VALUES, ReflectorReader, createProvider, isProviderLiteral, reflector} from '../core_private';
import {MapWrapper, StringMapWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions';
import {Type, isArray, isBlank, isPresent, isString, isStringMap, stringify} from '../src/facade/lang';
@ -19,6 +19,7 @@ import {CompilerConfig} from './config';
import {hasLifecycleHook} from './directive_lifecycle_reflector';
import {DirectiveResolver} from './directive_resolver';
import {Identifiers, identifierToken} from './identifiers';
import {NgModuleResolver} from './ng_module_resolver';
import {PipeResolver} from './pipe_resolver';
import {getUrlScheme} from './url_resolver';
import {MODULE_SUFFIX, ValueTransformer, sanitizeIdentifier, visitValue} from './util';
@ -28,13 +29,15 @@ 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 _ngModuleCache = new Map<Type, cpl.CompileNgModuleMetadata>();
private _ngModuleOfTypes = new Map<Type, Type>();
private _anonymousTypes = new Map<Object, number>();
private _anonymousTypeIndex = 0;
constructor(
private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
private _viewResolver: ViewResolver, private _config: CompilerConfig,
private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
private _pipeResolver: PipeResolver, private _viewResolver: ViewResolver,
private _config: CompilerConfig, private _console: Console,
private _reflector: ReflectorReader = reflector) {}
private sanitizeTokenName(token: any): string {
@ -54,13 +57,16 @@ export class CompileMetadataResolver {
clearCacheFor(type: Type) {
this._directiveCache.delete(type);
this._pipeCache.delete(type);
this._appModuleCache.delete(type);
this._ngModuleOfTypes.delete(type);
// Clear all of the NgModuleMetadata as they contain transitive information!
this._ngModuleCache.clear();
}
clearCache() {
this._directiveCache.clear();
this._pipeCache.clear();
this._appModuleCache.clear();
this._ngModuleCache.clear();
this._ngModuleOfTypes.clear();
}
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
@ -105,11 +111,14 @@ export class CompileMetadataResolver {
return null;
}
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
getDirectiveMetadata(directiveType: Type, throwIfNotFound = true): cpl.CompileDirectiveMetadata {
directiveType = resolveForwardRef(directiveType);
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
var dirMeta = this._directiveResolver.resolve(directiveType, throwIfNotFound);
if (!dirMeta) {
return null;
}
var templateMeta: cpl.CompileTemplateMetadata = null;
var changeDetectionStrategy: ChangeDetectionStrategy = null;
var viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
@ -182,83 +191,254 @@ 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;
getNgModuleMetadata(moduleType: any, throwIfNotFound = true): cpl.CompileNgModuleMetadata {
moduleType = resolveForwardRef(moduleType);
var compileMeta = this._appModuleCache.get(moduleType);
if (isBlank(compileMeta) || !useCache) {
var compileMeta = this._ngModuleCache.get(moduleType);
if (!compileMeta) {
const meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
if (!meta) {
meta = this._reflector.annotations(moduleType)
.find((meta) => meta instanceof AppModuleMetadata);
return null;
}
if (!meta) {
throw new BaseException(
`Could not compile '${stringify(moduleType)}' because it is not an AppModule.`);
}
let modules: cpl.CompileTypeMetadata[] = [];
let providers: any[] = [];
let directives: cpl.CompileTypeMetadata[] = [];
let pipes: cpl.CompileTypeMetadata[] = [];
let precompile: 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);
const declaredDirectives: cpl.CompileDirectiveMetadata[] = [];
const exportedDirectives: cpl.CompileDirectiveMetadata[] = [];
const declaredPipes: cpl.CompilePipeMetadata[] = [];
const exportedPipes: cpl.CompilePipeMetadata[] = [];
const importedModules: cpl.CompileNgModuleMetadata[] = [];
const exportedModules: cpl.CompileNgModuleMetadata[] = [];
if (meta.imports) {
flattenArray(meta.imports).forEach((importedType) => {
if (!isValidType(importedType)) {
throw new BaseException(
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
}
let importedModuleMeta: cpl.CompileNgModuleMetadata;
if (importedModuleMeta = this.getNgModuleMetadata(importedType, false)) {
importedModules.push(importedModuleMeta);
} else {
throw new BaseException(
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
}
});
}
if (meta.exports) {
flattenArray(meta.exports).forEach((exportedType) => {
if (!isValidType(exportedType)) {
throw new BaseException(
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
}
let exportedDirMeta: cpl.CompileDirectiveMetadata;
let exportedPipeMeta: cpl.CompilePipeMetadata;
let exportedModuleMeta: cpl.CompileNgModuleMetadata;
if (exportedDirMeta = this.getDirectiveMetadata(exportedType, false)) {
exportedDirectives.push(exportedDirMeta);
} else if (exportedPipeMeta = this.getPipeMetadata(exportedType, false)) {
exportedPipes.push(exportedPipeMeta);
} else if (exportedModuleMeta = this.getNgModuleMetadata(exportedType, false)) {
exportedModules.push(exportedModuleMeta);
} else {
throw new BaseException(
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
}
});
}
// Note: This will be modified later, so we rely on
// getting a new instance every time!
const transitiveModule =
this._getTransitiveNgModuleMetadata(importedModules, exportedModules);
if (meta.declarations) {
flattenArray(meta.declarations).forEach((declaredType) => {
if (!isValidType(declaredType)) {
throw new BaseException(
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
}
let declaredDirMeta: cpl.CompileDirectiveMetadata;
let declaredPipeMeta: cpl.CompilePipeMetadata;
if (declaredDirMeta = this.getDirectiveMetadata(declaredType, false)) {
this._addDirectiveToModule(
declaredDirMeta, moduleType, transitiveModule, declaredDirectives, true);
// Collect @Component.directives/pipes/precompile into our declared directives/pipes.
this._getTransitiveViewDirectivesAndPipes(
declaredDirMeta, moduleType, transitiveModule, declaredDirectives, declaredPipes);
} else if (declaredPipeMeta = this.getPipeMetadata(declaredType, false)) {
this._addPipeToModule(
declaredPipeMeta, moduleType, transitiveModule, declaredPipes, true);
} else {
throw new BaseException(
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
}
});
}
const providers: any[] = [];
const precompile: cpl.CompileTypeMetadata[] = [];
if (meta.providers) {
providers.push(...this.getProvidersMetadata(meta.providers, precompile));
}
if (meta.directives) {
directives.push(...flattenArray(meta.directives)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
if (meta.pipes) {
pipes.push(...flattenArray(meta.pipes)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
if (meta.precompile) {
precompile.push(...flattenArray(meta.precompile)
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
}
compileMeta = new cpl.CompileAppModuleMetadata({
transitiveModule.precompile.push(...precompile);
transitiveModule.providers.push(...providers);
compileMeta = new cpl.CompileNgModuleMetadata({
type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)),
providers: providers,
directives: directives,
pipes: pipes,
precompile: precompile,
modules: modules
declaredDirectives: declaredDirectives,
exportedDirectives: exportedDirectives,
declaredPipes: declaredPipes,
exportedPipes: exportedPipes,
importedModules: importedModules,
exportedModules: exportedModules,
transitiveModule: transitiveModule
});
if (useCache) {
this._appModuleCache.set(moduleType, compileMeta);
}
transitiveModule.modules.push(compileMeta);
this._verifyModule(compileMeta);
this._ngModuleCache.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.
*/
maybeGetDirectiveMetadata(someType: Type): cpl.CompileDirectiveMetadata {
try {
return this.getDirectiveMetadata(someType);
} catch (e) {
if (e.message.indexOf('No Directive annotation') !== -1) {
return null;
addComponentToModule(moduleType: Type, compType: Type) {
const moduleMeta = this.getNgModuleMetadata(moduleType);
// Collect @Component.directives/pipes/precompile into our declared directives/pipes.
const compMeta = this.getDirectiveMetadata(compType, false);
this._addDirectiveToModule(
compMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
moduleMeta.declaredDirectives);
this._getTransitiveViewDirectivesAndPipes(
compMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
moduleMeta.declaredDirectives, moduleMeta.declaredPipes);
moduleMeta.transitiveModule.precompile.push(compMeta.type);
moduleMeta.precompile.push(compMeta.type);
this._verifyModule(moduleMeta);
}
private _verifyModule(moduleMeta: cpl.CompileNgModuleMetadata) {
moduleMeta.exportedDirectives.forEach((dirMeta) => {
if (!moduleMeta.transitiveModule.directivesSet.has(dirMeta.type.runtime)) {
throw new BaseException(
`Can't export directive ${stringify(dirMeta.type.runtime)} from ${stringify(moduleMeta.type.runtime)} as it was neither declared nor imported!`);
}
throw e;
});
moduleMeta.exportedPipes.forEach((pipeMeta) => {
if (!moduleMeta.transitiveModule.pipesSet.has(pipeMeta.type.runtime)) {
throw new BaseException(
`Can't export pipe ${stringify(pipeMeta.type.runtime)} from ${stringify(moduleMeta.type.runtime)} as it was neither declared nor imported!`);
}
});
moduleMeta.declaredDirectives.forEach((dirMeta) => {
dirMeta.precompile.forEach((precompileComp) => {
if (!moduleMeta.transitiveModule.directivesSet.has(precompileComp.runtime)) {
throw new BaseException(
`Component ${stringify(dirMeta.type.runtime)} in NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(precompileComp.runtime)} via "precompile" but it was neither declared nor imported into the module!`);
}
});
});
moduleMeta.precompile.forEach((precompileType) => {
if (!moduleMeta.transitiveModule.directivesSet.has(precompileType.runtime)) {
throw new BaseException(
`NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(precompileType.runtime)} via "precompile" but it was neither declared nor imported!`);
}
});
}
private _addTypeToModule(type: Type, moduleType: Type) {
const oldModule = this._ngModuleOfTypes.get(type);
if (oldModule && oldModule !== moduleType) {
throw new BaseException(
`Type ${stringify(type)} is part of the declarations of 2 modules: ${stringify(oldModule)} and ${stringify(moduleType)}!`);
}
this._ngModuleOfTypes.set(type, moduleType);
}
private _getTransitiveViewDirectivesAndPipes(
compMeta: cpl.CompileDirectiveMetadata, moduleType: any,
transitiveModule: cpl.TransitiveCompileNgModuleMetadata,
declaredDirectives: cpl.CompileDirectiveMetadata[],
declaredPipes: cpl.CompilePipeMetadata[]) {
if (!compMeta.isComponent) {
return;
}
const addPipe = (pipeType: Type) => {
if (!pipeType) {
throw new BaseException(
`Unexpected pipe value '${pipeType}' on the View of component '${stringify(compMeta.type.runtime)}'`);
}
const pipeMeta = this.getPipeMetadata(pipeType);
this._addPipeToModule(pipeMeta, moduleType, transitiveModule, declaredPipes);
};
const addDirective = (dirType: Type) => {
if (!dirType) {
throw new BaseException(
`Unexpected directive value '${dirType}' on the View of component '${stringify(compMeta.type.runtime)}'`);
}
const dirMeta = this.getDirectiveMetadata(dirType);
if (this._addDirectiveToModule(dirMeta, moduleType, transitiveModule, declaredDirectives)) {
this._getTransitiveViewDirectivesAndPipes(
dirMeta, moduleType, transitiveModule, declaredDirectives, declaredPipes);
}
};
const view = this._viewResolver.resolve(compMeta.type.runtime);
if (view.pipes) {
flattenArray(view.pipes).forEach(addPipe);
}
if (view.directives) {
flattenArray(view.directives).forEach(addDirective);
}
}
private _getTransitiveNgModuleMetadata(
importedModules: cpl.CompileNgModuleMetadata[],
exportedModules: cpl.CompileNgModuleMetadata[]): cpl.TransitiveCompileNgModuleMetadata {
// collect `providers` / `precompile` from all imported and all exported modules
const transitiveModules = getTransitiveModules(importedModules.concat(exportedModules), true);
const providers = flattenArray(transitiveModules.map((ngModule) => ngModule.providers));
const precompile = flattenArray(transitiveModules.map((ngModule) => ngModule.precompile));
const transitiveExportedModules = getTransitiveModules(importedModules, false);
const directives =
flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedDirectives));
const pipes = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedPipes));
return new cpl.TransitiveCompileNgModuleMetadata(
transitiveModules, providers, precompile, directives, pipes);
}
private _addDirectiveToModule(
dirMeta: cpl.CompileDirectiveMetadata, moduleType: any,
transitiveModule: cpl.TransitiveCompileNgModuleMetadata,
declaredDirectives: cpl.CompileDirectiveMetadata[], force: boolean = false): boolean {
if (force || !transitiveModule.directivesSet.has(dirMeta.type.runtime)) {
transitiveModule.directivesSet.add(dirMeta.type.runtime);
transitiveModule.directives.push(dirMeta);
declaredDirectives.push(dirMeta);
this._addTypeToModule(dirMeta.type.runtime, moduleType);
return true;
}
return false;
}
private _addPipeToModule(
pipeMeta: cpl.CompilePipeMetadata, moduleType: any,
transitiveModule: cpl.TransitiveCompileNgModuleMetadata,
declaredPipes: cpl.CompilePipeMetadata[], force: boolean = false): boolean {
if (force || !transitiveModule.pipesSet.has(pipeMeta.type.runtime)) {
transitiveModule.pipesSet.add(pipeMeta.type.runtime);
transitiveModule.pipes.push(pipeMeta);
declaredPipes.push(pipeMeta);
this._addTypeToModule(pipeMeta.type.runtime, moduleType);
return true;
}
return false;
}
getTypeMetadata(type: Type, moduleUrl: string, dependencies: any[] = null):
@ -283,11 +463,14 @@ export class CompileMetadataResolver {
});
}
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata {
getPipeMetadata(pipeType: Type, throwIfNotFound = true): cpl.CompilePipeMetadata {
pipeType = resolveForwardRef(pipeType);
var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType);
var pipeMeta = this._pipeResolver.resolve(pipeType, throwIfNotFound);
if (!pipeMeta) {
return null;
}
meta = new cpl.CompilePipeMetadata({
type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
name: pipeMeta.name,
@ -299,30 +482,6 @@ export class CompileMetadataResolver {
return meta;
}
getViewDirectivesMetadata(component: Type): cpl.CompileDirectiveMetadata[] {
var view = this._viewResolver.resolve(component);
var directives = flattenDirectives(view, this._config.deprecatedPlatformDirectives);
for (var i = 0; i < directives.length; i++) {
if (!isValidType(directives[i])) {
throw new BaseException(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
return directives.map(type => this.getDirectiveMetadata(type));
}
getViewPipesMetadata(component: Type): cpl.CompilePipeMetadata[] {
var view = this._viewResolver.resolve(component);
var pipes = flattenPipes(view, this._config.deprecatedPlatformPipes);
for (var i = 0; i < pipes.length; i++) {
if (!isValidType(pipes[i])) {
throw new BaseException(
`Unexpected piped value '${stringify(pipes[i])}' on the View of component '${stringify(component)}'`);
}
}
return pipes.map(type => this.getPipeMetadata(type));
}
getDependenciesMetadata(typeOrFunc: Type|Function, dependencies: any[]):
cpl.CompileDiDependencyMetadata[] {
let hasUnknownDeps = false;
@ -454,7 +613,7 @@ export class CompileMetadataResolver {
}
convertToCompileValue(provider.useValue, collectedIdentifiers);
collectedIdentifiers.forEach((identifier) => {
let dirMeta = this.maybeGetDirectiveMetadata(identifier.runtime);
let dirMeta = this.getDirectiveMetadata(identifier.runtime, false);
if (dirMeta) {
components.push(dirMeta.type);
}
@ -523,35 +682,35 @@ export class CompileMetadataResolver {
}
}
function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[] {
let directives: Type[] = [];
if (isPresent(platformDirectives)) {
flattenArray(platformDirectives, directives);
}
if (isPresent(view.directives)) {
flattenArray(view.directives, directives);
}
return directives;
function getTransitiveModules(
modules: cpl.CompileNgModuleMetadata[], includeImports: boolean,
targetModules: cpl.CompileNgModuleMetadata[] = [],
visitedModules = new Set<Type>()): cpl.CompileNgModuleMetadata[] {
modules.forEach((ngModule) => {
if (!visitedModules.has(ngModule.type.runtime)) {
visitedModules.add(ngModule.type.runtime);
const nestedModules = includeImports ?
ngModule.importedModules.concat(ngModule.exportedModules) :
ngModule.exportedModules;
getTransitiveModules(nestedModules, includeImports, targetModules, visitedModules);
// Add after recursing so imported/exported modules are before the module itself.
// This is important for overwriting providers of imported modules!
targetModules.push(ngModule);
}
});
return targetModules;
}
function flattenPipes(view: ViewMetadata, platformPipes: any[]): Type[] {
let pipes: Type[] = [];
if (isPresent(platformPipes)) {
flattenArray(platformPipes, pipes);
}
if (isPresent(view.pipes)) {
flattenArray(view.pipes, pipes);
}
return pipes;
}
function flattenArray(tree: any[], out: Array<Type> = []): Array<Type> {
for (var i = 0; i < tree.length; i++) {
var item = resolveForwardRef(tree[i]);
if (isArray(item)) {
flattenArray(item, out);
} else {
out.push(item);
function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
if (tree) {
for (var i = 0; i < tree.length; i++) {
var item = resolveForwardRef(tree[i]);
if (isArray(item)) {
flattenArray(item, out);
} else {
out.push(item);
}
}
}
return out;

View File

@ -8,13 +8,13 @@
import {Injectable} from '@angular/core';
import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
import {CompileDiDependencyMetadata, CompileIdentifierMap, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata} from './compile_metadata';
import {isBlank, isPresent} from './facade/lang';
import {Identifiers, identifierToken} from './identifiers';
import * as o from './output/output_ast';
import {convertValueToOutputAst} from './output/value_util';
import {ParseLocation, ParseSourceFile, ParseSourceSpan} from './parse_util';
import {AppModuleProviderParser} from './provider_parser';
import {NgModuleProviderAnalyzer} from './provider_analyzer';
import {ProviderAst, ProviderAstType} from './template_ast';
import {createDiTokenExpression} from './util';
@ -23,57 +23,58 @@ export class ComponentFactoryDependency {
public comp: CompileIdentifierMetadata, public placeholder: CompileIdentifierMetadata) {}
}
export class AppModuleCompileResult {
export class NgModuleCompileResult {
constructor(
public statements: o.Statement[], public appModuleFactoryVar: string,
public statements: o.Statement[], public ngModuleFactoryVar: 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}`;
export class NgModuleCompiler {
compile(ngModuleMeta: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[]):
NgModuleCompileResult {
var sourceFileName = isPresent(ngModuleMeta.type.moduleUrl) ?
`in NgModule ${ngModuleMeta.type.name} in ${ngModuleMeta.type.moduleUrl}` :
`in NgModule ${ngModuleMeta.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 precompileComponents = ngModuleMeta.transitiveModule.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 builder = new _InjectorBuilder(ngModuleMeta, precompileComponents, sourceSpan);
var providerParser = new AppModuleProviderParser(appModuleMeta, sourceSpan);
var providerParser = new NgModuleProviderAnalyzer(ngModuleMeta, extraProviders, 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)
var ngModuleFactoryVar = `${ngModuleMeta.type.name}NgFactory`;
var ngModuleFactoryStmt =
o.variable(ngModuleFactoryVar)
.set(o.importExpr(Identifiers.NgModuleFactory)
.instantiate(
[o.variable(injectorClass.name), o.importExpr(appModuleMeta.type)],
[o.variable(injectorClass.name), o.importExpr(ngModuleMeta.type)],
o.importType(
Identifiers.AppModuleFactory, [o.importType(appModuleMeta.type)],
Identifiers.NgModuleFactory, [o.importType(ngModuleMeta.type)],
[o.TypeModifier.Const])))
.toDeclStmt(null, [o.StmtModifier.Final]);
return new AppModuleCompileResult(
[injectorClass, appModuleFactoryStmt], appModuleFactoryVar, deps);
return new NgModuleCompileResult(
[injectorClass, ngModuleFactoryStmt], ngModuleFactoryVar, deps);
}
}
class _InjectorBuilder {
private _instances = new CompileTokenMap<o.Expression>();
private _instances = new CompileIdentifierMap<CompileTokenMetadata, o.Expression>();
private _fields: o.ClassField[] = [];
private _createStmts: o.Statement[] = [];
private _getters: o.ClassGetter[] = [];
constructor(
private _appModuleMeta: CompileAppModuleMetadata,
private _ngModuleMeta: CompileNgModuleMetadata,
private _precompileComponents: CompileIdentifierMetadata[],
private _sourceSpan: ParseSourceSpan) {}
@ -97,8 +98,8 @@ class _InjectorBuilder {
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.ReturnStatement(this._instances.get(identifierToken(this._ngModuleMeta.type)))
), o.importType(this._ngModuleMeta.type)
),
new o.ClassMethod(
'getInternal',
@ -120,10 +121,10 @@ class _InjectorBuilder {
])
.toStmt()]);
var injClassName = `${this._appModuleMeta.type.name}Injector`;
var injClassName = `${this._ngModuleMeta.type.name}Injector`;
return new o.ClassStmt(
injClassName,
o.importExpr(Identifiers.AppModuleInjector, [o.importType(this._appModuleMeta.type)]),
o.importExpr(Identifiers.NgModuleInjector, [o.importType(this._ngModuleMeta.type)]),
this._fields, this._getters, ctor, methods);
}

View File

@ -0,0 +1,39 @@
/**
* @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, NgModuleMetadata} from '@angular/core';
import {ReflectorReader, reflector} from '../core_private';
import {BaseException} from '../src/facade/exceptions';
import {Type, isBlank, isPresent, stringify} from '../src/facade/lang';
function _isNgModuleMetadata(obj: any): obj is NgModuleMetadata {
return obj instanceof NgModuleMetadata;
}
/**
* Resolves types to {@link NgModuleMetadata}.
*/
@Injectable()
export class NgModuleResolver {
constructor(private _reflector: ReflectorReader = reflector) {}
resolve(type: Type, throwIfNotFound = true): NgModuleMetadata {
const ngModuleMeta: NgModuleMetadata =
this._reflector.annotations(type).find(_isNgModuleMetadata);
if (isPresent(ngModuleMeta)) {
return ngModuleMeta;
} else {
if (throwIfNotFound) {
throw new BaseException(`No NgModule metadata found for '${stringify(type)}'.`);
}
return null;
}
}
}

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AppModuleCompiler} from './app_module_compiler';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, 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 {NgModuleCompiler} from './ng_module_compiler';
import {OutputEmitter} from './output/abstract_emitter';
import * as o from './output/output_ast';
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
@ -23,61 +23,29 @@ export class SourceModule {
constructor(public moduleUrl: string, public source: string) {}
}
export class AppModulesSummary {
private _compAppModule = new Map<string, StaticSymbol>();
private _hashKey(type: StaticSymbol) { return `${type.filePath}#${type.name}`; }
hasComponent(component: StaticSymbol): boolean {
return this._compAppModule.has(this._hashKey(component));
}
addComponent(module: StaticSymbol, component: StaticSymbol) {
this._compAppModule.set(this._hashKey(component), module);
}
getModule(comp: StaticSymbol): StaticSymbol {
return this._compAppModule.get(this._hashKey(comp));
}
export class NgModulesSummary {
constructor(public ngModuleByComponent: Map<StaticSymbol, CompileNgModuleMetadata>) {}
}
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) {}
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter) {}
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));
});
return result;
}
analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary {
const ngModuleByComponent = new Map<StaticSymbol, CompileNgModuleMetadata>();
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);
ngModules.forEach((ngModule) => {
const ngModuleMeta = this._metadataResolver.getNgModuleMetadata(<any>ngModule);
ngModuleMeta.declaredDirectives.forEach((dirMeta) => {
if (dirMeta.isComponent) {
ngModuleByComponent.set(dirMeta.type.runtime, ngModuleMeta);
}
});
});
compMeta.precompile.forEach((precompileComp) => {
this._getTransitiveComponents(appModule, <any>precompileComp.type.runtime);
});
return target;
return new NgModulesSummary(ngModuleByComponent);
}
clearCache() {
@ -86,55 +54,45 @@ export class OfflineCompiler {
}
compile(
moduleUrl: string, appModulesSummary: AppModulesSummary, components: StaticSymbol[],
appModules: StaticSymbol[]): Promise<SourceModule[]> {
moduleUrl: string, ngModulesSummary: NgModulesSummary, components: StaticSymbol[],
ngModules: StaticSymbol[]): Promise<SourceModule[]> {
let fileSuffix = _splitLastSuffix(moduleUrl)[1];
let statements: o.Statement[] = [];
let exportedVars: string[] = [];
let outputSourceModules: SourceModule[] = [];
// compile app modules
// compile all ng modules
exportedVars.push(
...appModules.map((appModule) => this._compileAppModule(appModule, statements)));
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, 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)));
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>compType);
let ngModule = ngModulesSummary.ngModuleByComponent.get(compType);
if (!ngModule) {
throw new BaseException(
`Cannot determine the module for component ${compMeta.type.name}!`);
}
return Promise
.all([
this._metadataResolver.getDirectiveMetadata(<any>compType), ...appModuleDirectives,
...this._metadataResolver.getViewDirectivesMetadata(<any>compType)
].map(dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
.all([compMeta, ...ngModule.transitiveModule.directives].map(
dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
.then((normalizedCompWithDirectives) => {
let compMeta = normalizedCompWithDirectives[0];
let dirMetas = normalizedCompWithDirectives.slice(1);
const compMeta = normalizedCompWithDirectives[0];
const dirMetas = normalizedCompWithDirectives.slice(1);
_assertComponent(compMeta);
// compile styles
let stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
const 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));
compMeta, dirMetas, ngModule.transitiveModule.pipes,
stylesCompileResults.componentStylesheet, fileSuffix, statements));
});
}))
.then(() => {
@ -146,21 +104,21 @@ export class OfflineCompiler {
});
}
private _compileAppModule(appModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModuleType);
let appCompileResult = this._appModuleCompiler.compile(appModuleMeta);
private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
const ngModule = this._metadataResolver.getNgModuleMetadata(<any>ngModuleType);
let appCompileResult = this._ngModuleCompiler.compile(ngModule, []);
appCompileResult.dependencies.forEach((dep) => {
dep.placeholder.name = _componentFactoryName(dep.comp);
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp.moduleUrl);
});
targetStatements.push(...appCompileResult.statements);
return appCompileResult.appModuleFactoryVar;
return appCompileResult.ngModuleFactoryVar;
}
private _compileComponentFactory(
compMeta: CompileDirectiveMetadata, fileSuffix: string,
targetStatements: o.Statement[]): string {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
var hostMeta = createHostComponentMeta(compMeta);
var hostViewFactoryVar =
this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, targetStatements);
var compFactoryVar = _componentFactoryName(compMeta.type);

View File

@ -30,7 +30,7 @@ export class PipeResolver {
/**
* Return {@link PipeMetadata} for a given `Type`.
*/
resolve(type: Type): PipeMetadata {
resolve(type: Type, throwIfNotFound = true): PipeMetadata {
var metas = this._reflector.annotations(resolveForwardRef(type));
if (isPresent(metas)) {
var annotation = metas.find(_isPipeMetadata);
@ -38,6 +38,9 @@ export class PipeResolver {
return annotation;
}
}
throw new BaseException(`No Pipe decorator found on ${stringify(type)}`);
if (throwIfNotFound) {
throw new BaseException(`No Pipe decorator found on ${stringify(type)}`);
}
return null;
}
}
}

View File

@ -10,7 +10,7 @@ import {ListWrapper} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions';
import {isArray, isBlank, isPresent, normalizeBlank} from '../src/facade/lang';
import {CompileAppModuleMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMap, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileIdentifierMap, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, 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';
@ -23,16 +23,16 @@ export class ProviderViewContext {
/**
* @internal
*/
viewQueries: CompileTokenMap<CompileQueryMetadata[]>;
viewQueries: CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>;
/**
* @internal
*/
viewProviders: CompileTokenMap<boolean>;
viewProviders: CompileIdentifierMap<CompileTokenMetadata, boolean>;
errors: ProviderError[] = [];
constructor(public component: CompileDirectiveMetadata, public sourceSpan: ParseSourceSpan) {
this.viewQueries = _getViewQueries(component);
this.viewProviders = new CompileTokenMap<boolean>();
this.viewProviders = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
_normalizeProviders(component.viewProviders, sourceSpan, this.errors).forEach((provider) => {
if (isBlank(this.viewProviders.get(provider.token))) {
this.viewProviders.add(provider.token, true);
@ -42,11 +42,11 @@ export class ProviderViewContext {
}
export class ProviderElementContext {
private _contentQueries: CompileTokenMap<CompileQueryMetadata[]>;
private _contentQueries: CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>;
private _transformedProviders = new CompileTokenMap<ProviderAst>();
private _seenProviders = new CompileTokenMap<boolean>();
private _allProviders: CompileTokenMap<ProviderAst>;
private _transformedProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
private _seenProviders = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
private _allProviders: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>;
private _attrs: {[key: string]: string};
private _hasViewContainer: boolean = false;
@ -60,7 +60,7 @@ export class ProviderElementContext {
this._allProviders =
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta);
var queriedTokens = new CompileTokenMap<boolean>();
var queriedTokens = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
this._allProviders.values().forEach(
(provider) => { this._addQueryReadsTo(provider.token, queriedTokens); });
refs.forEach((refAst) => {
@ -100,7 +100,9 @@ export class ProviderElementContext {
get transformedHasViewContainer(): boolean { return this._hasViewContainer; }
private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: CompileTokenMap<boolean>) {
private _addQueryReadsTo(
token: CompileTokenMetadata,
queryReadTokens: CompileIdentifierMap<CompileTokenMetadata, boolean>) {
this._getQueriesFor(token).forEach((query) => {
const queryReadToken = isPresent(query.read) ? query.read : token;
if (isBlank(queryReadTokens.get(queryReadToken))) {
@ -272,24 +274,28 @@ export class ProviderElementContext {
}
export class AppModuleProviderParser {
private _transformedProviders = new CompileTokenMap<ProviderAst>();
private _seenProviders = new CompileTokenMap<boolean>();
export class NgModuleProviderAnalyzer {
private _transformedProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
private _seenProviders = new CompileIdentifierMap<CompileTokenMetadata, boolean>();
private _unparsedProviders: any[] = [];
private _allProviders: CompileTokenMap<ProviderAst>;
private _allProviders: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>;
private _errors: ProviderError[] = [];
constructor(appModule: CompileAppModuleMetadata, sourceSpan: ParseSourceSpan) {
this._allProviders = new CompileTokenMap<ProviderAst>();
[appModule.type].concat(appModule.modules).forEach((appModuleType: CompileTypeMetadata) => {
const appModuleProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: appModuleType}), useClass: appModuleType});
constructor(
ngModule: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[],
sourceSpan: ParseSourceSpan) {
this._allProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
const ngModuleTypes = ngModule.transitiveModule.modules.map((moduleMeta) => moduleMeta.type);
ngModuleTypes.forEach((ngModuleType: CompileTypeMetadata) => {
const ngModuleProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: ngModuleType}), useClass: ngModuleType});
_resolveProviders(
[appModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors,
[ngModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors,
this._allProviders);
});
_resolveProviders(
_normalizeProviders(appModule.providers, sourceSpan, this._errors),
_normalizeProviders(
ngModule.transitiveModule.providers.concat(extraProviders), sourceSpan, this._errors),
ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders);
}
@ -436,8 +442,8 @@ function _normalizeProviders(
function _resolveProvidersFromDirectives(
directives: CompileDirectiveMetadata[], sourceSpan: ParseSourceSpan,
targetErrors: ParseError[]): CompileTokenMap<ProviderAst> {
var providersByToken = new CompileTokenMap<ProviderAst>();
targetErrors: ParseError[]): CompileIdentifierMap<CompileTokenMetadata, ProviderAst> {
var providersByToken = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
directives.forEach((directive) => {
var dirProvider = new CompileProviderMetadata(
{token: new CompileTokenMetadata({identifier: directive.type}), useClass: directive.type});
@ -464,7 +470,7 @@ function _resolveProvidersFromDirectives(
function _resolveProviders(
providers: CompileProviderMetadata[], providerType: ProviderAstType, eager: boolean,
sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
targetProvidersByToken: CompileTokenMap<ProviderAst>) {
targetProvidersByToken: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>) {
providers.forEach((provider) => {
var resolvedProvider = targetProvidersByToken.get(provider.token);
if (isPresent(resolvedProvider) && resolvedProvider.multiProvider !== provider.multi) {
@ -487,8 +493,8 @@ function _resolveProviders(
function _getViewQueries(component: CompileDirectiveMetadata):
CompileTokenMap<CompileQueryMetadata[]> {
var viewQueries = new CompileTokenMap<CompileQueryMetadata[]>();
CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]> {
var viewQueries = new CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>();
if (isPresent(component.viewQueries)) {
component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, query));
}
@ -501,8 +507,8 @@ function _getViewQueries(component: CompileDirectiveMetadata):
}
function _getContentQueries(directives: CompileDirectiveMetadata[]):
CompileTokenMap<CompileQueryMetadata[]> {
var contentQueries = new CompileTokenMap<CompileQueryMetadata[]>();
CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]> {
var contentQueries = new CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>();
directives.forEach(directive => {
if (isPresent(directive.queries)) {
directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, query));
@ -517,7 +523,8 @@ function _getContentQueries(directives: CompileDirectiveMetadata[]):
}
function _addQueryToTokenMap(
map: CompileTokenMap<CompileQueryMetadata[]>, query: CompileQueryMetadata) {
map: CompileIdentifierMap<CompileTokenMetadata, CompileQueryMetadata[]>,
query: CompileQueryMetadata) {
query.selectors.forEach((token: CompileTokenMetadata) => {
var entry = map.get(token);
if (isBlank(entry)) {

View File

@ -6,19 +6,19 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, ComponentStillLoadingError, Injectable, Injector, OptionalMetadata, Provider, SkipSelfMetadata} from '@angular/core';
import {Console} from '../core_private';
import {Compiler, ComponentFactory, ComponentResolver, ComponentStillLoadingError, Injectable, Injector, NgModule, NgModuleFactory, NgModuleMetadata, OptionalMetadata, Provider, SkipSelfMetadata} from '@angular/core';
import {Console} from '../core_private';
import {BaseException} from '../src/facade/exceptions';
import {ConcreteType, IS_DART, Type, isBlank, isString, stringify} from '../src/facade/lang';
import {ListWrapper,} from '../src/facade/collection';
import {PromiseWrapper} from '../src/facade/async';
import {createHostComponentMeta, CompileDirectiveMetadata, CompilePipeMetadata, CompileIdentifierMetadata} from './compile_metadata';
import {createHostComponentMeta, CompileDirectiveMetadata, CompilePipeMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata} from './compile_metadata';
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 {NgModuleCompiler} from './ng_module_compiler';
import {TemplateParser} from './template_parser';
import {DirectiveNormalizer} from './directive_normalizer';
import {CompileMetadataResolver} from './metadata_resolver';
@ -38,122 +38,123 @@ import {SyncAsyncResult} from './util';
* application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
*/
@Injectable()
export class RuntimeCompiler implements ComponentResolver, Compiler {
export class RuntimeCompiler implements Compiler {
private _compiledTemplateCache = new Map<Type, CompiledTemplate>();
private _compiledHostTemplateCache = new Map<Type, CompiledTemplate>();
private _compiledAppModuleCache = new Map<Type, AppModuleFactory<any>>();
private _warnOnComponentResolver = true;
private _compiledNgModuleCache = new Map<Type, NgModuleFactory<any>>();
constructor(
private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _appModuleCompiler: AppModuleCompiler, private _genConfig: CompilerConfig,
private _console: Console) {
const flatDeprecatedPlatformDirectives =
ListWrapper.flatten(_genConfig.deprecatedPlatformDirectives);
if (flatDeprecatedPlatformDirectives.length > 0) {
this._console.warn(
`Providing platform directives via the PLATFORM_DIRECTIVES provider or the "CompilerConfig" is deprecated. Provide platform directives via an @AppModule instead. Directives: ` +
flatDeprecatedPlatformDirectives.map(stringify));
}
const flatDeprecatedPlatformPipes = ListWrapper.flatten(_genConfig.deprecatedPlatformPipes);
if (flatDeprecatedPlatformPipes.length > 0) {
this._console.warn(
`Providing platform pipes via the PLATFORM_PIPES provider or the "CompilerConfig" is deprecated. Provide platform pipes via an @AppModule instead. Pipes: ` +
flatDeprecatedPlatformPipes.map(stringify));
}
}
private _ngModuleCompiler: NgModuleCompiler, private _compilerConfig: CompilerConfig,
private _console: Console) {}
get injector(): Injector { return this._injector; }
resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
if (isString(component)) {
return PromiseWrapper.reject(
new BaseException(`Cannot resolve component using '${component}'.`), null);
compileModuleSync<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
return this._compileModuleAndComponents(moduleType, true).syncResult;
}
compileModuleAsync<T>(moduleType: ConcreteType<T>): Promise<NgModuleFactory<T>> {
return this._compileModuleAndComponents(moduleType, false).asyncResult;
}
compileComponentAsync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
Promise<ComponentFactory<T>> {
if (!ngModule) {
throw new BaseException(
`Calling compileComponentAsync on the root compiler without a module is not allowed! (Compiling component ${stringify(compType)})`);
}
if (this._warnOnComponentResolver) {
this._console.warn(ComponentResolver.DynamicCompilationDeprecationMsg);
this._warnOnComponentResolver = false;
return this._compileComponentInModule(compType, false, ngModule).asyncResult;
}
compileComponentSync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
ComponentFactory<T> {
if (!ngModule) {
throw new BaseException(
`Calling compileComponentSync on the root compiler without a module is not allowed! (Compiling component ${stringify(compType)})`);
}
return this.compileComponentAsync(<ConcreteType<any>>component);
return this._compileComponentInModule(compType, true, ngModule).syncResult;
}
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
AppModuleFactory<T> {
return this._compileAppModule(moduleType, true, metadata).syncResult;
private _compileModuleAndComponents<T>(moduleType: ConcreteType<T>, isSync: boolean):
SyncAsyncResult<NgModuleFactory<T>> {
const componentPromise = this._compileComponents(moduleType, isSync);
const ngModuleFactory = this._compileModule(moduleType);
return new SyncAsyncResult(ngModuleFactory, componentPromise.then(() => ngModuleFactory));
}
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);
let boundCompilerFactory = (parentResolver: ComponentResolver) => new BoundCompiler(
this, compileModuleMeta.directives.map(dir => dir.type.runtime),
compileModuleMeta.pipes.map((pipe) => pipe.type.runtime), parentResolver);
private _compileModule<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
let ngModuleFactory = this._compiledNgModuleCache.get(moduleType);
if (!ngModuleFactory) {
const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType);
const transitiveModuleMeta = moduleMeta.transitiveModule;
let boundCompilerFactory = (parentResolver: ComponentResolver) =>
new ModuleBoundCompiler(this, moduleMeta.type.runtime, parentResolver, this._console);
// Always provide a bound Compiler and ComponentResolver
compileModuleMeta.providers.push(
this._metadataResolver.getProviderMetadata(new Provider(Compiler, {
useFactory: boundCompilerFactory,
deps: [[new OptionalMetadata(), new SkipSelfMetadata(), ComponentResolver]]
})));
compileModuleMeta.providers.push(this._metadataResolver.getProviderMetadata(
new Provider(ComponentResolver, {useExisting: Compiler})));
var compileResult = this._appModuleCompiler.compile(compileModuleMeta);
const extraProviders = [
this._metadataResolver.getProviderMetadata(new Provider(Compiler, {
useFactory: boundCompilerFactory,
deps: [[new OptionalMetadata(), new SkipSelfMetadata(), ComponentResolver]]
})),
this._metadataResolver.getProviderMetadata(
new Provider(ComponentResolver, {useExisting: Compiler}))
];
var compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders);
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.runtime =
this._assertComponentKnown(dep.comp.runtime, true).proxyComponentFactory;
dep.placeholder.name = `compFactory_${dep.comp.name}`;
});
if (IS_DART || !this._genConfig.useJit) {
appModuleFactory =
interpretStatements(compileResult.statements, compileResult.appModuleFactoryVar);
if (IS_DART || !this._compilerConfig.useJit) {
ngModuleFactory =
interpretStatements(compileResult.statements, compileResult.ngModuleFactoryVar);
} else {
appModuleFactory = jitStatements(
`${compileModuleMeta.type.name}.ngfactory.js`, compileResult.statements,
compileResult.appModuleFactoryVar);
}
if (useCache) {
this._compiledAppModuleCache.set(moduleType, appModuleFactory);
ngModuleFactory = jitStatements(
`${moduleMeta.type.name}.ngfactory.js`, compileResult.statements,
compileResult.ngModuleFactoryVar);
}
this._compiledNgModuleCache.set(moduleMeta.type.runtime, ngModuleFactory);
}
return new SyncAsyncResult(
appModuleFactory, Promise.all(componentCompilePromises).then(() => appModuleFactory));
return ngModuleFactory;
}
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> {
return this._compileComponent(compType, false, [], []).asyncResult;
}
private _compileComponentInModule<T>(
compType: ConcreteType<T>, isSync: boolean,
moduleType: ConcreteType<any>): SyncAsyncResult<ComponentFactory<T>> {
this._metadataResolver.addComponentToModule(moduleType, compType);
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> {
return this._compileComponent(compType, true, [], []).syncResult;
const componentPromise = this._compileComponents(moduleType, isSync);
const componentFactory: ComponentFactory<T> =
this._assertComponentKnown(compType, true).proxyComponentFactory;
return new SyncAsyncResult(componentFactory, componentPromise.then(() => componentFactory));
}
/**
* @internal
*/
_compileComponent<T>(
compType: ConcreteType<T>, isSync: boolean, moduleDirectives: ConcreteType<any>[],
modulePipes: ConcreteType<any>[]): SyncAsyncResult<ComponentFactory<T>> {
var templates =
this._getTransitiveCompiledTemplates(compType, true, moduleDirectives, modulePipes);
_compileComponents(mainModule: Type, isSync: boolean): Promise<any> {
const templates = new Set<CompiledTemplate>();
var loadingPromises: Promise<any>[] = [];
const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule);
ngModule.transitiveModule.modules.forEach((localModuleMeta) => {
localModuleMeta.declaredDirectives.forEach((dirMeta) => {
if (dirMeta.isComponent) {
templates.add(this._createCompiledTemplate(
dirMeta, localModuleMeta.transitiveModule.directives,
localModuleMeta.transitiveModule.pipes));
dirMeta.precompile.forEach((precompileType) => {
templates.add(this._createCompiledHostTemplate(precompileType.runtime));
});
}
});
localModuleMeta.precompile.forEach((precompileType) => {
templates.add(this._createCompiledHostTemplate(precompileType.runtime));
});
});
templates.forEach((template) => {
if (template.loading) {
if (isSync) {
@ -167,16 +168,14 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
() => { templates.forEach((template) => { this._compileTemplate(template); }); };
if (isSync) {
compile();
return Promise.resolve(null);
} else {
return Promise.all(loadingPromises).then(compile);
}
let result = this._compiledHostTemplateCache.get(compType).proxyComponentFactory;
return new SyncAsyncResult(result, Promise.all(loadingPromises).then(() => {
compile();
return result;
}));
}
clearCacheFor(type: Type) {
this._compiledAppModuleCache.delete(type);
this._compiledNgModuleCache.delete(type);
this._metadataResolver.clearCacheFor(type);
this._compiledHostTemplateCache.delete(type);
var compiledTemplate = this._compiledTemplateCache.get(type);
@ -191,71 +190,54 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
this._compiledTemplateCache.clear();
this._compiledHostTemplateCache.clear();
this._templateNormalizer.clearCache();
this._compiledAppModuleCache.clear();
this._compiledNgModuleCache.clear();
}
private _createCompiledHostTemplate(type: Type): CompiledTemplate {
var compiledTemplate = this._compiledHostTemplateCache.get(type);
private _createCompiledHostTemplate(compType: Type): CompiledTemplate {
var compiledTemplate = this._compiledHostTemplateCache.get(compType);
if (isBlank(compiledTemplate)) {
var compMeta = this._metadataResolver.getDirectiveMetadata(type);
var compMeta = this._metadataResolver.getDirectiveMetadata(compType);
assertComponent(compMeta);
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
var hostMeta = createHostComponentMeta(compMeta);
compiledTemplate = new CompiledTemplate(
true, compMeta.selector, compMeta.type, [], [type], [], [],
true, compMeta.selector, compMeta.type, [compMeta], [],
this._templateNormalizer.normalizeDirective(hostMeta));
this._compiledHostTemplateCache.set(type, compiledTemplate);
this._compiledHostTemplateCache.set(compType, compiledTemplate);
}
return compiledTemplate;
}
private _createCompiledTemplate(
type: Type, moduleDirectives: ConcreteType<any>[],
modulePipes: ConcreteType<any>[]): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(type);
compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
pipes: CompilePipeMetadata[]): CompiledTemplate {
var compiledTemplate = this._compiledTemplateCache.get(compMeta.type.runtime);
if (isBlank(compiledTemplate)) {
const compMeta = this._metadataResolver.getDirectiveMetadata(type);
assertComponent(compMeta);
const viewDirectives: CompileDirectiveMetadata[] = [];
moduleDirectives.forEach(
(type) => viewDirectives.push(this._metadataResolver.getDirectiveMetadata(type)));
const viewComponentTypes: Type[] = [];
this._metadataResolver.getViewDirectivesMetadata(type).forEach(dirOrComp => {
if (dirOrComp.isComponent) {
viewComponentTypes.push(dirOrComp.type.runtime);
} else {
viewDirectives.push(dirOrComp);
}
});
const precompileComponentTypes = compMeta.precompile.map((typeMeta) => typeMeta.runtime);
const 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));
this._compiledTemplateCache.set(type, compiledTemplate);
false, compMeta.selector, compMeta.type, directives, pipes,
this._templateNormalizer.normalizeDirective(compMeta));
this._compiledTemplateCache.set(compMeta.type.runtime, compiledTemplate);
}
return compiledTemplate;
}
private _getTransitiveCompiledTemplates(
compType: Type, isHost: boolean, moduleDirectives: ConcreteType<any>[],
modulePipes: ConcreteType<any>[],
target: Set<CompiledTemplate> = new Set<CompiledTemplate>()): Set<CompiledTemplate> {
const 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, moduleDirectives, modulePipes, target);
});
template.precompileHostComponentTypes.forEach((compType) => {
this._getTransitiveCompiledTemplates(compType, true, moduleDirectives, modulePipes, target);
});
private _assertComponentKnown(compType: any, isHost: boolean): CompiledTemplate {
const compiledTemplate = isHost ? this._compiledHostTemplateCache.get(compType) :
this._compiledTemplateCache.get(compType);
if (!compiledTemplate) {
throw new BaseException(
`Illegal state: CompiledTemplate for ${stringify(compType)} (isHost: ${isHost}) does not exist!`);
}
return target;
return compiledTemplate;
}
private _assertComponentLoaded(compType: any, isHost: boolean): CompiledTemplate {
const compiledTemplate = this._assertComponentKnown(compType, isHost);
if (compiledTemplate.loading) {
throw new BaseException(
`Illegal state: CompiledTemplate for ${stringify(compType)} (isHost: ${isHost}) is still loading!`);
}
return compiledTemplate;
}
private _compileTemplate(template: CompiledTemplate) {
@ -270,7 +252,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
this._resolveStylesCompileResult(
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
const viewCompMetas = template.viewComponentTypes.map(
(compType) => this._compiledTemplateCache.get(compType).normalizedCompMeta);
(compType) => this._assertComponentLoaded(compType, false).normalizedCompMeta);
const parsedTemplate = this._templateParser.parse(
compMeta, compMeta.template.template, template.viewDirectives.concat(viewCompMetas),
template.viewPipes, compMeta.type.name);
@ -281,12 +263,12 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
let depTemplate: CompiledTemplate;
if (dep instanceof ViewFactoryDependency) {
let vfd = <ViewFactoryDependency>dep;
depTemplate = this._compiledTemplateCache.get(vfd.comp.runtime);
depTemplate = this._assertComponentLoaded(vfd.comp.runtime, false);
vfd.placeholder.runtime = depTemplate.proxyViewFactory;
vfd.placeholder.name = `viewFactory_${vfd.comp.name}`;
} else if (dep instanceof ComponentFactoryDependency) {
let cfd = <ComponentFactoryDependency>dep;
depTemplate = this._compiledHostTemplateCache.get(cfd.comp.runtime);
depTemplate = this._assertComponentLoaded(cfd.comp.runtime, true);
cfd.placeholder.runtime = depTemplate.proxyComponentFactory;
cfd.placeholder.name = `compFactory_${cfd.comp.name}`;
}
@ -294,7 +276,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
const statements =
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
let factory: any;
if (IS_DART || !this._genConfig.useJit) {
if (IS_DART || !this._compilerConfig.useJit) {
factory = interpretStatements(statements, compileResult.viewFactoryVar);
} else {
factory = jitStatements(
@ -318,7 +300,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
result: CompiledStylesheet,
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
if (IS_DART || !this._genConfig.useJit) {
if (IS_DART || !this._compilerConfig.useJit) {
return interpretStatements(result.statements, result.stylesVar);
} else {
return jitStatements(`${result.meta.moduleUrl}.css.js`, result.statements, result.stylesVar);
@ -334,13 +316,28 @@ class CompiledTemplate {
private _normalizedCompMeta: CompileDirectiveMetadata = null;
isCompiled = false;
isCompiledWithDeps = false;
viewComponentTypes: Type[] = [];
viewDirectives: CompileDirectiveMetadata[] = [];
constructor(
public isHost: boolean, selector: string, public compType: CompileIdentifierMetadata,
public viewDirectives: CompileDirectiveMetadata[], public viewComponentTypes: Type[],
public precompileHostComponentTypes: Type[], public viewPipes: CompilePipeMetadata[],
viewDirectivesAndComponents: CompileDirectiveMetadata[],
public viewPipes: CompilePipeMetadata[],
_normalizeResult: SyncAsyncResult<CompileDirectiveMetadata>) {
this.proxyViewFactory = (...args: any[]) => this._viewFactory.apply(null, args);
viewDirectivesAndComponents.forEach((dirMeta) => {
if (dirMeta.isComponent) {
this.viewComponentTypes.push(dirMeta.type.runtime);
} else {
this.viewDirectives.push(dirMeta);
}
});
this.proxyViewFactory = (...args: any[]) => {
if (!this._viewFactory) {
throw new BaseException(
`Illegal state: CompiledTemplate for ${stringify(this.compType)} is not compiled yet!`);
}
return this._viewFactory.apply(null, args);
};
this.proxyComponentFactory = isHost ?
new ComponentFactory<any>(selector, this.proxyViewFactory, compType.runtime) :
null;
@ -376,13 +373,15 @@ function assertComponent(meta: CompileDirectiveMetadata) {
}
/**
* A wrapper around `Compiler` and `ComponentResolver` that
* provides default patform directives / pipes.
* Implements `Compiler` and `ComponentResolver` by delegating
* to the RuntimeCompiler using a known module.
*/
class BoundCompiler implements Compiler, ComponentResolver {
class ModuleBoundCompiler implements Compiler, ComponentResolver {
private _warnOnComponentResolver = true;
constructor(
private _delegate: RuntimeCompiler, private _directives: any[], private _pipes: any[],
private _parentComponentResolver: ComponentResolver) {}
private _delegate: RuntimeCompiler, private _ngModule: ConcreteType<any>,
private _parentComponentResolver: ComponentResolver, private _console: Console) {}
get injector(): Injector { return this._delegate.injector; }
@ -395,27 +394,29 @@ class BoundCompiler implements Compiler, ComponentResolver {
new BaseException(`Cannot resolve component using '${component}'.`), null);
}
}
if (this._warnOnComponentResolver) {
this._console.warn(ComponentResolver.DynamicCompilationDeprecationMsg);
this._warnOnComponentResolver = false;
}
return this.compileComponentAsync(<ConcreteType<any>>component);
}
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> {
return this._delegate._compileComponent(compType, false, this._directives, this._pipes)
.asyncResult;
compileComponentAsync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
Promise<ComponentFactory<T>> {
return this._delegate.compileComponentAsync(compType, ngModule ? ngModule : this._ngModule);
}
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> {
return this._delegate._compileComponent(compType, true, this._directives, this._pipes)
.syncResult;
compileComponentSync<T>(compType: ConcreteType<T>, ngModule: ConcreteType<any> = null):
ComponentFactory<T> {
return this._delegate.compileComponentSync(compType, ngModule ? ngModule : this._ngModule);
}
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
AppModuleFactory<T> {
return this._delegate.compileAppModuleSync(moduleType, metadata);
compileModuleSync<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
return this._delegate.compileModuleSync(moduleType);
}
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
Promise<AppModuleFactory<T>> {
return this._delegate.compileAppModuleAsync(moduleType, metadata);
compileModuleAsync<T>(moduleType: ConcreteType<T>): Promise<NgModuleFactory<T>> {
return this._delegate.compileModuleAsync(moduleType);
}
/**
@ -429,7 +430,7 @@ class BoundCompiler implements Compiler, ComponentResolver {
}
/**
* Clears the cache for the given component/appModule.
* Clears the cache for the given component/ngModule.
*/
clearCacheFor(type: Type) { this._delegate.clearCacheFor(type); }
}
}

View File

@ -13,7 +13,7 @@ import {RegExpWrapper, isPresent, StringWrapper, isBlank} from '../src/facade/la
import {BaseException} from '../src/facade/exceptions';
import {AST, Interpolation, ASTWithSource, TemplateBinding, RecursiveAstVisitor, BindingPipe, ParserError} from './expression_parser/ast';
import {Parser} from './expression_parser/parser';
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileMetadataWithType, CompileTokenMetadata,} from './compile_metadata';
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileMetadataWithIdentifier, CompileTokenMetadata, CompileIdentifierMap, removeIdentifierDuplicates} from './compile_metadata';
import {HtmlParser, HtmlParseTreeResult} from './html_parser';
import {splitNsName, mergeNsAndName} from './html_tags';
import {ParseSourceSpan, ParseError, ParseErrorLevel} from './parse_util';
@ -27,7 +27,7 @@ import {HtmlAstVisitor, HtmlElementAst, HtmlAttrAst, HtmlTextAst, HtmlCommentAst
import {splitAtColon} from './util';
import {identifierToken, Identifiers} from './identifiers';
import {expandNodes} from './expander';
import {ProviderElementContext, ProviderViewContext} from './provider_parser';
import {ProviderElementContext, ProviderViewContext} from './provider_analyzer';
// Group 1 = "bind-"
// Group 2 = "var-"
@ -118,8 +118,8 @@ export class TemplateParser {
}
if (htmlAstWithErrors.rootNodes.length > 0) {
const uniqDirectives = <CompileDirectiveMetadata[]>removeDuplicates(directives);
const uniqPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
const uniqDirectives = removeIdentifierDuplicates(directives);
const uniqPipes = removeIdentifierDuplicates(pipes);
const providerViewContext =
new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan);
const parseVisitor = new TemplateParseVisitor(
@ -181,7 +181,6 @@ class TemplateParseVisitor implements HtmlAstVisitor {
const tempMeta = providerViewContext.component.template;
// TODO
if (isPresent(tempMeta) && isPresent(tempMeta.interpolation)) {
this._interpolationConfig = {
start: tempMeta.interpolation[0],
@ -1015,18 +1014,3 @@ export class PipeCollector extends RecursiveAstVisitor {
return null;
}
}
function removeDuplicates(items: CompileMetadataWithType[]): CompileMetadataWithType[] {
let res: CompileMetadataWithType[] = [];
items.forEach(item => {
let hasMatch =
res.filter(
r => r.type.name == item.type.name && r.type.moduleUrl == item.type.moduleUrl &&
r.type.runtime == item.type.runtime)
.length > 0;
if (!hasMatch) {
res.push(item);
}
});
return res;
}

View File

@ -18,7 +18,7 @@ import {ProviderAst, ProviderAstType, ReferenceAst, TemplateAst} from '../templa
import {CompileView} from './compile_view';
import {InjectMethodVars} from './constants';
import {CompileTokenMap, CompileDirectiveMetadata, CompileTokenMetadata, CompileQueryMetadata, CompileProviderMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata,} from '../compile_metadata';
import {CompileIdentifierMap, CompileDirectiveMetadata, CompileTokenMetadata, CompileQueryMetadata, CompileProviderMetadata, CompileDiDependencyMetadata, CompileIdentifierMetadata,} from '../compile_metadata';
import {getPropertyInView, injectFromViewParentInjector} from './util';
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
import {CompileMethod} from './compile_method';
@ -43,11 +43,11 @@ export class CompileElement extends CompileNode {
public appElement: o.ReadPropExpr;
public elementRef: o.Expression;
public injector: o.Expression;
private _instances = new CompileTokenMap<o.Expression>();
private _resolvedProviders: CompileTokenMap<ProviderAst>;
private _instances = new CompileIdentifierMap<CompileTokenMetadata, o.Expression>();
private _resolvedProviders: CompileIdentifierMap<CompileTokenMetadata, ProviderAst>;
private _queryCount = 0;
private _queries = new CompileTokenMap<CompileQuery[]>();
private _queries = new CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>();
private _componentConstructorViewQueryLists: o.Expression[] = [];
public contentNodesByNgContentIndex: Array<o.Expression>[] = null;
@ -144,7 +144,7 @@ export class CompileElement extends CompileNode {
identifierToken(Identifiers.ViewContainerRef), this.appElement.prop('vcRef'));
}
this._resolvedProviders = new CompileTokenMap<ProviderAst>();
this._resolvedProviders = new CompileIdentifierMap<CompileTokenMetadata, ProviderAst>();
this._resolvedProvidersArray.forEach(
provider => this._resolvedProviders.add(provider.token, provider));

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CompileQueryMetadata, CompileTokenMap} from '../compile_metadata';
import {CompileIdentifierMap, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent} from '../facade/lang';
import {Identifiers} from '../identifiers';
@ -125,7 +125,8 @@ export function createQueryList(
return expr;
}
export function addQueryToTokenMap(map: CompileTokenMap<CompileQuery[]>, query: CompileQuery) {
export function addQueryToTokenMap(
map: CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>, query: CompileQuery) {
query.meta.selectors.forEach((selector) => {
var entry = map.get(selector);
if (isBlank(entry)) {

View File

@ -8,7 +8,7 @@
import {ViewType} from '../../core_private';
import {CompiledAnimation} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMap} from '../compile_metadata';
import {CompileDirectiveMetadata, CompileIdentifierMap, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMetadata} from '../compile_metadata';
import {CompilerConfig} from '../config';
import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent} from '../facade/lang';
@ -27,7 +27,7 @@ import {createPureProxy, getPropertyInView, getViewFactoryName, injectFromViewPa
export class CompileView implements NameResolver {
public viewType: ViewType;
public viewQueries: CompileTokenMap<CompileQuery[]>;
public viewQueries: CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>;
public nodes: CompileNode[] = [];
// root nodes or AppElements for ViewContainers
@ -98,7 +98,7 @@ export class CompileView implements NameResolver {
this.componentContext =
getPropertyInView(o.THIS_EXPR.prop('context'), this, this.componentView);
var viewQueries = new CompileTokenMap<CompileQuery[]>();
var viewQueries = new CompileIdentifierMap<CompileTokenMetadata, CompileQuery[]>();
if (this.viewType === ViewType.COMPONENT) {
var directiveInstance = o.THIS_EXPR.prop('context');
ListWrapper.forEachWithIndex(this.component.viewQueries, (queryMeta, queryIndex) => {

View File

@ -22,7 +22,7 @@ function _isComponentMetadata(obj: any): obj is ComponentMetadata {
export class ViewResolver {
constructor(private _reflector: ReflectorReader = reflector) {}
resolve(component: Type): ViewMetadata {
resolve(component: Type, throwIfNotFound = true): ViewMetadata {
const compMeta: ComponentMetadata =
this._reflector.annotations(component).find(_isComponentMetadata);
@ -45,8 +45,11 @@ export class ViewResolver {
});
}
} else {
throw new BaseException(
`Could not compile '${stringify(component)}' because it is not a component.`);
if (throwIfNotFound) {
throw new BaseException(
`Could not compile '${stringify(component)}' because it is not a component.`);
}
return null;
}
}
}