2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AttributeMetadata, ChangeDetectionStrategy, ComponentMetadata, HostMetadata, InjectMetadata, Injectable, ModuleWithProviders, OptionalMetadata, Provider, QueryMetadata, SchemaMetadata, SelfMetadata, SkipSelfMetadata, Type, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
|
2016-06-08 19:38:52 -04:00
|
|
|
|
2016-08-19 16:51:45 -04:00
|
|
|
import {LIFECYCLE_HOOKS_VALUES, ReflectorReader, reflector} from '../core_private';
|
2016-07-21 16:56:58 -04:00
|
|
|
import {StringMapWrapper} from '../src/facade/collection';
|
2016-06-08 19:38:52 -04:00
|
|
|
|
2016-06-20 12:52:41 -04:00
|
|
|
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
2016-01-06 17:13:44 -05:00
|
|
|
import * as cpl from './compile_metadata';
|
|
|
|
import {DirectiveResolver} from './directive_resolver';
|
2016-08-10 21:21:28 -04:00
|
|
|
import {BaseException} from './facade/exceptions';
|
|
|
|
import {isArray, isBlank, isPresent, isString, stringify} from './facade/lang';
|
2016-07-07 13:05:55 -04:00
|
|
|
import {Identifiers, identifierToken} from './identifiers';
|
2016-08-02 04:37:42 -04:00
|
|
|
import {hasLifecycleHook} from './lifecycle_reflector';
|
2016-07-18 06:50:31 -04:00
|
|
|
import {NgModuleResolver} from './ng_module_resolver';
|
2016-01-06 17:13:44 -05:00
|
|
|
import {PipeResolver} from './pipe_resolver';
|
2016-07-28 13:39:10 -04:00
|
|
|
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
2016-04-28 20:50:03 -04:00
|
|
|
import {getUrlScheme} from './url_resolver';
|
2016-06-08 19:38:52 -04:00
|
|
|
import {MODULE_SUFFIX, ValueTransformer, sanitizeIdentifier, visitValue} from './util';
|
2016-04-28 20:50:03 -04:00
|
|
|
|
2015-09-14 18:59:09 -04:00
|
|
|
@Injectable()
|
2016-02-18 13:53:21 -05:00
|
|
|
export class CompileMetadataResolver {
|
2016-08-10 21:21:28 -04:00
|
|
|
private _directiveCache = new Map<Type<any>, cpl.CompileDirectiveMetadata>();
|
|
|
|
private _pipeCache = new Map<Type<any>, cpl.CompilePipeMetadata>();
|
|
|
|
private _ngModuleCache = new Map<Type<any>, cpl.CompileNgModuleMetadata>();
|
|
|
|
private _ngModuleOfTypes = new Map<Type<any>, Type<any>>();
|
2016-03-29 20:15:07 -04:00
|
|
|
private _anonymousTypes = new Map<Object, number>();
|
|
|
|
private _anonymousTypeIndex = 0;
|
2015-09-14 18:59:09 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
constructor(
|
2016-07-18 06:50:31 -04:00
|
|
|
private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
|
2016-08-19 16:51:45 -04:00
|
|
|
private _pipeResolver: PipeResolver, private _schemaRegistry: ElementSchemaRegistry,
|
2016-07-29 05:10:30 -04:00
|
|
|
private _reflector: ReflectorReader = reflector) {}
|
2015-09-14 18:59:09 -04:00
|
|
|
|
2016-04-20 21:10:19 -04:00
|
|
|
private sanitizeTokenName(token: any): string {
|
|
|
|
let identifier = stringify(token);
|
|
|
|
if (identifier.indexOf('(') >= 0) {
|
|
|
|
// case: anonymous functions!
|
|
|
|
let found = this._anonymousTypes.get(token);
|
|
|
|
if (isBlank(found)) {
|
|
|
|
this._anonymousTypes.set(token, this._anonymousTypeIndex++);
|
|
|
|
found = this._anonymousTypes.get(token);
|
|
|
|
}
|
|
|
|
identifier = `anonymous_token_${found}_`;
|
2016-03-29 20:15:07 -04:00
|
|
|
}
|
2016-04-20 21:10:19 -04:00
|
|
|
return sanitizeIdentifier(identifier);
|
2016-03-29 20:15:07 -04:00
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
clearCacheFor(type: Type<any>) {
|
2016-06-28 12:54:42 -04:00
|
|
|
this._directiveCache.delete(type);
|
|
|
|
this._pipeCache.delete(type);
|
2016-07-18 06:50:31 -04:00
|
|
|
this._ngModuleOfTypes.delete(type);
|
|
|
|
// Clear all of the NgModuleMetadata as they contain transitive information!
|
|
|
|
this._ngModuleCache.clear();
|
2016-06-24 11:46:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
clearCache() {
|
|
|
|
this._directiveCache.clear();
|
|
|
|
this._pipeCache.clear();
|
2016-07-18 06:50:31 -04:00
|
|
|
this._ngModuleCache.clear();
|
|
|
|
this._ngModuleOfTypes.clear();
|
2016-06-24 11:46:43 -04:00
|
|
|
}
|
|
|
|
|
2016-05-26 18:07:51 -04:00
|
|
|
getAnimationEntryMetadata(entry: AnimationEntryMetadata): cpl.CompileAnimationEntryMetadata {
|
2016-05-25 15:46:22 -04:00
|
|
|
var defs = entry.definitions.map(def => this.getAnimationStateMetadata(def));
|
|
|
|
return new cpl.CompileAnimationEntryMetadata(entry.name, defs);
|
|
|
|
}
|
|
|
|
|
2016-05-26 18:07:51 -04:00
|
|
|
getAnimationStateMetadata(value: AnimationStateMetadata): cpl.CompileAnimationStateMetadata {
|
|
|
|
if (value instanceof AnimationStateDeclarationMetadata) {
|
2016-05-25 15:46:22 -04:00
|
|
|
var styles = this.getAnimationStyleMetadata(value.styles);
|
|
|
|
return new cpl.CompileAnimationStateDeclarationMetadata(value.stateNameExpr, styles);
|
2016-05-26 18:07:51 -04:00
|
|
|
} else if (value instanceof AnimationStateTransitionMetadata) {
|
2016-06-08 19:38:52 -04:00
|
|
|
return new cpl.CompileAnimationStateTransitionMetadata(
|
|
|
|
value.stateChangeExpr, this.getAnimationMetadata(value.steps));
|
2016-05-25 15:46:22 -04:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-05-26 18:07:51 -04:00
|
|
|
getAnimationStyleMetadata(value: AnimationStyleMetadata): cpl.CompileAnimationStyleMetadata {
|
2016-05-25 15:46:22 -04:00
|
|
|
return new cpl.CompileAnimationStyleMetadata(value.offset, value.styles);
|
|
|
|
}
|
|
|
|
|
2016-05-26 18:07:51 -04:00
|
|
|
getAnimationMetadata(value: AnimationMetadata): cpl.CompileAnimationMetadata {
|
|
|
|
if (value instanceof AnimationStyleMetadata) {
|
2016-05-25 15:46:22 -04:00
|
|
|
return this.getAnimationStyleMetadata(value);
|
2016-05-26 18:07:51 -04:00
|
|
|
} else if (value instanceof AnimationKeyframesSequenceMetadata) {
|
2016-06-08 19:38:52 -04:00
|
|
|
return new cpl.CompileAnimationKeyframesSequenceMetadata(
|
|
|
|
value.steps.map(entry => this.getAnimationStyleMetadata(entry)));
|
2016-05-26 18:07:51 -04:00
|
|
|
} else if (value instanceof AnimationAnimateMetadata) {
|
2016-06-08 19:38:52 -04:00
|
|
|
let animateData =
|
|
|
|
<cpl.CompileAnimationStyleMetadata|cpl.CompileAnimationKeyframesSequenceMetadata>this
|
|
|
|
.getAnimationMetadata(value.styles);
|
2016-05-25 15:46:22 -04:00
|
|
|
return new cpl.CompileAnimationAnimateMetadata(value.timings, animateData);
|
2016-05-26 18:07:51 -04:00
|
|
|
} else if (value instanceof AnimationWithStepsMetadata) {
|
2016-05-25 15:46:22 -04:00
|
|
|
var steps = value.steps.map(step => this.getAnimationMetadata(step));
|
2016-05-26 18:07:51 -04:00
|
|
|
if (value instanceof AnimationGroupMetadata) {
|
2016-05-25 15:46:22 -04:00
|
|
|
return new cpl.CompileAnimationGroupMetadata(steps);
|
|
|
|
} else {
|
|
|
|
return new cpl.CompileAnimationSequenceMetadata(steps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
getDirectiveMetadata(directiveType: Type<any>, throwIfNotFound = true):
|
|
|
|
cpl.CompileDirectiveMetadata {
|
2016-06-28 12:54:42 -04:00
|
|
|
directiveType = resolveForwardRef(directiveType);
|
2015-12-02 13:35:51 -05:00
|
|
|
var meta = this._directiveCache.get(directiveType);
|
2015-09-14 18:59:09 -04:00
|
|
|
if (isBlank(meta)) {
|
2016-07-18 06:50:31 -04:00
|
|
|
var dirMeta = this._directiveResolver.resolve(directiveType, throwIfNotFound);
|
|
|
|
if (!dirMeta) {
|
|
|
|
return null;
|
|
|
|
}
|
2016-06-12 00:23:37 -04:00
|
|
|
var templateMeta: cpl.CompileTemplateMetadata = null;
|
2016-06-22 20:25:42 -04:00
|
|
|
var changeDetectionStrategy: ChangeDetectionStrategy = null;
|
|
|
|
var viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
2016-05-02 19:45:43 -04:00
|
|
|
var moduleUrl = staticTypeModuleUrl(directiveType);
|
2016-08-19 16:51:45 -04:00
|
|
|
var entryComponentMetadata: cpl.CompileTypeMetadata[] = [];
|
2016-07-28 13:39:10 -04:00
|
|
|
let selector = dirMeta.selector;
|
2016-04-28 20:50:03 -04:00
|
|
|
if (dirMeta instanceof ComponentMetadata) {
|
|
|
|
var cmpMeta = <ComponentMetadata>dirMeta;
|
2016-07-28 09:31:26 -04:00
|
|
|
assertArrayOfStrings('styles', cmpMeta.styles);
|
|
|
|
assertInterpolationSymbols('interpolation', cmpMeta.interpolation);
|
|
|
|
var animations = isPresent(cmpMeta.animations) ?
|
|
|
|
cmpMeta.animations.map(e => this.getAnimationEntryMetadata(e)) :
|
2016-06-08 19:38:52 -04:00
|
|
|
null;
|
2016-07-28 09:31:26 -04:00
|
|
|
assertArrayOfStrings('styles', cmpMeta.styles);
|
|
|
|
assertArrayOfStrings('styleUrls', cmpMeta.styleUrls);
|
2016-05-25 15:46:22 -04:00
|
|
|
|
2015-09-18 13:33:23 -04:00
|
|
|
templateMeta = new cpl.CompileTemplateMetadata({
|
2016-07-28 09:31:26 -04:00
|
|
|
encapsulation: cmpMeta.encapsulation,
|
|
|
|
template: cmpMeta.template,
|
|
|
|
templateUrl: cmpMeta.templateUrl,
|
|
|
|
styles: cmpMeta.styles,
|
|
|
|
styleUrls: cmpMeta.styleUrls,
|
2016-06-20 12:52:41 -04:00
|
|
|
animations: animations,
|
2016-07-28 09:31:26 -04:00
|
|
|
interpolation: cmpMeta.interpolation
|
2015-09-14 18:59:09 -04:00
|
|
|
});
|
2015-10-23 18:55:48 -04:00
|
|
|
changeDetectionStrategy = cmpMeta.changeDetection;
|
2016-01-06 17:13:44 -05:00
|
|
|
if (isPresent(dirMeta.viewProviders)) {
|
2016-06-21 20:27:27 -04:00
|
|
|
viewProviders = this.getProvidersMetadata(
|
2016-08-23 19:18:41 -04:00
|
|
|
dirMeta.viewProviders, entryComponentMetadata,
|
|
|
|
`viewProviders for "${stringify(directiveType)}"`);
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
2016-05-02 19:45:43 -04:00
|
|
|
moduleUrl = componentModuleUrl(this._reflector, directiveType, cmpMeta);
|
2016-07-25 03:36:30 -04:00
|
|
|
if (cmpMeta.entryComponents) {
|
2016-08-19 16:51:45 -04:00
|
|
|
entryComponentMetadata =
|
2016-07-25 03:36:30 -04:00
|
|
|
flattenArray(cmpMeta.entryComponents)
|
2016-08-19 16:51:45 -04:00
|
|
|
.map((type) => this.getTypeMetadata(type, staticTypeModuleUrl(type)))
|
|
|
|
.concat(entryComponentMetadata);
|
2016-06-22 17:06:23 -04:00
|
|
|
}
|
2016-07-28 13:39:10 -04:00
|
|
|
if (!selector) {
|
|
|
|
selector = this._schemaRegistry.getDefaultComponentElementName();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!selector) {
|
|
|
|
throw new BaseException(
|
|
|
|
`Directive ${stringify(directiveType)} has no selector, please add it!`);
|
|
|
|
}
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
|
|
|
|
2016-06-22 20:25:42 -04:00
|
|
|
var providers: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
2016-01-06 17:13:44 -05:00
|
|
|
if (isPresent(dirMeta.providers)) {
|
2016-06-21 20:27:27 -04:00
|
|
|
providers = this.getProvidersMetadata(
|
2016-08-23 19:18:41 -04:00
|
|
|
dirMeta.providers, entryComponentMetadata,
|
|
|
|
`providers for "${stringify(directiveType)}"`);
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
2016-07-07 13:05:55 -04:00
|
|
|
var queries: cpl.CompileQueryMetadata[] = [];
|
|
|
|
var viewQueries: cpl.CompileQueryMetadata[] = [];
|
2016-01-06 17:13:44 -05:00
|
|
|
if (isPresent(dirMeta.queries)) {
|
2016-06-04 22:46:03 -04:00
|
|
|
queries = this.getQueriesMetadata(dirMeta.queries, false, directiveType);
|
|
|
|
viewQueries = this.getQueriesMetadata(dirMeta.queries, true, directiveType);
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
2015-09-18 13:33:23 -04:00
|
|
|
meta = cpl.CompileDirectiveMetadata.create({
|
2016-07-28 13:39:10 -04:00
|
|
|
selector: selector,
|
2015-10-23 18:55:48 -04:00
|
|
|
exportAs: dirMeta.exportAs,
|
2015-09-14 18:59:09 -04:00
|
|
|
isComponent: isPresent(templateMeta),
|
2016-05-02 19:45:43 -04:00
|
|
|
type: this.getTypeMetadata(directiveType, moduleUrl),
|
2015-09-14 18:59:09 -04:00
|
|
|
template: templateMeta,
|
2015-09-18 13:33:23 -04:00
|
|
|
changeDetection: changeDetectionStrategy,
|
2015-10-23 18:55:48 -04:00
|
|
|
inputs: dirMeta.inputs,
|
|
|
|
outputs: dirMeta.outputs,
|
|
|
|
host: dirMeta.host,
|
2016-01-06 17:13:44 -05:00
|
|
|
providers: providers,
|
|
|
|
viewProviders: viewProviders,
|
|
|
|
queries: queries,
|
2016-06-22 17:06:23 -04:00
|
|
|
viewQueries: viewQueries,
|
2016-08-19 16:51:45 -04:00
|
|
|
entryComponents: entryComponentMetadata
|
2015-09-14 18:59:09 -04:00
|
|
|
});
|
2015-12-02 13:35:51 -05:00
|
|
|
this._directiveCache.set(directiveType, meta);
|
|
|
|
}
|
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
|
2016-07-18 06:50:31 -04:00
|
|
|
getNgModuleMetadata(moduleType: any, throwIfNotFound = true): cpl.CompileNgModuleMetadata {
|
2016-06-28 12:54:42 -04:00
|
|
|
moduleType = resolveForwardRef(moduleType);
|
2016-07-18 06:50:31 -04:00
|
|
|
var compileMeta = this._ngModuleCache.get(moduleType);
|
|
|
|
if (!compileMeta) {
|
|
|
|
const meta = this._ngModuleResolver.resolve(moduleType, throwIfNotFound);
|
2016-06-28 12:54:42 -04:00
|
|
|
if (!meta) {
|
2016-07-18 06:50:31 -04:00
|
|
|
return null;
|
2016-06-28 12:54:42 -04:00
|
|
|
}
|
2016-07-18 06:50:31 -04:00
|
|
|
const declaredDirectives: cpl.CompileDirectiveMetadata[] = [];
|
|
|
|
const exportedDirectives: cpl.CompileDirectiveMetadata[] = [];
|
|
|
|
const declaredPipes: cpl.CompilePipeMetadata[] = [];
|
|
|
|
const exportedPipes: cpl.CompilePipeMetadata[] = [];
|
|
|
|
const importedModules: cpl.CompileNgModuleMetadata[] = [];
|
|
|
|
const exportedModules: cpl.CompileNgModuleMetadata[] = [];
|
2016-07-25 04:39:50 -04:00
|
|
|
const providers: any[] = [];
|
|
|
|
const entryComponents: cpl.CompileTypeMetadata[] = [];
|
2016-08-02 09:54:08 -04:00
|
|
|
const bootstrapComponents: cpl.CompileTypeMetadata[] = [];
|
2016-07-25 06:02:57 -04:00
|
|
|
const schemas: SchemaMetadata[] = [];
|
|
|
|
|
2016-07-18 06:50:31 -04:00
|
|
|
if (meta.imports) {
|
|
|
|
flattenArray(meta.imports).forEach((importedType) => {
|
2016-08-10 21:21:28 -04:00
|
|
|
let importedModuleType: Type<any>;
|
2016-07-25 04:39:50 -04:00
|
|
|
if (isValidType(importedType)) {
|
|
|
|
importedModuleType = importedType;
|
|
|
|
} else if (importedType && importedType.ngModule) {
|
|
|
|
const moduleWithProviders: ModuleWithProviders = importedType;
|
|
|
|
importedModuleType = moduleWithProviders.ngModule;
|
|
|
|
if (moduleWithProviders.providers) {
|
2016-08-23 19:18:41 -04:00
|
|
|
providers.push(...this.getProvidersMetadata(
|
|
|
|
moduleWithProviders.providers, entryComponents,
|
|
|
|
`provider for the NgModule '${stringify(importedModuleType)}'`));
|
2016-07-25 04:39:50 -04:00
|
|
|
}
|
2016-07-18 06:50:31 -04:00
|
|
|
}
|
2016-07-25 04:39:50 -04:00
|
|
|
if (importedModuleType) {
|
2016-08-17 18:57:02 -04:00
|
|
|
let importedMeta = this.getNgModuleMetadata(importedModuleType, false);
|
|
|
|
if (importedMeta === null) {
|
|
|
|
throw new BaseException(
|
|
|
|
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
|
|
|
|
}
|
|
|
|
importedModules.push(importedMeta);
|
2016-07-18 06:50:31 -04:00
|
|
|
} 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(
|
2016-08-17 18:57:02 -04:00
|
|
|
`Unexpected ${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
|
2016-07-18 06:50:31 -04:00
|
|
|
}
|
|
|
|
});
|
2016-06-28 12:54:42 -04:00
|
|
|
}
|
2016-07-18 06:50:31 -04:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
} else if (declaredPipeMeta = this.getPipeMetadata(declaredType, false)) {
|
|
|
|
this._addPipeToModule(
|
|
|
|
declaredPipeMeta, moduleType, transitiveModule, declaredPipes, true);
|
|
|
|
} else {
|
|
|
|
throw new BaseException(
|
2016-08-17 18:57:02 -04:00
|
|
|
`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
|
2016-07-18 06:50:31 -04:00
|
|
|
}
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 16:07:17 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-07-27 04:52:31 -04:00
|
|
|
// The providers of the module have to go last
|
|
|
|
// so that they overwrite any other provider we already added.
|
|
|
|
if (meta.providers) {
|
2016-08-23 19:18:41 -04:00
|
|
|
providers.push(...this.getProvidersMetadata(
|
|
|
|
meta.providers, entryComponents,
|
|
|
|
`provider for the NgModule '${stringify(moduleType)}'`));
|
2016-07-27 04:52:31 -04:00
|
|
|
}
|
|
|
|
if (meta.entryComponents) {
|
|
|
|
entryComponents.push(
|
|
|
|
...flattenArray(meta.entryComponents)
|
|
|
|
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
|
|
|
}
|
2016-08-02 09:54:08 -04:00
|
|
|
if (meta.bootstrap) {
|
|
|
|
bootstrapComponents.push(
|
|
|
|
...flattenArray(meta.bootstrap)
|
|
|
|
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
|
|
|
}
|
|
|
|
entryComponents.push(...bootstrapComponents);
|
2016-07-27 04:52:31 -04:00
|
|
|
if (meta.schemas) {
|
|
|
|
schemas.push(...flattenArray(meta.schemas));
|
|
|
|
}
|
|
|
|
|
2016-07-25 03:36:30 -04:00
|
|
|
transitiveModule.entryComponents.push(...entryComponents);
|
2016-07-18 06:50:31 -04:00
|
|
|
transitiveModule.providers.push(...providers);
|
|
|
|
|
|
|
|
compileMeta = new cpl.CompileNgModuleMetadata({
|
2016-06-28 12:54:42 -04:00
|
|
|
type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)),
|
|
|
|
providers: providers,
|
2016-07-25 03:36:30 -04:00
|
|
|
entryComponents: entryComponents,
|
2016-08-02 09:54:08 -04:00
|
|
|
bootstrapComponents: bootstrapComponents,
|
2016-07-25 06:02:57 -04:00
|
|
|
schemas: schemas,
|
2016-07-18 06:50:31 -04:00
|
|
|
declaredDirectives: declaredDirectives,
|
|
|
|
exportedDirectives: exportedDirectives,
|
|
|
|
declaredPipes: declaredPipes,
|
|
|
|
exportedPipes: exportedPipes,
|
|
|
|
importedModules: importedModules,
|
|
|
|
exportedModules: exportedModules,
|
|
|
|
transitiveModule: transitiveModule
|
2016-06-28 12:54:42 -04:00
|
|
|
});
|
2016-07-18 06:50:31 -04:00
|
|
|
transitiveModule.modules.push(compileMeta);
|
|
|
|
this._verifyModule(compileMeta);
|
|
|
|
this._ngModuleCache.set(moduleType, compileMeta);
|
2016-06-28 12:54:42 -04:00
|
|
|
}
|
|
|
|
return compileMeta;
|
|
|
|
}
|
|
|
|
|
2016-07-18 06:50:31 -04:00
|
|
|
|
|
|
|
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!`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
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!`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-17 18:57:02 -04:00
|
|
|
private _getTypeDescriptor(type: Type<any>): string {
|
|
|
|
if (this._directiveResolver.resolve(type, false) !== null) {
|
|
|
|
return 'directive';
|
|
|
|
} else if (this._pipeResolver.resolve(type, false) !== null) {
|
|
|
|
return 'pipe';
|
|
|
|
} else if (this._ngModuleResolver.resolve(type, false) !== null) {
|
|
|
|
return 'module';
|
|
|
|
} else if ((type as any).provide) {
|
|
|
|
return 'provider';
|
|
|
|
} else {
|
|
|
|
return 'value';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
private _addTypeToModule(type: Type<any>, moduleType: Type<any>) {
|
2016-07-18 06:50:31 -04:00
|
|
|
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)}!`);
|
2016-02-18 13:53:21 -05:00
|
|
|
}
|
2016-07-18 06:50:31 -04:00
|
|
|
this._ngModuleOfTypes.set(type, moduleType);
|
|
|
|
}
|
|
|
|
|
|
|
|
private _getTransitiveNgModuleMetadata(
|
|
|
|
importedModules: cpl.CompileNgModuleMetadata[],
|
|
|
|
exportedModules: cpl.CompileNgModuleMetadata[]): cpl.TransitiveCompileNgModuleMetadata {
|
2016-07-25 03:36:30 -04:00
|
|
|
// collect `providers` / `entryComponents` from all imported and all exported modules
|
2016-07-18 06:50:31 -04:00
|
|
|
const transitiveModules = getTransitiveModules(importedModules.concat(exportedModules), true);
|
|
|
|
const providers = flattenArray(transitiveModules.map((ngModule) => ngModule.providers));
|
2016-07-25 03:36:30 -04:00
|
|
|
const entryComponents =
|
|
|
|
flattenArray(transitiveModules.map((ngModule) => ngModule.entryComponents));
|
2016-07-18 06:50:31 -04:00
|
|
|
|
|
|
|
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(
|
2016-07-25 03:36:30 -04:00
|
|
|
transitiveModules, providers, entryComponents, directives, pipes);
|
2016-07-18 06:50:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2016-02-18 13:53:21 -05:00
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
getTypeMetadata(type: Type<any>, moduleUrl: string, dependencies: any[] = null):
|
2016-06-18 12:42:34 -04:00
|
|
|
cpl.CompileTypeMetadata {
|
2016-06-28 12:54:42 -04:00
|
|
|
type = resolveForwardRef(type);
|
2016-01-06 17:13:44 -05:00
|
|
|
return new cpl.CompileTypeMetadata({
|
2016-04-20 21:10:19 -04:00
|
|
|
name: this.sanitizeTokenName(type),
|
2016-01-06 17:13:44 -05:00
|
|
|
moduleUrl: moduleUrl,
|
|
|
|
runtime: type,
|
2016-08-02 04:12:24 -04:00
|
|
|
diDeps: this.getDependenciesMetadata(type, dependencies),
|
|
|
|
lifecycleHooks: LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, type)),
|
2016-01-06 17:13:44 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-18 12:42:34 -04:00
|
|
|
getFactoryMetadata(factory: Function, moduleUrl: string, dependencies: any[] = null):
|
|
|
|
cpl.CompileFactoryMetadata {
|
2016-06-28 12:54:42 -04:00
|
|
|
factory = resolveForwardRef(factory);
|
2016-01-06 17:13:44 -05:00
|
|
|
return new cpl.CompileFactoryMetadata({
|
2016-04-20 21:10:19 -04:00
|
|
|
name: this.sanitizeTokenName(factory),
|
2016-01-06 17:13:44 -05:00
|
|
|
moduleUrl: moduleUrl,
|
|
|
|
runtime: factory,
|
2016-06-18 12:42:34 -04:00
|
|
|
diDeps: this.getDependenciesMetadata(factory, dependencies)
|
2016-01-06 17:13:44 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
getPipeMetadata(pipeType: Type<any>, throwIfNotFound = true): cpl.CompilePipeMetadata {
|
2016-06-28 12:54:42 -04:00
|
|
|
pipeType = resolveForwardRef(pipeType);
|
2015-12-02 13:35:51 -05:00
|
|
|
var meta = this._pipeCache.get(pipeType);
|
|
|
|
if (isBlank(meta)) {
|
2016-07-18 06:50:31 -04:00
|
|
|
var pipeMeta = this._pipeResolver.resolve(pipeType, throwIfNotFound);
|
|
|
|
if (!pipeMeta) {
|
|
|
|
return null;
|
|
|
|
}
|
2015-12-02 13:35:51 -05:00
|
|
|
meta = new cpl.CompilePipeMetadata({
|
2016-02-18 13:53:21 -05:00
|
|
|
type: this.getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
|
2015-12-02 13:35:51 -05:00
|
|
|
name: pipeMeta.name,
|
2016-08-02 04:12:24 -04:00
|
|
|
pure: pipeMeta.pure
|
2015-12-02 13:35:51 -05:00
|
|
|
});
|
|
|
|
this._pipeCache.set(pipeType, meta);
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
getDependenciesMetadata(typeOrFunc: Type<any>|Function, dependencies: any[]):
|
2016-06-08 19:38:52 -04:00
|
|
|
cpl.CompileDiDependencyMetadata[] {
|
2016-06-09 19:07:06 -04:00
|
|
|
let hasUnknownDeps = false;
|
2016-02-18 13:53:21 -05:00
|
|
|
let params = isPresent(dependencies) ? dependencies : this._reflector.parameters(typeOrFunc);
|
|
|
|
if (isBlank(params)) {
|
|
|
|
params = [];
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
2016-06-09 19:07:06 -04:00
|
|
|
let dependenciesMetadata: cpl.CompileDiDependencyMetadata[] = params.map((param) => {
|
2016-02-18 13:53:21 -05:00
|
|
|
let isAttribute = false;
|
|
|
|
let isHost = false;
|
|
|
|
let isSelf = false;
|
|
|
|
let isSkipSelf = false;
|
|
|
|
let isOptional = false;
|
2016-04-28 20:50:03 -04:00
|
|
|
let query: QueryMetadata = null;
|
|
|
|
let viewQuery: ViewQueryMetadata = null;
|
2016-06-17 13:57:50 -04:00
|
|
|
var token: any = null;
|
2016-02-18 13:53:21 -05:00
|
|
|
if (isArray(param)) {
|
2016-06-08 19:38:52 -04:00
|
|
|
(<any[]>param).forEach((paramEntry) => {
|
|
|
|
if (paramEntry instanceof HostMetadata) {
|
|
|
|
isHost = true;
|
|
|
|
} else if (paramEntry instanceof SelfMetadata) {
|
|
|
|
isSelf = true;
|
|
|
|
} else if (paramEntry instanceof SkipSelfMetadata) {
|
|
|
|
isSkipSelf = true;
|
|
|
|
} else if (paramEntry instanceof OptionalMetadata) {
|
|
|
|
isOptional = true;
|
|
|
|
} else if (paramEntry instanceof AttributeMetadata) {
|
|
|
|
isAttribute = true;
|
|
|
|
token = paramEntry.attributeName;
|
|
|
|
} else if (paramEntry instanceof QueryMetadata) {
|
|
|
|
if (paramEntry.isViewQuery) {
|
|
|
|
viewQuery = paramEntry;
|
|
|
|
} else {
|
|
|
|
query = paramEntry;
|
|
|
|
}
|
|
|
|
} else if (paramEntry instanceof InjectMetadata) {
|
|
|
|
token = paramEntry.token;
|
|
|
|
} else if (isValidType(paramEntry) && isBlank(token)) {
|
|
|
|
token = paramEntry;
|
|
|
|
}
|
|
|
|
});
|
2016-01-06 17:13:44 -05:00
|
|
|
} else {
|
2016-02-18 13:53:21 -05:00
|
|
|
token = param;
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
2016-02-18 13:53:21 -05:00
|
|
|
if (isBlank(token)) {
|
2016-06-09 19:07:06 -04:00
|
|
|
hasUnknownDeps = true;
|
2016-02-18 13:53:21 -05:00
|
|
|
return null;
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
|
|
|
return new cpl.CompileDiDependencyMetadata({
|
|
|
|
isAttribute: isAttribute,
|
2016-02-18 13:53:21 -05:00
|
|
|
isHost: isHost,
|
|
|
|
isSelf: isSelf,
|
|
|
|
isSkipSelf: isSkipSelf,
|
|
|
|
isOptional: isOptional,
|
2016-06-04 22:46:03 -04:00
|
|
|
query: isPresent(query) ? this.getQueryMetadata(query, null, typeOrFunc) : null,
|
|
|
|
viewQuery: isPresent(viewQuery) ? this.getQueryMetadata(viewQuery, null, typeOrFunc) : null,
|
2016-02-18 13:53:21 -05:00
|
|
|
token: this.getTokenMetadata(token)
|
2016-01-06 17:13:44 -05:00
|
|
|
});
|
2016-02-18 13:53:21 -05:00
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
});
|
2016-06-09 19:07:06 -04:00
|
|
|
|
|
|
|
if (hasUnknownDeps) {
|
2016-06-08 19:38:52 -04:00
|
|
|
let depsTokens =
|
|
|
|
dependenciesMetadata.map((dep) => { return dep ? stringify(dep.token) : '?'; })
|
|
|
|
.join(', ');
|
|
|
|
throw new BaseException(
|
|
|
|
`Can't resolve all parameters for ${stringify(typeOrFunc)}: (${depsTokens}).`);
|
2016-06-09 19:07:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return dependenciesMetadata;
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
getTokenMetadata(token: any): cpl.CompileTokenMetadata {
|
|
|
|
token = resolveForwardRef(token);
|
2016-06-08 18:45:15 -04:00
|
|
|
var compileToken: any /** TODO #9100 */;
|
2016-01-06 17:13:44 -05:00
|
|
|
if (isString(token)) {
|
|
|
|
compileToken = new cpl.CompileTokenMetadata({value: token});
|
|
|
|
} else {
|
2016-04-20 21:10:19 -04:00
|
|
|
compileToken = new cpl.CompileTokenMetadata({
|
2016-02-18 13:53:21 -05:00
|
|
|
identifier: new cpl.CompileIdentifierMetadata({
|
|
|
|
runtime: token,
|
|
|
|
name: this.sanitizeTokenName(token),
|
|
|
|
moduleUrl: staticTypeModuleUrl(token)
|
|
|
|
})
|
2016-04-20 21:10:19 -04:00
|
|
|
});
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
|
|
|
return compileToken;
|
|
|
|
}
|
|
|
|
|
2016-08-23 19:18:41 -04:00
|
|
|
getProvidersMetadata(
|
|
|
|
providers: Provider[], targetEntryComponents: cpl.CompileTypeMetadata[],
|
|
|
|
debugInfo?: string): Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> {
|
2016-07-07 13:05:55 -04:00
|
|
|
const compileProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
2016-08-23 19:18:41 -04:00
|
|
|
providers.forEach((provider: any, providerIdx: number) => {
|
2016-01-06 17:13:44 -05:00
|
|
|
provider = resolveForwardRef(provider);
|
2016-08-15 22:37:42 -04:00
|
|
|
if (provider && typeof provider == 'object' && provider.hasOwnProperty('provide')) {
|
|
|
|
provider = new cpl.ProviderMeta(provider.provide, provider);
|
2016-07-07 13:05:55 -04:00
|
|
|
}
|
|
|
|
let compileProvider: cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[];
|
2016-01-06 17:13:44 -05:00
|
|
|
if (isArray(provider)) {
|
2016-08-23 19:18:41 -04:00
|
|
|
compileProvider = this.getProvidersMetadata(provider, targetEntryComponents, debugInfo);
|
2016-08-15 22:37:42 -04:00
|
|
|
} else if (provider instanceof cpl.ProviderMeta) {
|
2016-07-07 13:05:55 -04:00
|
|
|
let tokenMeta = this.getTokenMetadata(provider.token);
|
2016-07-25 03:36:30 -04:00
|
|
|
if (tokenMeta.equalsTo(identifierToken(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS))) {
|
|
|
|
targetEntryComponents.push(...this._getEntryComponentsFromProvider(provider));
|
2016-07-07 13:05:55 -04:00
|
|
|
} else {
|
|
|
|
compileProvider = this.getProviderMetadata(provider);
|
|
|
|
}
|
2016-06-28 12:54:42 -04:00
|
|
|
} else if (isValidType(provider)) {
|
2016-07-07 13:05:55 -04:00
|
|
|
compileProvider = this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
|
2016-06-28 12:54:42 -04:00
|
|
|
} else {
|
2016-08-23 19:18:41 -04:00
|
|
|
let providersInfo = (<string[]>providers.reduce(
|
|
|
|
(soFar: string[], seenProvider: any, seenProviderIdx: number) => {
|
|
|
|
if (seenProviderIdx < providerIdx) {
|
|
|
|
soFar.push(`${stringify(seenProvider)}`);
|
|
|
|
} else if (seenProviderIdx == providerIdx) {
|
|
|
|
soFar.push(`?${stringify(seenProvider)}?`);
|
|
|
|
} else if (seenProviderIdx == providerIdx + 1) {
|
|
|
|
soFar.push('...');
|
|
|
|
}
|
|
|
|
return soFar;
|
|
|
|
},
|
|
|
|
[]))
|
|
|
|
.join(', ');
|
|
|
|
|
2016-06-28 12:54:42 -04:00
|
|
|
throw new BaseException(
|
2016-08-23 19:18:41 -04:00
|
|
|
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`);
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
2016-07-07 13:05:55 -04:00
|
|
|
if (compileProvider) {
|
|
|
|
compileProviders.push(compileProvider);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return compileProviders;
|
|
|
|
}
|
|
|
|
|
2016-08-15 22:37:42 -04:00
|
|
|
private _getEntryComponentsFromProvider(provider: cpl.ProviderMeta): cpl.CompileTypeMetadata[] {
|
2016-07-07 13:05:55 -04:00
|
|
|
let components: cpl.CompileTypeMetadata[] = [];
|
|
|
|
let collectedIdentifiers: cpl.CompileIdentifierMetadata[] = [];
|
|
|
|
if (provider.useFactory || provider.useExisting || provider.useClass) {
|
2016-07-25 03:36:30 -04:00
|
|
|
throw new BaseException(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!`);
|
2016-07-07 13:05:55 -04:00
|
|
|
}
|
|
|
|
if (!provider.multi) {
|
2016-07-25 03:36:30 -04:00
|
|
|
throw new BaseException(
|
|
|
|
`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!`);
|
2016-07-07 13:05:55 -04:00
|
|
|
}
|
|
|
|
convertToCompileValue(provider.useValue, collectedIdentifiers);
|
|
|
|
collectedIdentifiers.forEach((identifier) => {
|
2016-07-18 06:50:31 -04:00
|
|
|
let dirMeta = this.getDirectiveMetadata(identifier.runtime, false);
|
2016-07-07 13:05:55 -04:00
|
|
|
if (dirMeta) {
|
|
|
|
components.push(dirMeta.type);
|
|
|
|
}
|
2016-01-06 17:13:44 -05:00
|
|
|
});
|
2016-07-07 13:05:55 -04:00
|
|
|
return components;
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
|
|
|
|
2016-08-15 22:37:42 -04:00
|
|
|
getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata {
|
2016-06-18 12:42:34 -04:00
|
|
|
var compileDeps: cpl.CompileDiDependencyMetadata[];
|
|
|
|
var compileTypeMetadata: cpl.CompileTypeMetadata = null;
|
|
|
|
var compileFactoryMetadata: cpl.CompileFactoryMetadata = null;
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
if (isPresent(provider.useClass)) {
|
2016-06-18 12:42:34 -04:00
|
|
|
compileTypeMetadata = this.getTypeMetadata(
|
|
|
|
provider.useClass, staticTypeModuleUrl(provider.useClass), provider.dependencies);
|
|
|
|
compileDeps = compileTypeMetadata.diDeps;
|
2016-01-06 17:13:44 -05:00
|
|
|
} else if (isPresent(provider.useFactory)) {
|
2016-06-18 12:42:34 -04:00
|
|
|
compileFactoryMetadata = this.getFactoryMetadata(
|
|
|
|
provider.useFactory, staticTypeModuleUrl(provider.useFactory), provider.dependencies);
|
|
|
|
compileDeps = compileFactoryMetadata.diDeps;
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
2016-06-18 12:42:34 -04:00
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
return new cpl.CompileProviderMetadata({
|
|
|
|
token: this.getTokenMetadata(provider.token),
|
2016-06-18 12:42:34 -04:00
|
|
|
useClass: compileTypeMetadata,
|
2016-07-07 13:05:55 -04:00
|
|
|
useValue: convertToCompileValue(provider.useValue, []),
|
2016-06-18 12:42:34 -04:00
|
|
|
useFactory: compileFactoryMetadata,
|
2016-01-06 17:13:44 -05:00
|
|
|
useExisting: isPresent(provider.useExisting) ? this.getTokenMetadata(provider.useExisting) :
|
|
|
|
null,
|
|
|
|
deps: compileDeps,
|
|
|
|
multi: provider.multi
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
getQueriesMetadata(
|
|
|
|
queries: {[key: string]: QueryMetadata}, isViewQuery: boolean,
|
2016-08-10 21:21:28 -04:00
|
|
|
directiveType: Type<any>): cpl.CompileQueryMetadata[] {
|
2016-06-22 20:25:42 -04:00
|
|
|
var res: cpl.CompileQueryMetadata[] = [];
|
|
|
|
StringMapWrapper.forEach(queries, (query: QueryMetadata, propertyName: string) => {
|
|
|
|
if (query.isViewQuery === isViewQuery) {
|
|
|
|
res.push(this.getQueryMetadata(query, propertyName, directiveType));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return res;
|
2016-01-06 17:13:44 -05:00
|
|
|
}
|
|
|
|
|
2016-08-10 21:21:28 -04:00
|
|
|
getQueryMetadata(q: QueryMetadata, propertyName: string, typeOrFunc: Type<any>|Function):
|
2016-06-08 19:38:52 -04:00
|
|
|
cpl.CompileQueryMetadata {
|
2016-06-17 13:57:50 -04:00
|
|
|
var selectors: cpl.CompileTokenMetadata[];
|
2016-01-06 17:13:44 -05:00
|
|
|
if (q.isVarBindingQuery) {
|
|
|
|
selectors = q.varBindings.map(varName => this.getTokenMetadata(varName));
|
|
|
|
} else {
|
2016-06-04 22:46:03 -04:00
|
|
|
if (!isPresent(q.selector)) {
|
2016-06-08 19:38:52 -04:00
|
|
|
throw new BaseException(
|
|
|
|
`Can't construct a query for the property "${propertyName}" of "${stringify(typeOrFunc)}" since the query selector wasn't defined.`);
|
2016-06-04 22:46:03 -04:00
|
|
|
}
|
2016-01-06 17:13:44 -05:00
|
|
|
selectors = [this.getTokenMetadata(q.selector)];
|
|
|
|
}
|
|
|
|
return new cpl.CompileQueryMetadata({
|
|
|
|
selectors: selectors,
|
|
|
|
first: q.first,
|
|
|
|
descendants: q.descendants,
|
2016-04-18 16:24:42 -04:00
|
|
|
propertyName: propertyName,
|
|
|
|
read: isPresent(q.read) ? this.getTokenMetadata(q.read) : null
|
2016-01-06 17:13:44 -05:00
|
|
|
});
|
|
|
|
}
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
|
|
|
|
2016-07-18 06:50:31 -04:00
|
|
|
function getTransitiveModules(
|
|
|
|
modules: cpl.CompileNgModuleMetadata[], includeImports: boolean,
|
|
|
|
targetModules: cpl.CompileNgModuleMetadata[] = [],
|
2016-08-10 21:21:28 -04:00
|
|
|
visitedModules = new Set<Type<any>>()): cpl.CompileNgModuleMetadata[] {
|
2016-07-18 06:50:31 -04:00
|
|
|
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;
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
|
|
|
|
2015-12-02 13:35:51 -05:00
|
|
|
|
2016-07-18 06:50:31 -04:00
|
|
|
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);
|
|
|
|
}
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
|
|
|
}
|
2016-06-22 17:06:23 -04:00
|
|
|
return out;
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
|
|
|
|
2016-02-18 13:53:21 -05:00
|
|
|
function isValidType(value: any): boolean {
|
2016-06-28 12:54:42 -04:00
|
|
|
return cpl.isStaticSymbol(value) || (value instanceof Type);
|
2016-02-18 13:53:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
function staticTypeModuleUrl(value: any): string {
|
2016-06-28 12:54:42 -04:00
|
|
|
return cpl.isStaticSymbol(value) ? value.filePath : null;
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
function componentModuleUrl(
|
|
|
|
reflector: ReflectorReader, type: any, cmpMetadata: ComponentMetadata): string {
|
2016-06-28 12:54:42 -04:00
|
|
|
if (cpl.isStaticSymbol(type)) {
|
2016-05-02 12:38:46 -04:00
|
|
|
return staticTypeModuleUrl(type);
|
2016-04-29 00:54:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(cmpMetadata.moduleId)) {
|
|
|
|
var moduleId = cmpMetadata.moduleId;
|
2015-12-05 05:21:38 -05:00
|
|
|
var scheme = getUrlScheme(moduleId);
|
|
|
|
return isPresent(scheme) && scheme.length > 0 ? moduleId :
|
2016-05-02 01:50:37 -04:00
|
|
|
`package:${moduleId}${MODULE_SUFFIX}`;
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
2016-04-29 00:54:02 -04:00
|
|
|
|
|
|
|
return reflector.importUri(type);
|
2015-09-14 18:59:09 -04:00
|
|
|
}
|
2016-04-30 19:13:03 -04:00
|
|
|
|
2016-07-07 13:05:55 -04:00
|
|
|
function convertToCompileValue(
|
|
|
|
value: any, targetIdentifiers: cpl.CompileIdentifierMetadata[]): any {
|
|
|
|
return visitValue(value, new _CompileValueConverter(), targetIdentifiers);
|
2016-04-30 19:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
class _CompileValueConverter extends ValueTransformer {
|
2016-07-07 13:05:55 -04:00
|
|
|
visitOther(value: any, targetIdentifiers: cpl.CompileIdentifierMetadata[]): any {
|
|
|
|
let identifier: cpl.CompileIdentifierMetadata;
|
2016-06-28 12:54:42 -04:00
|
|
|
if (cpl.isStaticSymbol(value)) {
|
2016-07-07 13:05:55 -04:00
|
|
|
identifier = new cpl.CompileIdentifierMetadata(
|
|
|
|
{name: value.name, moduleUrl: value.filePath, runtime: value});
|
2016-04-30 19:13:03 -04:00
|
|
|
} else {
|
2016-07-07 13:05:55 -04:00
|
|
|
identifier = new cpl.CompileIdentifierMetadata({runtime: value});
|
2016-04-30 19:13:03 -04:00
|
|
|
}
|
2016-07-07 13:05:55 -04:00
|
|
|
targetIdentifiers.push(identifier);
|
|
|
|
return identifier;
|
2016-04-30 19:13:03 -04:00
|
|
|
}
|
|
|
|
}
|