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
*/
2017-01-03 16:54:46 -08:00
import { AnimationAnimateMetadata , AnimationEntryMetadata , AnimationGroupMetadata , AnimationKeyframesSequenceMetadata , AnimationMetadata , AnimationStateDeclarationMetadata , AnimationStateMetadata , AnimationStateTransitionMetadata , AnimationStyleMetadata , AnimationWithStepsMetadata , Attribute , ChangeDetectionStrategy , Component , ComponentFactory , Directive , Host , Inject , Injectable , InjectionToken , ModuleWithProviders , Optional , Provider , Query , SchemaMetadata , Self , SkipSelf , Type , resolveForwardRef } from '@angular/core' ;
2016-06-08 16:38:52 -07:00
2016-12-27 09:36:47 -08:00
import { StaticSymbol , StaticSymbolCache } from './aot/static_symbol' ;
import { ngfactoryFilePath } from './aot/util' ;
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' ;
2017-02-02 15:01:35 -08:00
import { USE_VIEW_ENGINE } from './config' ;
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-12-28 01:02:28 +03:00
import { stringify } from './facade/lang' ;
import { Identifiers , resolveIdentifier } from './identifiers' ;
2016-12-15 09:12:40 -08:00
import { CompilerInjectable } from './injectable' ;
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' ;
2017-02-02 15:01:35 -08:00
import { ERROR_COMPONENT_TYPE , LIFECYCLE_HOOKS_VALUES , ReflectorReader , reflector , viewEngine } from './private_import_core' ;
2016-07-28 19:39:10 +02:00
import { ElementSchemaRegistry } from './schema/element_schema_registry' ;
2016-11-29 15:36:33 -08:00
import { SummaryResolver } from './summary_resolver' ;
2016-04-28 17:50:03 -07:00
import { getUrlScheme } from './url_resolver' ;
2017-01-27 13:19:00 -08:00
import { MODULE_SUFFIX , ValueTransformer , syntaxError , visitValue } from './util' ;
2016-04-28 17:50:03 -07:00
2016-12-06 17:11:09 -08:00
export type ErrorCollector = ( error : any , type ?: any ) => void ;
2017-01-03 16:54:46 -08:00
export const ERROR_COLLECTOR_TOKEN = new InjectionToken ( 'ErrorCollector' );
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.
2016-12-15 09:12:40 -08:00
@CompilerInjectable ()
2016-02-18 10:53:21 -08:00
export class CompileMetadataResolver {
2016-12-27 09:36:47 -08:00
private _nonNormalizedDirectiveCache =
new Map < Type < any >, { annotation : Directive , metadata : cpl.CompileDirectiveMetadata }>();
2016-08-10 18:21:28 -07:00
private _directiveCache = new Map < Type < any >, cpl.CompileDirectiveMetadata >();
2016-12-02 10:08:46 -08:00
private _summaryCache = new Map < Type < any >, cpl.CompileTypeSummary >();
2016-08-10 18:21:28 -07:00
private _pipeCache = new Map < Type < any >, cpl.CompilePipeMetadata >();
private _ngModuleCache = new Map < Type < any >, cpl.CompileNgModuleMetadata >();
private _ngModuleOfTypes = new Map < Type < any >, Type < any >>();
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-12-15 09:12:40 -08:00
private _pipeResolver : PipeResolver , private _summaryResolver : SummaryResolver < any >,
2016-11-29 15:36:33 -08:00
private _schemaRegistry : ElementSchemaRegistry ,
2016-11-10 14:07:30 -08:00
private _directiveNormalizer : DirectiveNormalizer ,
2016-12-27 09:36:47 -08:00
@Optional () private _staticSymbolCache : StaticSymbolCache ,
2016-12-06 17:11:09 -08:00
private _reflector : ReflectorReader = reflector ,
2017-02-02 15:01:35 -08:00
@Optional () @Inject ( ERROR_COLLECTOR_TOKEN ) private _errorCollector? : ErrorCollector ,
@Optional () @Inject ( USE_VIEW_ENGINE ) private _useViewEngine? : boolean ) {}
2015-09-14 15:59:09 -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-12-27 09:36:47 -08:00
this . _nonNormalizedDirectiveCache . delete ( type );
2016-12-02 10:08:46 -08:00
this . _summaryCache . delete ( type );
2016-06-28 09:54:42 -07:00
this . _pipeCache . 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
}
2016-12-28 01:02:28 +03:00
clearCache () : void {
2016-06-24 08:46:43 -07:00
this . _directiveCache . clear ();
2016-12-27 09:36:47 -08:00
this . _nonNormalizedDirectiveCache . clear ();
2016-12-02 10:08:46 -08:00
this . _summaryCache . clear ();
2016-06-24 08:46:43 -07:00
this . _pipeCache . 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-12-27 09:36:47 -08:00
private _createProxyClass ( baseType : any , name : string ) : cpl . ProxyClass {
let delegate : any = null ;
const proxyClass : cpl.ProxyClass = < any > function () {
if ( ! delegate ) {
throw new Error (
`Illegal state: Class ${ name } for type ${ stringify ( baseType ) } is not compiled yet!` );
}
return delegate . apply ( this , arguments );
};
proxyClass . setDelegate = ( d ) => {
delegate = d ;
(< any > proxyClass ). prototype = d . prototype ;
};
// Make stringify work correctly
(< any > proxyClass ). overriddenName = name ;
return proxyClass ;
}
private getGeneratedClass ( dirType : any , name : string ) : StaticSymbol | cpl . ProxyClass {
if ( dirType instanceof StaticSymbol ) {
return this . _staticSymbolCache . get ( ngfactoryFilePath ( dirType . filePath ), name );
} else {
return this . _createProxyClass ( dirType , name );
}
}
private getDirectiveWrapperClass ( dirType : any ) : StaticSymbol | cpl . ProxyClass {
return this . getGeneratedClass ( dirType , cpl . dirWrapperClassName ( dirType ));
}
private getComponentViewClass ( dirType : any ) : StaticSymbol | cpl . ProxyClass {
return this . getGeneratedClass ( dirType , cpl . viewClassName ( dirType , 0 ));
}
getHostComponentViewClass ( dirType : any ) : StaticSymbol | cpl . ProxyClass {
return this . getGeneratedClass ( dirType , cpl . hostViewClassName ( dirType ));
}
getHostComponentType ( dirType : any ) : StaticSymbol | Type < any > {
const name = ` ${ cpl . identifierName ({ reference : dirType } )}_Host` ;
if ( dirType instanceof StaticSymbol ) {
return this . _staticSymbolCache . get ( dirType . filePath , name );
} else {
const HostClass = < any > function HostClass() { };
HostClass . overriddenName = name ;
return HostClass ;
}
}
private getComponentFactory ( selector : string , dirType : any ) : StaticSymbol | ComponentFactory < any > {
if ( dirType instanceof StaticSymbol ) {
return this . _staticSymbolCache . get (
ngfactoryFilePath ( dirType . filePath ), cpl . componentFactoryName ( dirType ));
} else {
const hostView = this . getHostComponentViewClass ( dirType );
2017-02-02 15:01:35 -08:00
if ( this . _useViewEngine ) {
return viewEngine . createComponentFactory ( selector , dirType , < any > hostView );
} else {
return new ComponentFactory ( selector , < any > hostView , dirType );
}
2016-12-27 09:36:47 -08: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-12-02 10:08:46 -08:00
private _loadSummary ( type : any , kind : cpl.CompileSummaryKind ) : cpl . CompileTypeSummary {
2016-12-15 09:12:40 -08:00
let typeSummary = this . _summaryCache . get ( type );
if ( ! typeSummary ) {
const summary = this . _summaryResolver . resolveSummary ( type );
typeSummary = summary ? summary.type : null ;
this . _summaryCache . set ( type , typeSummary );
2016-12-02 10:08:46 -08:00
}
2016-12-15 09:12:40 -08:00
return typeSummary && typeSummary . summaryKind === kind ? typeSummary : null ;
2016-12-02 10:08:46 -08:00
}
2016-11-29 15:36:33 -08:00
private _loadDirectiveMetadata ( directiveType : any , isSync : boolean ) : Promise < any > {
2016-11-10 14:07:30 -08:00
if ( this . _directiveCache . has ( directiveType )) {
return ;
}
2016-06-28 09:54:42 -07:00
directiveType = resolveForwardRef ( directiveType );
2016-11-23 09:42:19 -08:00
const { annotation , metadata } = this . getNonNormalizedDirectiveMetadata ( directiveType );
2016-11-10 14:07:30 -08:00
2016-11-16 10:22:11 -08:00
const createDirectiveMetadata = ( templateMetadata : cpl.CompileTemplateMetadata ) => {
const normalizedDirMeta = new cpl . CompileDirectiveMetadata ({
2016-11-23 09:42:19 -08:00
type : metadata . type ,
isComponent : metadata.isComponent ,
selector : metadata.selector ,
exportAs : metadata.exportAs ,
changeDetection : metadata.changeDetection ,
inputs : metadata.inputs ,
outputs : metadata.outputs ,
hostListeners : metadata.hostListeners ,
hostProperties : metadata.hostProperties ,
hostAttributes : metadata.hostAttributes ,
providers : metadata.providers ,
viewProviders : metadata.viewProviders ,
queries : metadata.queries ,
viewQueries : metadata.viewQueries ,
entryComponents : metadata.entryComponents ,
2016-12-27 09:36:47 -08:00
wrapperType : metadata.wrapperType ,
componentViewType : metadata.componentViewType ,
componentFactory : metadata.componentFactory ,
2016-11-16 10:22:11 -08:00
template : templateMetadata
2015-09-14 15:59:09 -07:00
});
2016-11-16 10:22:11 -08:00
this . _directiveCache . set ( directiveType , normalizedDirMeta );
2016-12-02 10:08:46 -08:00
this . _summaryCache . set ( directiveType , normalizedDirMeta . toSummary ());
2016-11-16 10:22:11 -08:00
return normalizedDirMeta ;
2016-11-10 14:07:30 -08:00
};
2016-11-23 09:42:19 -08:00
if ( metadata . isComponent ) {
2016-11-10 14:07:30 -08:00
const templateMeta = this . _directiveNormalizer . normalizeTemplate ({
componentType : directiveType ,
2016-11-23 09:42:19 -08:00
moduleUrl : componentModuleUrl ( this . _reflector , directiveType , annotation ),
encapsulation : metadata.template.encapsulation ,
template : metadata.template.template ,
templateUrl : metadata.template.templateUrl ,
styles : metadata.template.styles ,
styleUrls : metadata.template.styleUrls ,
animations : metadata.template.animations ,
interpolation : metadata.template.interpolation
2016-11-10 14:07:30 -08:00
});
if ( templateMeta . syncResult ) {
createDirectiveMetadata ( templateMeta . syncResult );
return null ;
} else {
if ( isSync ) {
2017-01-27 13:19:00 -08:00
this . _reportError ( componentStillLoadingError ( directiveType ), directiveType );
2016-12-06 17:11:09 -08:00
return null ;
2016-11-10 14:07:30 -08:00
}
2016-11-29 15:36:33 -08:00
return templateMeta . asyncResult . then ( createDirectiveMetadata );
2016-11-10 14:07:30 -08:00
}
} else {
// directive
createDirectiveMetadata ( null );
return null ;
2015-12-02 10:35:51 -08:00
}
}
2016-11-23 09:42:19 -08:00
getNonNormalizedDirectiveMetadata ( directiveType : any ) :
{ annotation : Directive , metadata : cpl.CompileDirectiveMetadata } {
2016-11-16 10:22:11 -08:00
directiveType = resolveForwardRef ( directiveType );
2016-12-27 09:36:47 -08:00
if ( ! directiveType ) {
return null ;
}
let cacheEntry = this . _nonNormalizedDirectiveCache . get ( directiveType );
if ( cacheEntry ) {
return cacheEntry ;
}
const dirMeta = this . _directiveResolver . resolve ( directiveType , false );
2016-11-16 10:22:11 -08:00
if ( ! dirMeta ) {
return null ;
}
let nonNormalizedTemplateMetadata : cpl.CompileTemplateMetadata ;
if ( dirMeta instanceof Component ) {
// component
assertArrayOfStrings ( 'styles' , dirMeta . styles );
assertArrayOfStrings ( 'styleUrls' , dirMeta . styleUrls );
assertInterpolationSymbols ( 'interpolation' , dirMeta . interpolation );
const animations = dirMeta . animations ?
dirMeta . animations . map ( e => this . getAnimationEntryMetadata ( e )) :
null ;
nonNormalizedTemplateMetadata = new cpl . CompileTemplateMetadata ({
encapsulation : dirMeta.encapsulation ,
template : dirMeta.template ,
templateUrl : dirMeta.templateUrl ,
styles : dirMeta.styles ,
styleUrls : dirMeta.styleUrls ,
animations : animations ,
interpolation : dirMeta.interpolation
});
}
let changeDetectionStrategy : ChangeDetectionStrategy = null ;
2016-11-30 10:52:51 -08:00
let viewProviders : cpl.CompileProviderMetadata [] = [];
2016-12-27 09:36:47 -08:00
let entryComponentMetadata : cpl.CompileEntryComponentMetadata [] = [];
2016-11-16 10:22:11 -08:00
let selector = dirMeta . selector ;
if ( dirMeta instanceof Component ) {
// Component
changeDetectionStrategy = dirMeta . changeDetection ;
if ( dirMeta . viewProviders ) {
viewProviders = this . _getProvidersMetadata (
dirMeta . viewProviders , entryComponentMetadata ,
2016-12-15 09:12:40 -08:00
`viewProviders for " ${ stringifyType ( directiveType ) } "` , [], directiveType );
2016-11-16 10:22:11 -08:00
}
if ( dirMeta . entryComponents ) {
2016-11-23 09:42:19 -08:00
entryComponentMetadata = flattenAndDedupeArray ( dirMeta . entryComponents )
2016-12-27 09:36:47 -08:00
. map (( type ) => this . _getEntryComponentMetadata ( type ))
2016-11-23 09:42:19 -08:00
. concat ( entryComponentMetadata );
2016-11-16 10:22:11 -08:00
}
if ( ! selector ) {
selector = this . _schemaRegistry . getDefaultComponentElementName ();
}
} else {
// Directive
if ( ! selector ) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 13:54:38 -08:00
`Directive ${ stringifyType ( directiveType ) } has no selector, please add it!` ),
2016-12-06 17:11:09 -08:00
directiveType );
selector = 'error' ;
2016-11-16 10:22:11 -08:00
}
}
2016-11-30 10:52:51 -08:00
let providers : cpl.CompileProviderMetadata [] = [];
2016-12-28 01:02:28 +03:00
if ( dirMeta . providers != null ) {
2016-11-16 10:22:11 -08:00
providers = this . _getProvidersMetadata (
2016-12-15 09:12:40 -08:00
dirMeta . providers , entryComponentMetadata ,
`providers for " ${ stringifyType ( directiveType ) } "` , [], directiveType );
2016-11-16 10:22:11 -08:00
}
let queries : cpl.CompileQueryMetadata [] = [];
let viewQueries : cpl.CompileQueryMetadata [] = [];
2016-12-28 01:02:28 +03:00
if ( dirMeta . queries != null ) {
2016-11-16 10:22:11 -08:00
queries = this . _getQueriesMetadata ( dirMeta . queries , false , directiveType );
viewQueries = this . _getQueriesMetadata ( dirMeta . queries , true , directiveType );
}
2016-11-23 09:42:19 -08:00
const metadata = cpl . CompileDirectiveMetadata . create ({
2016-11-16 10:22:11 -08:00
selector : selector ,
exportAs : dirMeta.exportAs ,
isComponent : !! nonNormalizedTemplateMetadata ,
2016-11-23 09:42:19 -08:00
type : this . _getTypeMetadata ( directiveType ),
2016-11-16 10:22:11 -08:00
template : nonNormalizedTemplateMetadata ,
changeDetection : changeDetectionStrategy ,
inputs : dirMeta.inputs ,
outputs : dirMeta.outputs ,
host : dirMeta.host ,
providers : providers ,
viewProviders : viewProviders ,
queries : queries ,
viewQueries : viewQueries ,
2016-12-27 09:36:47 -08:00
entryComponents : entryComponentMetadata ,
wrapperType : this.getDirectiveWrapperClass ( directiveType ),
componentViewType : nonNormalizedTemplateMetadata ? this . getComponentViewClass ( directiveType ) :
undefined ,
componentFactory : nonNormalizedTemplateMetadata ?
this . getComponentFactory ( selector , directiveType ) :
undefined
2016-11-16 10:22:11 -08:00
});
2016-12-27 09:36:47 -08:00
cacheEntry = { metadata , annotation : dirMeta };
this . _nonNormalizedDirectiveCache . set ( directiveType , cacheEntry );
return cacheEntry ;
2016-11-16 10:22:11 -08:00
}
2016-11-10 14:07:30 -08:00
/**
* Gets the metadata for the given directive.
2017-02-05 14:22:06 -08:00
* This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
2016-11-10 14:07:30 -08:00
*/
getDirectiveMetadata ( directiveType : any ) : cpl . CompileDirectiveMetadata {
const dirMeta = this . _directiveCache . get ( directiveType );
if ( ! dirMeta ) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2017-02-05 14:22:06 -08:00
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${ stringifyType ( directiveType ) } .` ),
2016-12-06 17:11:09 -08:00
directiveType );
2016-11-10 14:07:30 -08:00
}
return dirMeta ;
}
2016-11-10 16:27:53 -08:00
getDirectiveSummary ( dirType : any ) : cpl . CompileDirectiveSummary {
2016-12-02 10:08:46 -08:00
const dirSummary =
< cpl.CompileDirectiveSummary > this . _loadSummary ( dirType , cpl . CompileSummaryKind . Directive );
2016-11-10 16:27:53 -08:00
if ( ! dirSummary ) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Illegal state: Could not load the summary for directive ${ stringifyType ( dirType ) } .` ),
2016-12-06 17:11:09 -08:00
dirType );
2016-11-10 16:27:53 -08:00
}
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 ); }
2016-11-29 15:36:33 -08:00
getNgModuleSummary ( moduleType : any ) : cpl . CompileNgModuleSummary {
2016-12-02 10:08:46 -08:00
let moduleSummary =
< cpl.CompileNgModuleSummary > this . _loadSummary ( moduleType , cpl . CompileSummaryKind . NgModule );
2016-11-29 15:36:33 -08:00
if ( ! moduleSummary ) {
2016-12-02 10:08:46 -08:00
const moduleMeta = this . getNgModuleMetadata ( moduleType , false );
moduleSummary = moduleMeta ? moduleMeta . toSummary () : null ;
2016-11-29 15:36:33 -08:00
if ( moduleSummary ) {
2016-12-02 10:08:46 -08:00
this . _summaryCache . set ( moduleType , moduleSummary );
2016-11-29 15:36:33 -08:00
}
}
return moduleSummary ;
2016-11-10 16:27:53 -08:00
}
2016-11-10 14:07:30 -08:00
/**
2016-11-29 15:36:33 -08:00
* Loads the declared directives and pipes of an NgModule.
2016-11-10 14:07:30 -08:00
*/
2016-11-29 08:08:22 -08:00
loadNgModuleDirectiveAndPipeMetadata ( moduleType : any , isSync : boolean , throwIfNotFound = true ) :
2016-11-29 15:36:33 -08:00
Promise < any > {
2016-11-29 08:08:22 -08:00
const ngModule = this . getNgModuleMetadata ( moduleType , throwIfNotFound );
2016-11-29 15:36:33 -08:00
const loading : Promise < any >[] = [];
2016-11-29 08:08:22 -08:00
if ( ngModule ) {
2016-11-29 15:36:33 -08:00
ngModule . declaredDirectives . forEach (( id ) => {
const promise = this . _loadDirectiveMetadata ( id . reference , isSync );
if ( promise ) {
loading . push ( promise );
}
});
ngModule . declaredPipes . forEach (( id ) => this . _loadPipeMetadata ( id . reference ));
2016-11-29 08:08:22 -08:00
}
2016-11-29 15:36:33 -08:00
return Promise . all ( loading );
2016-11-10 14:07:30 -08:00
}
2016-11-29 08:08:22 -08:00
getNgModuleMetadata ( moduleType : any , 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-29 08:08:22 -08:00
const providers : cpl.CompileProviderMetadata [] = [];
2016-12-27 09:36:47 -08:00
const entryComponents : cpl.CompileEntryComponentMetadata [] = [];
2016-11-10 14:07:30 -08:00
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 ,
2016-12-15 09:12:40 -08:00
`provider for the NgModule ' ${ stringifyType ( importedModuleType ) } '` , [],
importedType ));
2016-11-10 14:07:30 -08:00
}
}
if ( importedModuleType ) {
2016-11-29 15:36:33 -08:00
const importedModuleSummary = this . getNgModuleSummary ( importedModuleType );
2016-11-10 16:27:53 -08:00
if ( ! importedModuleSummary ) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Unexpected ${ this . _getTypeDescriptor ( importedType ) } ' ${ stringifyType ( importedType ) } ' imported by the module ' ${ stringifyType ( moduleType ) } '` ),
2016-12-06 17:11:09 -08:00
moduleType );
return ;
2016-11-10 14:07:30 -08:00
}
2016-11-10 16:27:53 -08:00
importedModules . push ( importedModuleSummary );
2016-11-10 14:07:30 -08:00
} else {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Unexpected value ' ${ stringifyType ( importedType ) } ' imported by the module ' ${ stringifyType ( moduleType ) } '` ),
2016-12-06 17:11:09 -08:00
moduleType );
return ;
2016-11-10 14:07:30 -08:00
}
});
}
if ( meta . exports ) {
flattenAndDedupeArray ( meta . exports ). forEach (( exportedType ) => {
if ( ! isValidType ( exportedType )) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Unexpected value ' ${ stringifyType ( exportedType ) } ' exported by the module ' ${ stringifyType ( moduleType ) } '` ),
2016-12-06 17:11:09 -08:00
moduleType );
return ;
2016-11-10 14:07:30 -08:00
}
2016-11-29 15:36:33 -08:00
const exportedModuleSummary = this . getNgModuleSummary ( exportedType );
2016-11-10 16:27:53 -08:00
if ( exportedModuleSummary ) {
exportedModules . push ( exportedModuleSummary );
2016-11-10 14:07:30 -08:00
} else {
2016-11-23 09:42:19 -08:00
exportedNonModuleIdentifiers . push ( this . _getIdentifierMetadata ( 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 )) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Unexpected value ' ${ stringifyType ( declaredType ) } ' declared by the module ' ${ stringifyType ( moduleType ) } '` ),
2016-12-06 17:11:09 -08:00
moduleType );
return ;
2016-11-10 14:07:30 -08:00
}
2016-11-23 09:42:19 -08:00
const declaredIdentifier = this . _getIdentifierMetadata ( declaredType );
2016-11-10 14:07:30 -08:00
if ( this . _directiveResolver . isDirective ( declaredType )) {
2016-12-02 10:08:46 -08:00
transitiveModule . addDirective ( declaredIdentifier );
2016-11-10 14:07:30 -08:00
declaredDirectives . push ( declaredIdentifier );
this . _addTypeToModule ( declaredType , moduleType );
} else if ( this . _pipeResolver . isPipe ( declaredType )) {
2016-12-02 10:08:46 -08:00
transitiveModule . addPipe ( declaredIdentifier );
2016-11-10 14:07:30 -08:00
transitiveModule . pipes . push ( declaredIdentifier );
declaredPipes . push ( declaredIdentifier );
this . _addTypeToModule ( declaredType , moduleType );
} else {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Unexpected ${ this . _getTypeDescriptor ( declaredType ) } ' ${ stringifyType ( declaredType ) } ' declared by the module ' ${ stringifyType ( moduleType ) } '` ),
2016-12-06 17:11:09 -08:00
moduleType );
return ;
2016-11-10 14:07:30 -08:00
}
});
}
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 );
2016-12-02 10:08:46 -08:00
transitiveModule . addExportedDirective ( exportedId );
2016-11-10 16:27:53 -08:00
} else if ( transitiveModule . pipesSet . has ( exportedId . reference )) {
exportedPipes . push ( exportedId );
2016-12-02 10:08:46 -08:00
transitiveModule . addExportedPipe ( exportedId );
2016-11-10 16:27:53 -08:00
} else {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Can't export ${ this . _getTypeDescriptor ( exportedId . reference ) } ${ stringifyType ( exportedId . reference ) } from ${ stringifyType ( moduleType ) } as it was neither declared nor imported!` ),
2016-12-06 17:11:09 -08:00
moduleType );
2016-11-10 16:27:53 -08:00
}
});
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 (
2016-12-15 09:12:40 -08:00
meta . providers , entryComponents ,
`provider for the NgModule ' ${ stringifyType ( moduleType ) } '` , [], moduleType ));
2016-11-10 14:07:30 -08:00
}
if ( meta . entryComponents ) {
2016-12-15 09:12:40 -08:00
entryComponents . push (... flattenAndDedupeArray ( meta . entryComponents )
2016-12-27 09:36:47 -08:00
. map ( type => this . _getEntryComponentMetadata ( type )));
2016-11-10 14:07:30 -08:00
}
if ( meta . bootstrap ) {
2016-12-06 17:11:09 -08:00
flattenAndDedupeArray ( meta . bootstrap ). forEach ( type => {
2016-11-10 14:07:30 -08:00
if ( ! isValidType ( type )) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Unexpected value ' ${ stringifyType ( type ) } ' used in the bootstrap property of module ' ${ stringifyType ( moduleType ) } '` ),
2016-12-06 17:11:09 -08:00
moduleType );
return ;
2016-11-10 14:07:30 -08:00
}
2016-12-15 09:12:40 -08:00
bootstrapComponents . push ( this . _getIdentifierMetadata ( type ));
2016-11-10 14:07:30 -08:00
});
}
2016-12-27 09:36:47 -08:00
entryComponents . push (
... bootstrapComponents . map ( type => this . _getEntryComponentMetadata ( type . reference )));
2016-11-10 14:07:30 -08:00
if ( meta . schemas ) {
schemas . push (... flattenAndDedupeArray ( meta . schemas ));
}
compileMeta = new cpl . CompileNgModuleMetadata ({
2016-11-23 09:42:19 -08:00
type : this . _getTypeMetadata ( moduleType ),
2016-11-10 14:07:30 -08:00
providers ,
entryComponents ,
bootstrapComponents ,
schemas ,
declaredDirectives ,
exportedDirectives ,
declaredPipes ,
exportedPipes ,
importedModules ,
exportedModules ,
transitiveModule ,
id : meta.id ,
});
2016-12-02 10:08:46 -08:00
entryComponents . forEach (( id ) => transitiveModule . addEntryComponent ( id ));
providers . forEach (( provider ) => transitiveModule . addProvider ( provider , compileMeta . type ));
transitiveModule . addModule ( compileMeta . type );
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-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Type ${ stringifyType ( type ) } is part of the declarations of 2 modules: ${ stringifyType ( oldModule ) } and ${ stringifyType ( moduleType ) } ! ` +
`Please consider moving ${ stringifyType ( type ) } to a higher module that imports ${ stringifyType ( oldModule ) } and ${ stringifyType ( moduleType ) } . ` +
`You can also create a new NgModule that exports and includes ${ stringifyType ( type ) } then import that NgModule in ${ stringifyType ( oldModule ) } and ${ stringifyType ( moduleType ) } .` ),
2016-12-06 17:11:09 -08:00
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-12-02 10:08:46 -08:00
const result = new cpl . TransitiveCompileNgModuleMetadata ();
2016-11-29 08:08:22 -08:00
const modulesByToken = new Map < any , Set < any >>();
importedModules . concat ( exportedModules ). forEach (( modSummary ) => {
2016-12-02 10:08:46 -08:00
modSummary . modules . forEach (( mod ) => result . addModule ( mod ));
modSummary . entryComponents . forEach (( comp ) => result . addEntryComponent ( comp ));
2016-11-29 15:36:33 -08:00
const addedTokens = new Set < any >();
2016-11-29 08:08:22 -08:00
modSummary . providers . forEach (( entry ) => {
const tokenRef = cpl . tokenReference ( entry . provider . token );
let prevModules = modulesByToken . get ( tokenRef );
if ( ! prevModules ) {
prevModules = new Set < any >();
modulesByToken . set ( tokenRef , prevModules );
}
const moduleRef = entry . module . reference ;
2016-11-29 15:36:33 -08:00
// Note: the providers of one module may still contain multiple providers
// per token (e.g. for multi providers), and we need to preserve these.
if ( addedTokens . has ( tokenRef ) || ! prevModules . has ( moduleRef )) {
2016-11-29 08:08:22 -08:00
prevModules . add ( moduleRef );
2016-11-29 15:36:33 -08:00
addedTokens . add ( tokenRef );
2016-12-02 10:08:46 -08:00
result . addProvider ( entry . provider , entry . module );
2016-11-29 08:08:22 -08:00
}
});
});
2016-12-02 10:08:46 -08:00
exportedModules . forEach (( modSummary ) => {
modSummary . exportedDirectives . forEach (( id ) => result . addExportedDirective ( id ));
modSummary . exportedPipes . forEach (( id ) => result . addExportedPipe ( id ));
2016-11-29 08:08:22 -08:00
});
2016-12-02 10:08:46 -08:00
importedModules . forEach (( modSummary ) => {
modSummary . exportedDirectives . forEach (( id ) => result . addDirective ( id ));
modSummary . exportedPipes . forEach (( id ) => result . addPipe ( id ));
});
return result ;
2016-07-18 03:50:31 -07:00
}
2016-11-23 09:42:19 -08:00
private _getIdentifierMetadata ( type : Type < any >) : cpl . CompileIdentifierMetadata {
2016-06-28 09:54:42 -07:00
type = resolveForwardRef ( type );
2016-11-30 10:52:51 -08:00
return { reference : type };
2016-11-10 14:07:30 -08:00
}
2016-12-15 09:12:40 -08:00
isInjectable ( type : any ) : boolean {
const annotations = this . _reflector . annotations ( type );
// Note: We need an exact check here as @Component / @Directive / ... inherit
// from @CompilerInjectable!
return annotations . some ( ann => ann . constructor === Injectable );
}
getInjectableSummary ( type : any ) : cpl . CompileTypeSummary {
return { summaryKind : cpl.CompileSummaryKind.Injectable , type : this . _getTypeMetadata ( type )};
}
private _getInjectableMetadata ( type : Type < any >, dependencies : any [] = null ) :
cpl . CompileTypeMetadata {
const typeSummary = this . _loadSummary ( type , cpl . CompileSummaryKind . Injectable );
if ( typeSummary ) {
return typeSummary . type ;
}
return this . _getTypeMetadata ( type , dependencies );
}
2016-11-23 09:42:19 -08:00
private _getTypeMetadata ( type : Type < any >, dependencies : any [] = null ) : cpl . CompileTypeMetadata {
const identifier = this . _getIdentifierMetadata ( type );
2016-11-30 10:52:51 -08:00
return {
2016-11-10 14:07:30 -08:00
reference : identifier.reference ,
diDeps : this._getDependenciesMetadata ( identifier . reference , dependencies ),
lifecycleHooks :
LIFECYCLE_HOOKS_VALUES.filter ( hook => hasLifecycleHook ( hook , identifier . reference )),
2016-11-30 10:52:51 -08:00
};
2016-01-06 14:13:44 -08:00
}
2016-11-23 09:42:19 -08:00
private _getFactoryMetadata ( factory : Function , 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-11-30 10:52:51 -08:00
return { reference : factory , 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.
2017-02-05 14:22:06 -08:00
* This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first.
2016-11-10 14:07:30 -08:00
*/
getPipeMetadata ( pipeType : any ) : cpl . CompilePipeMetadata {
const pipeMeta = this . _pipeCache . get ( pipeType );
if ( ! pipeMeta ) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2017-02-05 14:22:06 -08:00
`Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${ stringifyType ( pipeType ) } .` ),
2016-12-06 17:11:09 -08:00
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 {
2016-12-02 10:08:46 -08:00
const pipeSummary =
< cpl.CompilePipeSummary > this . _loadSummary ( pipeType , cpl . CompileSummaryKind . Pipe );
2016-11-10 16:27:53 -08:00
if ( ! pipeSummary ) {
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Illegal state: Could not load the summary for pipe ${ stringifyType ( pipeType ) } .` ),
2016-12-06 17:11:09 -08:00
pipeType );
2016-11-10 16:27:53 -08:00
}
return pipeSummary ;
}
2016-11-16 10:22:11 -08:00
getOrLoadPipeMetadata ( pipeType : any ) : cpl . CompilePipeMetadata {
let pipeMeta = this . _pipeCache . get ( pipeType );
2016-11-10 14:07:30 -08:00
if ( ! pipeMeta ) {
2016-11-16 10:22:11 -08:00
pipeMeta = this . _loadPipeMetadata ( pipeType );
2016-11-10 14:07:30 -08:00
}
2016-11-16 10:22:11 -08:00
return pipeMeta ;
}
2016-11-10 14:07:30 -08:00
2016-11-16 10:22:11 -08:00
private _loadPipeMetadata ( pipeType : any ) : cpl . CompilePipeMetadata {
pipeType = resolveForwardRef ( pipeType );
const pipeAnnotation = this . _pipeResolver . resolve ( pipeType );
const pipeMeta = new cpl . CompilePipeMetadata ({
2016-11-23 09:42:19 -08:00
type : this . _getTypeMetadata ( pipeType ),
2016-11-16 10:22:11 -08:00
name : pipeAnnotation.name ,
pure : pipeAnnotation.pure
2016-11-10 14:07:30 -08:00
});
2016-11-16 10:22:11 -08:00
this . _pipeCache . set ( pipeType , pipeMeta );
2016-12-02 10:08:46 -08:00
this . _summaryCache . set ( pipeType , pipeMeta . toSummary ());
2016-11-16 10:22:11 -08:00
return pipeMeta ;
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 ;
2016-12-28 01:02:28 +03:00
} else if ( isValidType ( paramEntry ) && token == null ) {
2016-06-08 16:38:52 -07:00
token = paramEntry ;
}
});
2016-02-18 10:53:21 -08:00
} else {
token = param ;
}
2016-12-28 01:02:28 +03:00
if ( token == null ) {
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-11-30 10:52:51 -08:00
return {
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-11-30 10:52:51 -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-12-15 09:12:40 -08:00
dependenciesMetadata . map (( dep ) => dep ? stringifyType ( dep . token ) : '?' ). join ( ', ' );
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Can't resolve all parameters for ${ stringifyType ( typeOrFunc ) } : ( ${ depsTokens } ).` ),
2016-12-06 17:11:09 -08:00
typeOrFunc );
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-11-30 10:52:51 -08:00
compileToken = { value : token };
2016-01-06 14:13:44 -08:00
} else {
2016-11-30 10:52:51 -08:00
compileToken = { identifier : { reference : token }};
2016-01-06 14:13:44 -08:00
}
return compileToken ;
}
2016-11-10 14:07:30 -08:00
private _getProvidersMetadata (
2016-12-27 09:36:47 -08:00
providers : Provider [], targetEntryComponents : cpl.CompileEntryComponentMetadata [],
2016-12-06 17:11:09 -08:00
debugInfo? : string , compileProviders : cpl.CompileProviderMetadata [] = [],
type ?: any ) : cpl . CompileProviderMetadata [] {
2016-08-24 01:18:41 +02:00
providers . forEach (( provider : any , providerIdx : number ) => {
2016-09-14 15:58:18 -07:00
if ( Array . isArray ( provider )) {
2016-11-30 10:52:51 -08:00
this . _getProvidersMetadata ( provider , targetEntryComponents , debugInfo , compileProviders );
2016-06-28 09:54:42 -07:00
} else {
2016-11-30 10:52:51 -08:00
provider = resolveForwardRef ( provider );
let providerMeta : cpl.ProviderMeta ;
2016-12-28 04:05:14 +03:00
if ( provider && typeof provider === 'object' && provider . hasOwnProperty ( 'provide' )) {
2016-12-28 01:02:28 +03:00
this . _validateProvider ( provider );
2016-11-30 10:52:51 -08:00
providerMeta = new cpl . ProviderMeta ( provider . provide , provider );
} else if ( isValidType ( provider )) {
providerMeta = new cpl . ProviderMeta ( provider , { useClass : provider });
2016-12-28 04:05:14 +03:00
} else if ( provider === void 0 ) {
2017-01-27 13:19:00 -08:00
this . _reportError ( syntaxError (
2016-12-28 04:05:14 +03:00
`Encountered undefined provider! Usually this means you have a circular dependencies (might be caused by using 'barrel' index.ts files.` ));
2016-11-30 10:52:51 -08:00
} else {
const providersInfo =
(< string [] > providers . reduce (
( soFar : string [], seenProvider : any , seenProviderIdx : number ) => {
if ( seenProviderIdx < providerIdx ) {
2016-12-15 09:12:40 -08:00
soFar . push ( ` ${ stringifyType ( seenProvider ) } ` );
2016-11-30 10:52:51 -08:00
} else if ( seenProviderIdx == providerIdx ) {
2016-12-15 09:12:40 -08:00
soFar . push ( `? ${ stringifyType ( seenProvider ) } ?` );
2016-11-30 10:52:51 -08:00
} else if ( seenProviderIdx == providerIdx + 1 ) {
soFar . push ( '...' );
}
return soFar ;
},
[]))
. join ( ', ' );
2016-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-06 17:11:09 -08:00
`Invalid ${ debugInfo ? debugInfo : 'provider' } - only instances of Provider and Type are allowed, got: [ ${ providersInfo } ]` ),
type );
2016-11-30 10:52:51 -08:00
}
if ( providerMeta . token === resolveIdentifier ( Identifiers . ANALYZE_FOR_ENTRY_COMPONENTS )) {
2016-12-06 17:11:09 -08:00
targetEntryComponents . push (... this . _getEntryComponentsFromProvider ( providerMeta , type ));
2016-11-30 10:52:51 -08:00
} else {
compileProviders . push ( this . getProviderMetadata ( providerMeta ));
}
2016-07-07 10:05:55 -07:00
}
2016-01-06 14:13:44 -08:00
});
2016-07-07 10:05:55 -07:00
return compileProviders ;
}
2016-12-28 01:02:28 +03:00
private _validateProvider ( provider : any ) : void {
if ( provider . hasOwnProperty ( 'useClass' ) && provider . useClass == null ) {
2017-01-27 13:19:00 -08:00
this . _reportError ( syntaxError (
2016-12-28 01:02:28 +03:00
`Invalid provider for ${ stringifyType ( provider . provide ) } . useClass cannot be ${ provider . useClass } .
Usually it happens when:
1. There's a circular dependency (might be caused by using index.ts (barrel) files).
2. Class was used before it was declared. Use forwardRef in this case.` ));
}
}
2016-12-06 17:11:09 -08:00
private _getEntryComponentsFromProvider ( provider : cpl.ProviderMeta , type ?: any ) :
2016-12-27 09:36:47 -08:00
cpl . CompileEntryComponentMetadata [] {
const components : cpl.CompileEntryComponentMetadata [] = [];
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-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError ( `The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!` ), type );
2016-12-06 17:11:09 -08:00
return [];
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-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError ( `The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!` ),
2016-12-15 13:07:12 -08:00
type );
2016-12-06 17:11:09 -08:00
return [];
2016-07-07 10:05:55 -07:00
}
2016-09-14 15:58:18 -07:00
2016-11-30 10:52:51 -08:00
extractIdentifiers ( provider . useValue , collectedIdentifiers );
2016-07-07 10:05:55 -07:00
collectedIdentifiers . forEach (( identifier ) => {
2017-02-06 17:55:58 -08:00
const entry = this . _getEntryComponentMetadata ( identifier . reference , false );
2016-12-27 09:36:47 -08:00
if ( entry ) {
components . push ( entry );
2016-07-07 10:05:55 -07:00
}
});
return components ;
2016-01-06 14:13:44 -08:00
}
2017-02-06 17:55:58 -08:00
private _getEntryComponentMetadata ( dirType : any , throwIfNotFound = true ) :
cpl . CompileEntryComponentMetadata {
2016-12-27 09:36:47 -08:00
const dirMeta = this . getNonNormalizedDirectiveMetadata ( dirType );
2017-02-06 17:55:58 -08:00
if ( dirMeta && dirMeta . metadata . isComponent ) {
2016-12-27 09:36:47 -08:00
return { componentType : dirType , componentFactory : dirMeta.metadata.componentFactory };
} else {
const dirSummary =
< cpl.CompileDirectiveSummary > this . _loadSummary ( dirType , cpl . CompileSummaryKind . Directive );
2017-02-06 17:55:58 -08:00
if ( dirSummary && dirSummary . isComponent ) {
2016-12-27 09:36:47 -08:00
return { componentType : dirType , componentFactory : dirSummary.componentFactory };
}
}
2017-02-06 17:55:58 -08:00
if ( throwIfNotFound ) {
throw syntaxError ( ` ${ dirType . name } cannot be used as an entry component.` );
}
2016-12-27 09:36:47 -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-11-30 10:52:51 -08:00
let token : cpl.CompileTokenMetadata = this . _getTokenMetadata ( provider . token );
2016-06-18 18:42:34 +02:00
2016-09-14 15:58:18 -07:00
if ( provider . useClass ) {
2016-12-15 09:12:40 -08:00
compileTypeMetadata = this . _getInjectableMetadata ( provider . useClass , provider . dependencies );
2016-06-18 18:42:34 +02:00
compileDeps = compileTypeMetadata . diDeps ;
2016-11-30 10:52:51 -08:00
if ( provider . token === provider . useClass ) {
// use the compileTypeMetadata as it contains information about lifecycleHooks...
token = { identifier : compileTypeMetadata };
}
2016-09-14 15:58:18 -07:00
} else if ( provider . useFactory ) {
2016-11-23 09:42:19 -08:00
compileFactoryMetadata = this . _getFactoryMetadata ( provider . useFactory , provider . dependencies );
2016-06-18 18:42:34 +02:00
compileDeps = compileFactoryMetadata . diDeps ;
2016-01-06 14:13:44 -08:00
}
2016-06-18 18:42:34 +02:00
2016-11-30 10:52:51 -08:00
return {
token : token ,
2016-06-18 18:42:34 +02:00
useClass : compileTypeMetadata ,
2016-11-30 10:52:51 -08:00
useValue : 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-30 10:52:51 -08:00
};
2016-01-06 14:13:44 -08:00
}
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-12-06 17:11:09 -08:00
this . _reportError (
2017-01-27 13:19:00 -08:00
syntaxError (
2016-12-15 09:12:40 -08:00
`Can't construct a query for the property " ${ propertyName } " of " ${ stringifyType ( typeOrFunc ) } " since the query selector wasn't defined.` ),
2016-12-06 17:11:09 -08:00
typeOrFunc );
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-11-30 10:52:51 -08:00
return {
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-11-30 10:52:51 -08:00
};
2016-01-06 14:13:44 -08:00
}
2016-12-06 17:11:09 -08:00
private _reportError ( error : any , type ?: any , otherType? : any ) {
if ( this . _errorCollector ) {
this . _errorCollector ( error , type );
if ( otherType ) {
this . _errorCollector ( error , otherType );
}
} else {
throw error ;
}
}
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-12-05 13:26:12 -08:00
return ( value instanceof StaticSymbol ) || ( value instanceof Type );
2016-02-18 10:53:21 -08:00
}
2016-11-23 09:42:19 -08:00
export function componentModuleUrl (
2016-09-14 16:49:13 -07:00
reflector : ReflectorReader , type : Type < any >, cmpMetadata : Component ) : string {
2016-12-05 13:26:12 -08:00
if ( type instanceof StaticSymbol ) {
2016-11-23 09:42:19 -08:00
return type . filePath ;
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 ) {
2017-01-27 13:19:00 -08:00
throw syntaxError (
2016-12-15 09:12:40 -08:00
`moduleId should be a string in " ${ stringifyType ( type ) } ". See https://goo.gl/wIDDiL for more information. \ n` +
2016-09-14 16:49:13 -07:00
`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-11-30 10:52:51 -08:00
function extractIdentifiers ( value : any , targetIdentifiers : cpl.CompileIdentifierMetadata []) {
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 {
2016-11-30 10:52:51 -08:00
targetIdentifiers . push ({ reference : value });
2016-04-30 16:13:03 -07:00
}
}
2016-12-15 09:12:40 -08:00
function stringifyType ( type : any ) : string {
if ( type instanceof StaticSymbol ) {
return ` ${ type . name } in ${ type . filePath } ` ;
} else {
return stringify ( type );
}
2016-12-16 02:07:26 +01:00
}
2017-01-27 13:19:00 -08:00
/**
* Indicates that a component is still being loaded in a synchronous compile.
*/
function componentStillLoadingError ( compType : Type < any >) {
debugger ;
const error =
Error ( `Can't compile synchronously as ${ stringify ( compType ) } is still being loaded!` );
( error as any )[ ERROR_COMPONENT_TYPE ] = compType ;
return error ;
2017-02-06 17:55:58 -08:00
}