2016-06-23 09:47:54 -07: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-09-12 19:14:17 -07:00
import { AnimationAnimateMetadata , AnimationEntryMetadata , AnimationGroupMetadata , AnimationKeyframesSequenceMetadata , AnimationMetadata , AnimationStateDeclarationMetadata , AnimationStateMetadata , AnimationStateTransitionMetadata , AnimationStyleMetadata , AnimationWithStepsMetadata , Attribute , ChangeDetectionStrategy , Component , Host , Inject , Injectable , ModuleWithProviders , Optional , Provider , Query , SchemaMetadata , Self , SkipSelf , Type , resolveForwardRef } from '@angular/core' ;
2016-06-08 16:38:52 -07:00
2016-06-20 09:52:41 -07:00
import { assertArrayOfStrings , assertInterpolationSymbols } from './assertions' ;
2016-01-06 14:13:44 -08:00
import * as cpl from './compile_metadata' ;
2016-11-10 14:07:30 -08:00
import { DirectiveNormalizer } from './directive_normalizer' ;
2016-01-06 14:13:44 -08:00
import { DirectiveResolver } from './directive_resolver' ;
2016-11-10 16:27:53 -08:00
import { ListWrapper , StringMapWrapper } from './facade/collection' ;
2016-10-19 13:42:39 -07:00
import { isBlank , isPresent , stringify } from './facade/lang' ;
2016-08-24 17:39:49 -07:00
import { Identifiers , resolveIdentifierToken } from './identifiers' ;
2016-08-02 01:37:42 -07:00
import { hasLifecycleHook } from './lifecycle_reflector' ;
2016-07-18 03:50:31 -07:00
import { NgModuleResolver } from './ng_module_resolver' ;
2016-01-06 14:13:44 -08:00
import { PipeResolver } from './pipe_resolver' ;
2016-11-10 14:07:30 -08:00
import { ComponentStillLoadingError , LIFECYCLE_HOOKS_VALUES , ReflectorReader , reflector } from './private_import_core' ;
2016-07-28 19:39:10 +02:00
import { ElementSchemaRegistry } from './schema/element_schema_registry' ;
2016-04-28 17:50:03 -07:00
import { getUrlScheme } from './url_resolver' ;
2016-11-10 14:07:30 -08:00
import { MODULE_SUFFIX , SyncAsyncResult , ValueTransformer , sanitizeIdentifier , visitValue } from './util' ;
2016-04-28 17:50:03 -07:00
2016-11-10 14:07:30 -08:00
2016-11-10 16:27:53 -08:00
2016-11-10 14:07:30 -08:00
// Design notes:
// - don't lazily create metadata:
// For some metadata, we need to do async work sometimes,
// so the user has to kick off this loading.
// But we want to report errors even when the async work is
// not required to check that the user would have been able
// to wait correctly.
2015-09-14 15:59:09 -07:00
@Injectable ()
2016-02-18 10:53:21 -08:00
export class CompileMetadataResolver {
2016-08-10 18:21:28 -07:00
private _directiveCache = new Map < Type < any >, cpl.CompileDirectiveMetadata >();
2016-11-10 16:27:53 -08:00
private _directiveSummaryCache = new Map < Type < any >, cpl.CompileDirectiveSummary >();
2016-08-10 18:21:28 -07:00
private _pipeCache = new Map < Type < any >, cpl.CompilePipeMetadata >();
2016-11-10 16:27:53 -08:00
private _pipeSummaryCache = new Map < Type < any >, cpl.CompilePipeSummary >();
2016-08-10 18:21:28 -07:00
private _ngModuleCache = new Map < Type < any >, cpl.CompileNgModuleMetadata >();
private _ngModuleOfTypes = new Map < Type < any >, Type < any >>();
2016-03-29 17:15:07 -07:00
private _anonymousTypes = new Map < Object , number >();
private _anonymousTypeIndex = 0 ;
2015-09-14 15:59:09 -07:00
2016-06-08 16:38:52 -07:00
constructor (
2016-07-18 03:50:31 -07:00
private _ngModuleResolver : NgModuleResolver , private _directiveResolver : DirectiveResolver ,
2016-08-19 13:51:45 -07:00
private _pipeResolver : PipeResolver , private _schemaRegistry : ElementSchemaRegistry ,
2016-11-10 14:07:30 -08:00
private _directiveNormalizer : DirectiveNormalizer ,
2016-07-29 02:10:30 -07:00
private _reflector : ReflectorReader = reflector ) {}
2015-09-14 15:59:09 -07:00
2016-04-20 18:10:19 -07:00
private sanitizeTokenName ( token : any ) : string {
let identifier = stringify ( token );
if ( identifier . indexOf ( '(' ) >= 0 ) {
// case: anonymous functions!
let found = this . _anonymousTypes . get ( token );
2016-09-14 15:58:18 -07:00
if ( ! found ) {
2016-04-20 18:10:19 -07:00
this . _anonymousTypes . set ( token , this . _anonymousTypeIndex ++ );
found = this . _anonymousTypes . get ( token );
}
identifier = `anonymous_token_ ${ found } _` ;
2016-03-29 17:15:07 -07:00
}
2016-04-20 18:10:19 -07:00
return sanitizeIdentifier ( identifier );
2016-03-29 17:15:07 -07:00
}
2016-08-10 18:21:28 -07:00
clearCacheFor ( type : Type < any >) {
2016-11-10 14:07:30 -08:00
const dirMeta = this . _directiveCache . get ( type );
2016-06-28 09:54:42 -07:00
this . _directiveCache . delete ( type );
2016-11-10 16:27:53 -08:00
this . _directiveSummaryCache . delete ( type );
2016-06-28 09:54:42 -07:00
this . _pipeCache . delete ( type );
2016-11-10 16:27:53 -08:00
this . _pipeSummaryCache . delete ( type );
2016-07-18 03:50:31 -07:00
this . _ngModuleOfTypes . delete ( type );
2016-09-12 19:14:17 -07:00
// Clear all of the NgModule as they contain transitive information!
2016-07-18 03:50:31 -07:00
this . _ngModuleCache . clear ();
2016-11-10 14:07:30 -08:00
if ( dirMeta ) {
this . _directiveNormalizer . clearCacheFor ( dirMeta );
}
2016-06-24 08:46:43 -07:00
}
clearCache() {
this . _directiveCache . clear ();
2016-11-10 16:27:53 -08:00
this . _directiveSummaryCache . clear ();
2016-06-24 08:46:43 -07:00
this . _pipeCache . clear ();
2016-11-10 16:27:53 -08:00
this . _pipeSummaryCache . clear ();
2016-07-18 03:50:31 -07:00
this . _ngModuleCache . clear ();
this . _ngModuleOfTypes . clear ();
2016-11-10 14:07:30 -08:00
this . _directiveNormalizer . clearCache ();
2016-06-24 08:46:43 -07:00
}
2016-05-26 15:07:51 -07:00
getAnimationEntryMetadata ( entry : AnimationEntryMetadata ) : cpl . CompileAnimationEntryMetadata {
2016-11-10 14:07:30 -08:00
const defs = entry . definitions . map ( def => this . _getAnimationStateMetadata ( def ));
2016-05-25 12:46:22 -07:00
return new cpl . CompileAnimationEntryMetadata ( entry . name , defs );
}
2016-11-10 14:07:30 -08:00
private _getAnimationStateMetadata ( value : AnimationStateMetadata ) :
cpl . CompileAnimationStateMetadata {
2016-05-26 15:07:51 -07:00
if ( value instanceof AnimationStateDeclarationMetadata ) {
2016-11-10 14:07:30 -08:00
const styles = this . _getAnimationStyleMetadata ( value . styles );
2016-05-25 12:46:22 -07:00
return new cpl . CompileAnimationStateDeclarationMetadata ( value . stateNameExpr , styles );
2016-09-14 15:58:18 -07:00
}
if ( value instanceof AnimationStateTransitionMetadata ) {
2016-06-08 16:38:52 -07:00
return new cpl . CompileAnimationStateTransitionMetadata (
2016-11-10 14:07:30 -08:00
value . stateChangeExpr , this . _getAnimationMetadata ( value . steps ));
2016-05-25 12:46:22 -07:00
}
2016-09-14 15:58:18 -07:00
2016-05-25 12:46:22 -07:00
return null ;
}
2016-11-10 14:07:30 -08:00
private _getAnimationStyleMetadata ( value : AnimationStyleMetadata ) :
cpl . CompileAnimationStyleMetadata {
2016-05-25 12:46:22 -07:00
return new cpl . CompileAnimationStyleMetadata ( value . offset , value . styles );
}
2016-11-10 14:07:30 -08:00
private _getAnimationMetadata ( value : AnimationMetadata ) : cpl . CompileAnimationMetadata {
2016-05-26 15:07:51 -07:00
if ( value instanceof AnimationStyleMetadata ) {
2016-11-10 14:07:30 -08:00
return this . _getAnimationStyleMetadata ( value );
2016-09-14 15:58:18 -07:00
}
if ( value instanceof AnimationKeyframesSequenceMetadata ) {
2016-06-08 16:38:52 -07:00
return new cpl . CompileAnimationKeyframesSequenceMetadata (
2016-11-10 14:07:30 -08:00
value . steps . map ( entry => this . _getAnimationStyleMetadata ( entry )));
2016-09-14 15:58:18 -07:00
}
if ( value instanceof AnimationAnimateMetadata ) {
const animateData =
2016-06-08 16:38:52 -07:00
< cpl.CompileAnimationStyleMetadata | cpl.CompileAnimationKeyframesSequenceMetadata > this
2016-11-10 14:07:30 -08:00
. _getAnimationMetadata ( value . styles );
2016-05-25 12:46:22 -07:00
return new cpl . CompileAnimationAnimateMetadata ( value . timings , animateData );
2016-09-14 15:58:18 -07:00
}
if ( value instanceof AnimationWithStepsMetadata ) {
2016-11-10 14:07:30 -08:00
const steps = value . steps . map ( step => this . _getAnimationMetadata ( step ));
2016-09-14 15:58:18 -07:00
2016-05-26 15:07:51 -07:00
if ( value instanceof AnimationGroupMetadata ) {
2016-05-25 12:46:22 -07:00
return new cpl . CompileAnimationGroupMetadata ( steps );
}
2016-09-14 15:58:18 -07:00
return new cpl . CompileAnimationSequenceMetadata ( steps );
2016-05-25 12:46:22 -07:00
}
return null ;
}
2016-11-10 14:07:30 -08:00
private _loadDirectiveMetadata ( directiveType : any , isSync : boolean ) : Promise < any > {
if ( this . _directiveCache . has ( directiveType )) {
return ;
}
2016-06-28 09:54:42 -07:00
directiveType = resolveForwardRef ( directiveType );
2016-11-10 14:07:30 -08:00
const dirMeta = this . _directiveResolver . resolve ( directiveType );
if ( ! dirMeta ) {
return null ;
}
let moduleUrl = staticTypeModuleUrl ( directiveType );
const createDirectiveMetadata = ( templateMeta : cpl.CompileTemplateMetadata ) => {
2016-09-14 15:58:18 -07:00
let changeDetectionStrategy : ChangeDetectionStrategy = null ;
let viewProviders : Array < cpl.CompileProviderMetadata | cpl.CompileTypeMetadata | any [] > = [];
2016-11-10 14:07:30 -08:00
let entryComponentMetadata : cpl.CompileIdentifierMetadata [] = [];
2016-07-28 19:39:10 +02:00
let selector = dirMeta . selector ;
2016-09-14 15:58:18 -07:00
2016-09-12 19:14:17 -07:00
if ( dirMeta instanceof Component ) {
2016-09-14 15:58:18 -07:00
// Component
changeDetectionStrategy = dirMeta . changeDetection ;
if ( dirMeta . viewProviders ) {
2016-11-10 14:07:30 -08:00
viewProviders = this . _getProvidersMetadata (
2016-08-24 01:18:41 +02:00
dirMeta . viewProviders , entryComponentMetadata ,
`viewProviders for " ${ stringify ( directiveType ) } "` );
2016-01-06 14:13:44 -08:00
}
2016-09-14 15:58:18 -07:00
if ( dirMeta . entryComponents ) {
2016-08-19 13:51:45 -07:00
entryComponentMetadata =
2016-10-28 14:08:54 -07:00
flattenAndDedupeArray ( dirMeta . entryComponents )
2016-11-10 14:07:30 -08:00
. map (( type ) => this . _getIdentifierMetadata ( type , staticTypeModuleUrl ( type )))
2016-08-19 13:51:45 -07:00
. concat ( entryComponentMetadata );
2016-06-22 14:06:23 -07:00
}
2016-07-28 19:39:10 +02:00
if ( ! selector ) {
selector = this . _schemaRegistry . getDefaultComponentElementName ();
}
} else {
2016-09-14 15:58:18 -07:00
// Directive
2016-07-28 19:39:10 +02:00
if ( ! selector ) {
2016-08-25 00:50:16 -07:00
throw new Error ( `Directive ${ stringify ( directiveType ) } has no selector, please add it!` );
2016-07-28 19:39:10 +02:00
}
2016-01-06 14:13:44 -08:00
}
2016-09-14 15:58:18 -07:00
let providers : Array < cpl.CompileProviderMetadata | cpl.CompileTypeMetadata | any [] > = [];
2016-01-06 14:13:44 -08:00
if ( isPresent ( dirMeta . providers )) {
2016-11-10 14:07:30 -08:00
providers = this . _getProvidersMetadata (
2016-08-24 01:18:41 +02:00
dirMeta . providers , entryComponentMetadata ,
`providers for " ${ stringify ( directiveType ) } "` );
2016-01-06 14:13:44 -08:00
}
2016-09-14 15:58:18 -07:00
let queries : cpl.CompileQueryMetadata [] = [];
let viewQueries : cpl.CompileQueryMetadata [] = [];
2016-01-06 14:13:44 -08:00
if ( isPresent ( dirMeta . queries )) {
2016-11-10 14:07:30 -08:00
queries = this . _getQueriesMetadata ( dirMeta . queries , false , directiveType );
viewQueries = this . _getQueriesMetadata ( dirMeta . queries , true , directiveType );
2015-09-14 15:59:09 -07:00
}
2016-09-14 15:58:18 -07:00
2016-11-10 14:07:30 -08:00
const meta = cpl . CompileDirectiveMetadata . create ({
2016-07-28 19:39:10 +02:00
selector : selector ,
2015-10-23 15:55:48 -07:00
exportAs : dirMeta.exportAs ,
2016-09-14 15:58:18 -07:00
isComponent : !! templateMeta ,
2016-11-10 14:07:30 -08:00
type : this . _getTypeMetadata ( directiveType , moduleUrl ),
2015-09-14 15:59:09 -07:00
template : templateMeta ,
2015-09-18 10:33:23 -07:00
changeDetection : changeDetectionStrategy ,
2015-10-23 15:55:48 -07:00
inputs : dirMeta.inputs ,
outputs : dirMeta.outputs ,
host : dirMeta.host ,
2016-01-06 14:13:44 -08:00
providers : providers ,
viewProviders : viewProviders ,
queries : queries ,
2016-06-22 14:06:23 -07:00
viewQueries : viewQueries ,
2016-08-19 13:51:45 -07:00
entryComponents : entryComponentMetadata
2015-09-14 15:59:09 -07:00
});
2015-12-02 10:35:51 -08:00
this . _directiveCache . set ( directiveType , meta );
2016-11-10 16:27:53 -08:00
this . _directiveSummaryCache . set ( directiveType , meta . toSummary ());
2016-11-10 14:07:30 -08:00
return meta ;
};
if ( dirMeta instanceof Component ) {
// component
moduleUrl = componentModuleUrl ( this . _reflector , directiveType , dirMeta );
assertArrayOfStrings ( 'styles' , dirMeta . styles );
assertArrayOfStrings ( 'styleUrls' , dirMeta . styleUrls );
assertInterpolationSymbols ( 'interpolation' , dirMeta . interpolation );
const animations = dirMeta . animations ?
dirMeta . animations . map ( e => this . getAnimationEntryMetadata ( e )) :
null ;
const templateMeta = this . _directiveNormalizer . normalizeTemplate ({
componentType : directiveType ,
moduleUrl : moduleUrl ,
encapsulation : dirMeta.encapsulation ,
template : dirMeta.template ,
templateUrl : dirMeta.templateUrl ,
styles : dirMeta.styles ,
styleUrls : dirMeta.styleUrls ,
animations : animations ,
interpolation : dirMeta.interpolation
});
if ( templateMeta . syncResult ) {
createDirectiveMetadata ( templateMeta . syncResult );
return null ;
} else {
if ( isSync ) {
throw new ComponentStillLoadingError ( directiveType );
}
return templateMeta . asyncResult . then ( createDirectiveMetadata );
}
} else {
// directive
createDirectiveMetadata ( null );
return null ;
2015-12-02 10:35:51 -08:00
}
}
2016-11-10 14:07:30 -08:00
/**
* Gets the metadata for the given directive.
* This assumes `loadNgModuleMetadata` has been called first.
*/
getDirectiveMetadata ( directiveType : any ) : cpl . CompileDirectiveMetadata {
const dirMeta = this . _directiveCache . get ( directiveType );
if ( ! dirMeta ) {
throw new Error (
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleMetadata for a module that declares it. Directive ${ stringify ( directiveType ) } .` );
}
return dirMeta ;
}
2016-11-10 16:27:53 -08:00
getDirectiveSummary ( dirType : any ) : cpl . CompileDirectiveSummary {
const dirSummary = this . _directiveSummaryCache . get ( dirType );
if ( ! dirSummary ) {
throw new Error (
`Illegal state: getDirectiveSummary can only be called after loadNgModuleMetadata for a module that imports it. Directive ${ stringify ( dirType ) } .` );
}
return dirSummary ;
}
2016-11-10 14:07:30 -08:00
isDirective ( type : any ) { return this . _directiveResolver . isDirective ( type ); }
isPipe ( type : any ) { return this . _pipeResolver . isPipe ( type ); }
/**
* Gets the metadata for the given module.
* This assumes `loadNgModuleMetadata` has been called first.
*/
getNgModuleMetadata ( moduleType : any ) : cpl . CompileNgModuleMetadata {
const modMeta = this . _ngModuleCache . get ( moduleType );
if ( ! modMeta ) {
throw new Error (
`Illegal state: getNgModuleMetadata can only be called after loadNgModuleMetadata. Module ${ stringify ( moduleType ) } .` );
}
return modMeta ;
}
2016-11-10 16:27:53 -08:00
private _loadNgModuleSummary ( moduleType : any , isSync : boolean ) : cpl . CompileNgModuleSummary {
// TODO(tbosch): add logic to read summary files!
// - needs to add directive / pipe summaries to this._directiveSummaryCache /
// this._pipeSummaryCache as well!
const moduleMeta = this . _loadNgModuleMetadata ( moduleType , isSync , false );
return moduleMeta ? moduleMeta . toSummary () : null ;
}
2016-11-10 14:07:30 -08:00
/**
* Loads an NgModule and all of its directives. This includes loading the exported directives of
* imported modules,
* but not private directives of imported modules.
*/
loadNgModuleMetadata ( moduleType : any , isSync : boolean , throwIfNotFound = true ) :
{ ngModule : cpl.CompileNgModuleMetadata , loading : Promise < any >} {
const ngModule = this . _loadNgModuleMetadata ( moduleType , isSync , throwIfNotFound );
const loading =
ngModule ? Promise . all ( ngModule . transitiveModule . loadingPromises ) : Promise . resolve ( null );
return { ngModule , loading };
}
private _loadNgModuleMetadata ( moduleType : any , isSync : boolean , throwIfNotFound = true ) :
cpl . CompileNgModuleMetadata {
2016-06-28 09:54:42 -07:00
moduleType = resolveForwardRef ( moduleType );
2016-09-14 15:58:18 -07:00
let compileMeta = this . _ngModuleCache . get ( moduleType );
2016-11-10 14:07:30 -08:00
if ( compileMeta ) {
return compileMeta ;
2016-06-28 09:54:42 -07:00
}
2016-11-10 14:07:30 -08:00
const meta = this . _ngModuleResolver . resolve ( moduleType , throwIfNotFound );
if ( ! meta ) {
return null ;
}
const declaredDirectives : cpl.CompileIdentifierMetadata [] = [];
2016-11-10 16:27:53 -08:00
const exportedNonModuleIdentifiers : cpl.CompileIdentifierMetadata [] = [];
2016-11-10 14:07:30 -08:00
const declaredPipes : cpl.CompileIdentifierMetadata [] = [];
2016-11-10 16:27:53 -08:00
const importedModules : cpl.CompileNgModuleSummary [] = [];
const exportedModules : cpl.CompileNgModuleSummary [] = [];
2016-11-10 14:07:30 -08:00
const providers : any [] = [];
const entryComponents : cpl.CompileIdentifierMetadata [] = [];
const bootstrapComponents : cpl.CompileIdentifierMetadata [] = [];
const schemas : SchemaMetadata [] = [];
if ( meta . imports ) {
flattenAndDedupeArray ( meta . imports ). forEach (( importedType ) => {
let importedModuleType : Type < any >;
if ( isValidType ( importedType )) {
importedModuleType = importedType ;
} else if ( importedType && importedType . ngModule ) {
const moduleWithProviders : ModuleWithProviders = importedType ;
importedModuleType = moduleWithProviders . ngModule ;
if ( moduleWithProviders . providers ) {
providers . push (... this . _getProvidersMetadata (
moduleWithProviders . providers , entryComponents ,
`provider for the NgModule ' ${ stringify ( importedModuleType ) } '` ));
}
}
if ( importedModuleType ) {
2016-11-10 16:27:53 -08:00
const importedModuleSummary = this . _loadNgModuleSummary ( importedModuleType , isSync );
if ( ! importedModuleSummary ) {
2016-11-10 14:07:30 -08:00
throw new Error (
`Unexpected ${ this . _getTypeDescriptor ( importedType ) } ' ${ stringify ( importedType ) } ' imported by the module ' ${ stringify ( moduleType ) } '` );
}
2016-11-10 16:27:53 -08:00
importedModules . push ( importedModuleSummary );
2016-11-10 14:07:30 -08:00
} else {
throw new Error (
`Unexpected value ' ${ stringify ( importedType ) } ' imported by the module ' ${ stringify ( moduleType ) } '` );
}
});
}
if ( meta . exports ) {
flattenAndDedupeArray ( meta . exports ). forEach (( exportedType ) => {
if ( ! isValidType ( exportedType )) {
throw new Error (
`Unexpected value ' ${ stringify ( exportedType ) } ' exported by the module ' ${ stringify ( moduleType ) } '` );
}
2016-11-10 16:27:53 -08:00
const exportedModuleSummary = this . _loadNgModuleSummary ( exportedType , isSync );
if ( exportedModuleSummary ) {
exportedModules . push ( exportedModuleSummary );
2016-11-10 14:07:30 -08:00
} else {
2016-11-10 16:27:53 -08:00
exportedNonModuleIdentifiers . push (
this . _getIdentifierMetadata ( exportedType , staticTypeModuleUrl ( exportedType )));
2016-11-10 14:07:30 -08: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 ) {
flattenAndDedupeArray ( meta . declarations ). forEach (( declaredType ) => {
if ( ! isValidType ( declaredType )) {
throw new Error (
`Unexpected value ' ${ stringify ( declaredType ) } ' declared by the module ' ${ stringify ( moduleType ) } '` );
}
const declaredIdentifier =
this . _getIdentifierMetadata ( declaredType , staticTypeModuleUrl ( declaredType ));
if ( this . _directiveResolver . isDirective ( declaredType )) {
transitiveModule . directivesSet . add ( declaredType );
transitiveModule . directives . push ( declaredIdentifier );
declaredDirectives . push ( declaredIdentifier );
this . _addTypeToModule ( declaredType , moduleType );
const loadingPromise = this . _loadDirectiveMetadata ( declaredType , isSync );
if ( loadingPromise ) {
transitiveModule . loadingPromises . push ( loadingPromise );
}
} else if ( this . _pipeResolver . isPipe ( declaredType )) {
transitiveModule . pipesSet . add ( declaredType );
transitiveModule . pipes . push ( declaredIdentifier );
declaredPipes . push ( declaredIdentifier );
this . _addTypeToModule ( declaredType , moduleType );
this . _loadPipeMetadata ( declaredType );
} else {
throw new Error (
`Unexpected ${ this . _getTypeDescriptor ( declaredType ) } ' ${ stringify ( declaredType ) } ' declared by the module ' ${ stringify ( moduleType ) } '` );
}
});
}
2016-11-10 16:27:53 -08:00
const exportedDirectives : cpl.CompileIdentifierMetadata [] = [];
const exportedPipes : cpl.CompileIdentifierMetadata [] = [];
exportedNonModuleIdentifiers . forEach (( exportedId ) => {
if ( transitiveModule . directivesSet . has ( exportedId . reference )) {
exportedDirectives . push ( exportedId );
} else if ( transitiveModule . pipesSet . has ( exportedId . reference )) {
exportedPipes . push ( exportedId );
} else {
throw new Error (
`Can't export ${ this . _getTypeDescriptor ( exportedId . reference ) } ${ stringify ( exportedId . reference ) } from ${ stringify ( moduleType ) } as it was neither declared nor imported!` );
}
});
2016-11-10 14:07:30 -08:00
// The providers of the module have to go last
// so that they overwrite any other provider we already added.
if ( meta . providers ) {
providers . push (... this . _getProvidersMetadata (
meta . providers , entryComponents , `provider for the NgModule ' ${ stringify ( moduleType ) } '` ));
}
if ( meta . entryComponents ) {
entryComponents . push (
... flattenAndDedupeArray ( meta . entryComponents )
. map ( type => this . _getTypeMetadata ( type , staticTypeModuleUrl ( type ))));
}
if ( meta . bootstrap ) {
const typeMetadata = flattenAndDedupeArray ( meta . bootstrap ). map ( type => {
if ( ! isValidType ( type )) {
throw new Error (
`Unexpected value ' ${ stringify ( type ) } ' used in the bootstrap property of module ' ${ stringify ( moduleType ) } '` );
}
return this . _getTypeMetadata ( type , staticTypeModuleUrl ( type ));
});
bootstrapComponents . push (... typeMetadata );
}
entryComponents . push (... bootstrapComponents );
if ( meta . schemas ) {
schemas . push (... flattenAndDedupeArray ( meta . schemas ));
}
transitiveModule . entryComponents . push (... entryComponents );
transitiveModule . providers . push (... providers );
compileMeta = new cpl . CompileNgModuleMetadata ({
type : this . _getTypeMetadata ( moduleType , staticTypeModuleUrl ( moduleType )),
providers ,
entryComponents ,
bootstrapComponents ,
schemas ,
declaredDirectives ,
exportedDirectives ,
declaredPipes ,
exportedPipes ,
importedModules ,
exportedModules ,
transitiveModule ,
id : meta.id ,
});
2016-11-10 16:27:53 -08:00
transitiveModule . modules . push ( compileMeta . toInjectorSummary ());
2016-11-10 14:07:30 -08:00
this . _ngModuleCache . set ( moduleType , compileMeta );
2016-06-28 09:54:42 -07:00
return compileMeta ;
}
2016-08-17 15:57:02 -07:00
private _getTypeDescriptor ( type : Type < any >) : string {
2016-11-10 14:07:30 -08:00
if ( this . _directiveResolver . isDirective ( type )) {
2016-08-17 15:57:02 -07:00
return 'directive' ;
}
2016-09-14 15:58:18 -07:00
2016-11-10 14:07:30 -08:00
if ( this . _pipeResolver . isPipe ( type )) {
2016-09-14 15:58:18 -07:00
return 'pipe' ;
}
2016-11-10 14:07:30 -08:00
if ( this . _ngModuleResolver . isNgModule ( type )) {
2016-09-14 15:58:18 -07:00
return 'module' ;
}
if (( type as any ). provide ) {
return 'provider' ;
}
return 'value' ;
2016-08-17 15:57:02 -07:00
}
2016-11-10 14:07:30 -08:00
2016-08-10 18:21:28 -07:00
private _addTypeToModule ( type : Type < any >, moduleType : Type < any >) {
2016-07-18 03:50:31 -07:00
const oldModule = this . _ngModuleOfTypes . get ( type );
if ( oldModule && oldModule !== moduleType ) {
2016-08-25 00:50:16 -07:00
throw new Error (
2016-09-07 14:09:25 -07:00
`Type ${ stringify ( type ) } is part of the declarations of 2 modules: ${ stringify ( oldModule ) } and ${ stringify ( moduleType ) } ! ` +
`Please consider moving ${ stringify ( type ) } to a higher module that imports ${ stringify ( oldModule ) } and ${ stringify ( moduleType ) } . ` +
`You can also create a new NgModule that exports and includes ${ stringify ( type ) } then import that NgModule in ${ stringify ( oldModule ) } and ${ stringify ( moduleType ) } .` );
2016-02-18 10:53:21 -08:00
}
2016-07-18 03:50:31 -07:00
this . _ngModuleOfTypes . set ( type , moduleType );
}
private _getTransitiveNgModuleMetadata (
2016-11-10 16:27:53 -08:00
importedModules : cpl.CompileNgModuleSummary [],
exportedModules : cpl.CompileNgModuleSummary []) : cpl . TransitiveCompileNgModuleMetadata {
2016-07-25 00:36:30 -07:00
// collect `providers` / `entryComponents` from all imported and all exported modules
2016-11-10 16:27:53 -08:00
const transitiveModules = getTransitiveImportedModules ( importedModules . concat ( exportedModules ));
2016-07-18 03:50:31 -07:00
const providers = flattenArray ( transitiveModules . map (( ngModule ) => ngModule . providers ));
2016-07-25 00:36:30 -07:00
const entryComponents =
flattenArray ( transitiveModules . map (( ngModule ) => ngModule . entryComponents ));
2016-07-18 03:50:31 -07:00
2016-11-10 16:27:53 -08:00
const transitiveExportedModules = getTransitiveExportedModules ( importedModules );
2016-07-18 03:50:31 -07:00
const directives =
flattenArray ( transitiveExportedModules . map (( ngModule ) => ngModule . exportedDirectives ));
const pipes = flattenArray ( transitiveExportedModules . map (( ngModule ) => ngModule . exportedPipes ));
2016-11-10 16:27:53 -08:00
const loadingPromises =
ListWrapper . flatten ( transitiveExportedModules . map ( ngModule => ngModule . loadingPromises ));
2016-07-18 03:50:31 -07:00
return new cpl . TransitiveCompileNgModuleMetadata (
2016-11-10 14:07:30 -08:00
transitiveModules , providers , entryComponents , directives , pipes , loadingPromises );
2016-07-18 03:50:31 -07:00
}
2016-11-10 14:07:30 -08:00
private _getIdentifierMetadata ( type : Type < any >, moduleUrl : string ) :
cpl . CompileIdentifierMetadata {
2016-06-28 09:54:42 -07:00
type = resolveForwardRef ( type );
2016-11-10 14:07:30 -08:00
return new cpl . CompileIdentifierMetadata (
{ name : this.sanitizeTokenName ( type ), moduleUrl , reference : type });
}
private _getTypeMetadata ( type : Type < any >, moduleUrl : string , dependencies : any [] = null ) :
cpl . CompileTypeMetadata {
const identifier = this . _getIdentifierMetadata ( type , moduleUrl );
2016-01-06 14:13:44 -08:00
return new cpl . CompileTypeMetadata ({
2016-11-10 14:07:30 -08:00
name : identifier.name ,
moduleUrl : identifier.moduleUrl ,
reference : identifier.reference ,
diDeps : this._getDependenciesMetadata ( identifier . reference , dependencies ),
lifecycleHooks :
LIFECYCLE_HOOKS_VALUES.filter ( hook => hasLifecycleHook ( hook , identifier . reference )),
2016-01-06 14:13:44 -08:00
});
}
2016-11-10 14:07:30 -08:00
private _getFactoryMetadata ( factory : Function , moduleUrl : string , dependencies : any [] = null ) :
2016-06-18 18:42:34 +02:00
cpl . CompileFactoryMetadata {
2016-06-28 09:54:42 -07:00
factory = resolveForwardRef ( factory );
2016-01-06 14:13:44 -08:00
return new cpl . CompileFactoryMetadata ({
2016-04-20 18:10:19 -07:00
name : this.sanitizeTokenName ( factory ),
2016-09-14 15:58:18 -07:00
moduleUrl ,
2016-08-29 08:52:25 -07:00
reference : factory ,
2016-11-10 14:07:30 -08:00
diDeps : this._getDependenciesMetadata ( factory , dependencies )
2016-01-06 14:13:44 -08:00
});
}
2016-11-10 14:07:30 -08:00
/**
* Gets the metadata for the given pipe.
* This assumes `loadNgModuleMetadata` has been called first.
*/
getPipeMetadata ( pipeType : any ) : cpl . CompilePipeMetadata {
const pipeMeta = this . _pipeCache . get ( pipeType );
if ( ! pipeMeta ) {
throw new Error (
`Illegal state: getPipeMetadata can only be called after loadNgModuleMetadata for a module that declares it. Pipe ${ stringify ( pipeType ) } .` );
2015-09-14 15:59:09 -07:00
}
2016-11-10 14:07:30 -08:00
return pipeMeta ;
2015-09-14 15:59:09 -07:00
}
2016-11-10 16:27:53 -08:00
getPipeSummary ( pipeType : any ) : cpl . CompilePipeSummary {
const pipeSummary = this . _pipeSummaryCache . get ( pipeType );
if ( ! pipeSummary ) {
throw new Error (
`Illegal state: getPipeSummary can only be called after loadNgModuleMetadata for a module that imports it. Pipe ${ stringify ( pipeType ) } .` );
}
return pipeSummary ;
}
2016-11-10 14:07:30 -08:00
private _loadPipeMetadata ( pipeType : Type < any >) : void {
pipeType = resolveForwardRef ( pipeType );
const pipeMeta = this . _pipeResolver . resolve ( pipeType );
if ( ! pipeMeta ) {
return null ;
}
const meta = new cpl . CompilePipeMetadata ({
type : this . _getTypeMetadata ( pipeType , staticTypeModuleUrl ( pipeType )),
name : pipeMeta.name ,
pure : pipeMeta.pure
});
this . _pipeCache . set ( pipeType , meta );
2016-11-10 16:27:53 -08:00
this . _pipeSummaryCache . set ( pipeType , meta . toSummary ());
2016-11-10 14:07:30 -08:00
}
private _getDependenciesMetadata ( typeOrFunc : Type < any > | Function , dependencies : any []) :
2016-06-08 16:38:52 -07:00
cpl . CompileDiDependencyMetadata [] {
2016-06-10 01:07:06 +02:00
let hasUnknownDeps = false ;
2016-11-12 14:08:58 +01:00
const params = dependencies || this . _reflector . parameters ( typeOrFunc ) || [];
2016-09-14 15:58:18 -07:00
2016-11-12 14:08:58 +01:00
const dependenciesMetadata : cpl.CompileDiDependencyMetadata [] = params . map (( param ) => {
2016-02-18 10:53:21 -08:00
let isAttribute = false ;
let isHost = false ;
let isSelf = false ;
let isSkipSelf = false ;
let isOptional = false ;
2016-10-24 13:28:23 -07:00
let token : any = null ;
2016-09-14 15:58:18 -07:00
if ( Array . isArray ( param )) {
param . forEach (( paramEntry ) => {
2016-09-12 19:14:17 -07:00
if ( paramEntry instanceof Host ) {
2016-06-08 16:38:52 -07:00
isHost = true ;
2016-09-12 19:14:17 -07:00
} else if ( paramEntry instanceof Self ) {
2016-06-08 16:38:52 -07:00
isSelf = true ;
2016-09-12 19:14:17 -07:00
} else if ( paramEntry instanceof SkipSelf ) {
2016-06-08 16:38:52 -07:00
isSkipSelf = true ;
2016-09-12 19:14:17 -07:00
} else if ( paramEntry instanceof Optional ) {
2016-06-08 16:38:52 -07:00
isOptional = true ;
2016-09-12 19:14:17 -07:00
} else if ( paramEntry instanceof Attribute ) {
2016-06-08 16:38:52 -07:00
isAttribute = true ;
token = paramEntry . attributeName ;
2016-09-12 19:14:17 -07:00
} else if ( paramEntry instanceof Inject ) {
2016-06-08 16:38:52 -07:00
token = paramEntry . token ;
} else if ( isValidType ( paramEntry ) && isBlank ( token )) {
token = paramEntry ;
}
});
2016-02-18 10:53:21 -08:00
} else {
token = param ;
}
if ( isBlank ( token )) {
2016-06-10 01:07:06 +02:00
hasUnknownDeps = true ;
2016-02-18 10:53:21 -08:00
return null ;
2016-01-06 14:13:44 -08:00
}
2016-09-14 15:58:18 -07:00
2016-01-06 14:13:44 -08:00
return new cpl . CompileDiDependencyMetadata ({
2016-09-14 15:58:18 -07:00
isAttribute ,
isHost ,
isSelf ,
isSkipSelf ,
isOptional ,
2016-11-10 14:07:30 -08:00
token : this._getTokenMetadata ( token )
2016-01-06 14:13:44 -08:00
});
2016-02-18 10:53:21 -08:00
2016-01-06 14:13:44 -08:00
});
2016-06-10 01:07:06 +02:00
if ( hasUnknownDeps ) {
2016-11-12 14:08:58 +01:00
const depsTokens =
2016-09-14 15:58:18 -07:00
dependenciesMetadata . map (( dep ) => dep ? stringify ( dep . token ) : '?' ). join ( ', ' );
2016-08-25 00:50:16 -07:00
throw new Error (
2016-06-08 16:38:52 -07:00
`Can't resolve all parameters for ${ stringify ( typeOrFunc ) } : ( ${ depsTokens } ).` );
2016-06-10 01:07:06 +02:00
}
return dependenciesMetadata ;
2016-01-06 14:13:44 -08:00
}
2016-11-10 14:07:30 -08:00
private _getTokenMetadata ( token : any ) : cpl . CompileTokenMetadata {
2016-01-06 14:13:44 -08:00
token = resolveForwardRef ( token );
2016-09-14 15:58:18 -07:00
let compileToken : cpl.CompileTokenMetadata ;
2016-10-19 13:42:39 -07:00
if ( typeof token === 'string' ) {
2016-01-06 14:13:44 -08:00
compileToken = new cpl . CompileTokenMetadata ({ value : token });
} else {
2016-04-20 18:10:19 -07:00
compileToken = new cpl . CompileTokenMetadata ({
2016-02-18 10:53:21 -08:00
identifier : new cpl . CompileIdentifierMetadata ({
2016-08-29 08:52:25 -07:00
reference : token ,
2016-02-18 10:53:21 -08:00
name : this.sanitizeTokenName ( token ),
moduleUrl : staticTypeModuleUrl ( token )
})
2016-04-20 18:10:19 -07:00
});
2016-01-06 14:13:44 -08:00
}
return compileToken ;
}
2016-11-10 14:07:30 -08:00
private _getProvidersMetadata (
providers : Provider [], targetEntryComponents : cpl.CompileIdentifierMetadata [],
2016-08-24 01:18:41 +02:00
debugInfo? : string ) : Array < cpl.CompileProviderMetadata | cpl.CompileTypeMetadata | any [] > {
2016-07-07 10:05:55 -07:00
const compileProviders : Array < cpl.CompileProviderMetadata | cpl.CompileTypeMetadata | any [] > = [];
2016-08-24 01:18:41 +02:00
providers . forEach (( provider : any , providerIdx : number ) => {
2016-01-06 14:13:44 -08:00
provider = resolveForwardRef ( provider );
2016-08-15 19:37:42 -07:00
if ( provider && typeof provider == 'object' && provider . hasOwnProperty ( 'provide' )) {
provider = new cpl . ProviderMeta ( provider . provide , provider );
2016-07-07 10:05:55 -07:00
}
let compileProvider : cpl.CompileProviderMetadata | cpl . CompileTypeMetadata | any [];
2016-09-14 15:58:18 -07:00
if ( Array . isArray ( provider )) {
2016-11-10 14:07:30 -08:00
compileProvider = this . _getProvidersMetadata ( provider , targetEntryComponents , debugInfo );
2016-08-15 19:37:42 -07:00
} else if ( provider instanceof cpl . ProviderMeta ) {
2016-11-12 14:08:58 +01:00
const tokenMeta = this . _getTokenMetadata ( provider . token );
2016-08-29 08:52:25 -07:00
if ( tokenMeta . reference ===
resolveIdentifierToken ( Identifiers . ANALYZE_FOR_ENTRY_COMPONENTS ). reference ) {
2016-07-25 00:36:30 -07:00
targetEntryComponents . push (... this . _getEntryComponentsFromProvider ( provider ));
2016-07-07 10:05:55 -07:00
} else {
compileProvider = this . getProviderMetadata ( provider );
}
2016-06-28 09:54:42 -07:00
} else if ( isValidType ( provider )) {
2016-11-10 14:07:30 -08:00
compileProvider = this . _getTypeMetadata ( provider , staticTypeModuleUrl ( provider ));
2016-06-28 09:54:42 -07:00
} else {
2016-10-24 13:28:23 -07:00
const 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-08-24 01:18:41 +02:00
2016-08-25 00:50:16 -07:00
throw new Error (
2016-08-24 01:18:41 +02:00
`Invalid ${ debugInfo ? debugInfo : 'provider' } - only instances of Provider and Type are allowed, got: [ ${ providersInfo } ]` );
2016-01-06 14:13:44 -08:00
}
2016-07-07 10:05:55 -07:00
if ( compileProvider ) {
compileProviders . push ( compileProvider );
}
2016-01-06 14:13:44 -08:00
});
2016-07-07 10:05:55 -07:00
return compileProviders ;
}
2016-11-10 14:07:30 -08:00
private _getEntryComponentsFromProvider ( provider : cpl.ProviderMeta ) :
cpl . CompileIdentifierMetadata [] {
const components : cpl.CompileIdentifierMetadata [] = [];
2016-09-14 15:58:18 -07:00
const collectedIdentifiers : cpl.CompileIdentifierMetadata [] = [];
2016-07-07 10:05:55 -07:00
if ( provider . useFactory || provider . useExisting || provider . useClass ) {
2016-08-25 00:50:16 -07:00
throw new Error ( `The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!` );
2016-07-07 10:05:55 -07:00
}
2016-09-14 15:58:18 -07:00
2016-07-07 10:05:55 -07:00
if ( ! provider . multi ) {
2016-08-25 00:50:16 -07:00
throw new Error ( `The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!` );
2016-07-07 10:05:55 -07:00
}
2016-09-14 15:58:18 -07:00
2016-07-07 10:05:55 -07:00
convertToCompileValue ( provider . useValue , collectedIdentifiers );
collectedIdentifiers . forEach (( identifier ) => {
2016-11-10 14:07:30 -08:00
if ( this . _directiveResolver . isDirective ( identifier . reference )) {
components . push ( identifier );
2016-07-07 10:05:55 -07:00
}
});
return components ;
2016-01-06 14:13:44 -08:00
}
2016-08-15 19:37:42 -07:00
getProviderMetadata ( provider : cpl.ProviderMeta ) : cpl . CompileProviderMetadata {
2016-09-14 15:58:18 -07:00
let compileDeps : cpl.CompileDiDependencyMetadata [];
let compileTypeMetadata : cpl.CompileTypeMetadata = null ;
let compileFactoryMetadata : cpl.CompileFactoryMetadata = null ;
2016-06-18 18:42:34 +02:00
2016-09-14 15:58:18 -07:00
if ( provider . useClass ) {
2016-11-10 14:07:30 -08:00
compileTypeMetadata = this . _getTypeMetadata (
2016-06-18 18:42:34 +02:00
provider . useClass , staticTypeModuleUrl ( provider . useClass ), provider . dependencies );
compileDeps = compileTypeMetadata . diDeps ;
2016-09-14 15:58:18 -07:00
} else if ( provider . useFactory ) {
2016-11-10 14:07:30 -08:00
compileFactoryMetadata = this . _getFactoryMetadata (
2016-06-18 18:42:34 +02:00
provider . useFactory , staticTypeModuleUrl ( provider . useFactory ), provider . dependencies );
compileDeps = compileFactoryMetadata . diDeps ;
2016-01-06 14:13:44 -08:00
}
2016-06-18 18:42:34 +02:00
2016-01-06 14:13:44 -08:00
return new cpl . CompileProviderMetadata ({
2016-11-10 14:07:30 -08:00
token : this._getTokenMetadata ( provider . token ),
2016-06-18 18:42:34 +02:00
useClass : compileTypeMetadata ,
2016-07-07 10:05:55 -07:00
useValue : convertToCompileValue ( provider . useValue , []),
2016-06-18 18:42:34 +02:00
useFactory : compileFactoryMetadata ,
2016-11-10 14:07:30 -08:00
useExisting : provider.useExisting ? this . _getTokenMetadata ( provider . useExisting ) : null ,
2016-01-06 14:13:44 -08:00
deps : compileDeps ,
multi : provider.multi
});
}
2016-11-10 14:07:30 -08:00
private _getQueriesMetadata (
2016-09-12 19:14:17 -07:00
queries : {[ key : string ] : Query }, isViewQuery : boolean ,
2016-08-10 18:21:28 -07:00
directiveType : Type < any >) : cpl . CompileQueryMetadata [] {
2016-09-14 15:58:18 -07:00
const res : cpl.CompileQueryMetadata [] = [];
Object . keys ( queries ). forEach (( propertyName : string ) => {
const query = queries [ propertyName ];
2016-06-22 17:25:42 -07:00
if ( query . isViewQuery === isViewQuery ) {
2016-11-10 14:07:30 -08:00
res . push ( this . _getQueryMetadata ( query , propertyName , directiveType ));
2016-06-22 17:25:42 -07:00
}
});
2016-09-14 15:58:18 -07:00
2016-06-22 17:25:42 -07:00
return res ;
2016-01-06 14:13:44 -08:00
}
2016-09-14 15:58:18 -07:00
private _queryVarBindings ( selector : any ) : string [] { return selector . split ( /\s*,\s*/ ); }
2016-09-12 09:44:20 -07:00
2016-11-10 14:07:30 -08:00
private _getQueryMetadata ( q : Query , propertyName : string , typeOrFunc : Type < any > | Function ) :
2016-06-08 16:38:52 -07:00
cpl . CompileQueryMetadata {
2016-11-12 14:08:58 +01:00
let selectors : cpl.CompileTokenMetadata [];
2016-09-14 15:58:18 -07:00
if ( typeof q . selector === 'string' ) {
2016-11-10 14:07:30 -08:00
selectors =
this . _queryVarBindings ( q . selector ). map ( varName => this . _getTokenMetadata ( varName ));
2016-01-06 14:13:44 -08:00
} else {
2016-09-14 15:58:18 -07:00
if ( ! q . selector ) {
2016-08-25 00:50:16 -07:00
throw new Error (
2016-06-08 16:38:52 -07:00
`Can't construct a query for the property " ${ propertyName } " of " ${ stringify ( typeOrFunc ) } " since the query selector wasn't defined.` );
2016-06-05 04:46:03 +02:00
}
2016-11-10 14:07:30 -08:00
selectors = [ this . _getTokenMetadata ( q . selector )];
2016-01-06 14:13:44 -08:00
}
2016-09-14 15:58:18 -07:00
2016-01-06 14:13:44 -08:00
return new cpl . CompileQueryMetadata ({
2016-09-14 15:58:18 -07:00
selectors ,
2016-01-06 14:13:44 -08:00
first : q.first ,
2016-09-14 15:58:18 -07:00
descendants : q.descendants , propertyName ,
2016-11-10 14:07:30 -08:00
read : q.read ? this . _getTokenMetadata ( q . read ) : null
2016-01-06 14:13:44 -08:00
});
}
2015-09-14 15:59:09 -07:00
}
2016-11-10 16:27:53 -08:00
function getTransitiveExportedModules (
modules : cpl.CompileNgModuleDirectiveSummary [],
targetModules : cpl.CompileNgModuleDirectiveSummary [] = [],
visitedModules = new Set < Type < any >>()) : cpl . CompileNgModuleDirectiveSummary [] {
2016-07-18 03:50:31 -07:00
modules . forEach (( ngModule ) => {
2016-08-29 08:52:25 -07:00
if ( ! visitedModules . has ( ngModule . type . reference )) {
visitedModules . add ( ngModule . type . reference );
2016-11-10 16:27:53 -08:00
getTransitiveExportedModules ( ngModule . exportedModules , 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 getTransitiveImportedModules (
modules : cpl.CompileNgModuleInjectorSummary [],
targetModules : cpl.CompileNgModuleInjectorSummary [] = [],
visitedModules = new Set < Type < any >>()) : cpl . CompileNgModuleInjectorSummary [] {
modules . forEach (( ngModule ) => {
if ( ! visitedModules . has ( ngModule . type . reference )) {
visitedModules . add ( ngModule . type . reference );
const nestedModules = ngModule . importedModules . concat ( ngModule . exportedModules );
getTransitiveImportedModules ( nestedModules , targetModules , visitedModules );
2016-07-18 03:50:31 -07:00
// 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 15:59:09 -07:00
}
2016-07-18 03:50:31 -07:00
function flattenArray ( tree : any [], out : Array < any > = []) : Array < any > {
if ( tree ) {
2016-09-14 15:58:18 -07:00
for ( let i = 0 ; i < tree . length ; i ++ ) {
const item = resolveForwardRef ( tree [ i ]);
if ( Array . isArray ( item )) {
2016-07-18 03:50:31 -07:00
flattenArray ( item , out );
} else {
out . push ( item );
}
2015-09-14 15:59:09 -07:00
}
}
2016-06-22 14:06:23 -07:00
return out ;
2015-09-14 15:59:09 -07:00
}
2016-10-28 14:08:54 -07:00
function dedupeArray ( array : any []) : Array < any > {
if ( array ) {
return Array . from ( new Set ( array ));
}
return [];
}
function flattenAndDedupeArray ( tree : any []) : Array < any > {
return dedupeArray ( flattenArray ( tree ));
}
2016-02-18 10:53:21 -08:00
function isValidType ( value : any ) : boolean {
2016-06-28 09:54:42 -07:00
return cpl . isStaticSymbol ( value ) || ( value instanceof Type );
2016-02-18 10:53:21 -08:00
}
function staticTypeModuleUrl ( value : any ) : string {
2016-06-28 09:54:42 -07:00
return cpl . isStaticSymbol ( value ) ? value.filePath : null ;
2015-09-14 15:59:09 -07:00
}
2016-09-14 16:49:13 -07:00
function componentModuleUrl (
reflector : ReflectorReader , type : Type < any >, cmpMetadata : Component ) : string {
2016-06-28 09:54:42 -07:00
if ( cpl . isStaticSymbol ( type )) {
2016-05-02 09:38:46 -07:00
return staticTypeModuleUrl ( type );
2016-04-28 21:54:02 -07:00
}
2016-09-14 16:49:13 -07:00
const moduleId = cmpMetadata . moduleId ;
if ( typeof moduleId === 'string' ) {
2016-09-14 15:58:18 -07:00
const scheme = getUrlScheme ( moduleId );
return scheme ? moduleId : `package: ${ moduleId }${ MODULE_SUFFIX } ` ;
2016-09-14 16:49:13 -07:00
} else if ( moduleId !== null && moduleId !== void 0 ) {
throw new Error (
`moduleId should be a string in " ${ stringify ( type ) } ". See https://goo.gl/wIDDiL for more information. \ n` +
`If you're using Webpack you should inline the template and the styles, see https://goo.gl/X2J8zc.` );
2015-09-14 15:59:09 -07:00
}
2016-04-28 21:54:02 -07:00
return reflector . importUri ( type );
2015-09-14 15:59:09 -07:00
}
2016-04-30 16:13:03 -07:00
2016-07-07 10:05:55 -07:00
function convertToCompileValue (
value : any , targetIdentifiers : cpl.CompileIdentifierMetadata []) : any {
return visitValue ( value , new _CompileValueConverter (), targetIdentifiers );
2016-04-30 16:13:03 -07:00
}
class _CompileValueConverter extends ValueTransformer {
2016-07-07 10:05:55 -07:00
visitOther ( value : any , targetIdentifiers : cpl.CompileIdentifierMetadata []) : any {
let identifier : cpl.CompileIdentifierMetadata ;
2016-06-28 09:54:42 -07:00
if ( cpl . isStaticSymbol ( value )) {
2016-07-07 10:05:55 -07:00
identifier = new cpl . CompileIdentifierMetadata (
2016-08-29 08:52:25 -07:00
{ name : value.name , moduleUrl : value.filePath , reference : value });
2016-04-30 16:13:03 -07:00
} else {
2016-08-29 08:52:25 -07:00
identifier = new cpl . CompileIdentifierMetadata ({ reference : value });
2016-04-30 16:13:03 -07:00
}
2016-07-07 10:05:55 -07:00
targetIdentifiers . push ( identifier );
return identifier ;
2016-04-30 16:13:03 -07:00
}
}