2016-06-23 12:47:54 -04:00
/ * *
* @license
* Copyright Google Inc . All Rights Reserved .
*
* Use of this source code is governed by an MIT - style license that can be
* found in the LICENSE file at https : //angular.io/license
* /
2016-12-06 20:11:09 -05:00
import { AnimationAnimateMetadata , AnimationEntryMetadata , AnimationGroupMetadata , AnimationKeyframesSequenceMetadata , AnimationMetadata , AnimationStateDeclarationMetadata , AnimationStateMetadata , AnimationStateTransitionMetadata , AnimationStyleMetadata , AnimationWithStepsMetadata , Attribute , ChangeDetectionStrategy , Component , Directive , Host , Inject , Injectable , ModuleWithProviders , OpaqueToken , Optional , Provider , Query , SchemaMetadata , Self , SkipSelf , Type , resolveForwardRef } from '@angular/core' ;
2016-06-08 19:38:52 -04:00
2016-12-05 16:26:12 -05:00
import { StaticSymbol } from './aot/static_symbol' ;
2016-06-20 12:52:41 -04:00
import { assertArrayOfStrings , assertInterpolationSymbols } from './assertions' ;
2016-01-06 17:13:44 -05:00
import * as cpl from './compile_metadata' ;
2016-11-10 17:07:30 -05:00
import { DirectiveNormalizer } from './directive_normalizer' ;
2016-01-06 17:13:44 -05:00
import { DirectiveResolver } from './directive_resolver' ;
2016-11-10 19:27:53 -05:00
import { ListWrapper , StringMapWrapper } from './facade/collection' ;
2016-10-19 16:42:39 -04:00
import { isBlank , isPresent , stringify } from './facade/lang' ;
2016-11-23 12:42:19 -05:00
import { Identifiers , createIdentifierToken , resolveIdentifier } from './identifiers' ;
2016-12-15 12:12:40 -05:00
import { CompilerInjectable } from './injectable' ;
2016-08-02 04:37:42 -04:00
import { hasLifecycleHook } from './lifecycle_reflector' ;
2016-07-18 06:50:31 -04:00
import { NgModuleResolver } from './ng_module_resolver' ;
2016-01-06 17:13:44 -05:00
import { PipeResolver } from './pipe_resolver' ;
2016-11-10 17:07:30 -05:00
import { ComponentStillLoadingError , LIFECYCLE_HOOKS_VALUES , ReflectorReader , reflector } from './private_import_core' ;
2016-07-28 13:39:10 -04:00
import { ElementSchemaRegistry } from './schema/element_schema_registry' ;
2016-11-29 18:36:33 -05:00
import { SummaryResolver } from './summary_resolver' ;
2016-04-28 20:50:03 -04:00
import { getUrlScheme } from './url_resolver' ;
2016-12-15 16:07:12 -05:00
import { MODULE_SUFFIX , SyncAsyncResult , SyntaxError , ValueTransformer , visitValue } from './util' ;
2016-04-28 20:50:03 -04:00
2016-12-06 20:11:09 -05:00
export type ErrorCollector = ( error : any , type ? : any ) = > void ;
export const ERROR_COLLECTOR_TOKEN = new OpaqueToken ( 'ErrorCollector' ) ;
2016-11-10 19:27:53 -05:00
2016-11-10 17:07:30 -05: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 12:12:40 -05:00
@CompilerInjectable ( )
2016-02-18 13:53:21 -05:00
export class CompileMetadataResolver {
2016-08-10 21:21:28 -04:00
private _directiveCache = new Map < Type < any > , cpl . CompileDirectiveMetadata > ( ) ;
2016-12-02 13:08:46 -05:00
private _summaryCache = new Map < Type < any > , cpl . CompileTypeSummary > ( ) ;
2016-08-10 21:21:28 -04: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 18:59:09 -04:00
2016-06-08 19:38:52 -04:00
constructor (
2016-07-18 06:50:31 -04:00
private _ngModuleResolver : NgModuleResolver , private _directiveResolver : DirectiveResolver ,
2016-12-15 12:12:40 -05:00
private _pipeResolver : PipeResolver , private _summaryResolver : SummaryResolver < any > ,
2016-11-29 18:36:33 -05:00
private _schemaRegistry : ElementSchemaRegistry ,
2016-11-10 17:07:30 -05:00
private _directiveNormalizer : DirectiveNormalizer ,
2016-12-06 20:11:09 -05:00
private _reflector : ReflectorReader = reflector ,
@Optional ( ) @Inject ( ERROR_COLLECTOR_TOKEN ) private _errorCollector? : ErrorCollector ) { }
2015-09-14 18:59:09 -04:00
2016-08-10 21:21:28 -04:00
clearCacheFor ( type : Type < any > ) {
2016-11-10 17:07:30 -05:00
const dirMeta = this . _directiveCache . get ( type ) ;
2016-06-28 12:54:42 -04:00
this . _directiveCache . delete ( type ) ;
2016-12-02 13:08:46 -05:00
this . _summaryCache . delete ( type ) ;
2016-06-28 12:54:42 -04:00
this . _pipeCache . delete ( type ) ;
2016-07-18 06:50:31 -04:00
this . _ngModuleOfTypes . delete ( type ) ;
2016-09-12 22:14:17 -04:00
// Clear all of the NgModule as they contain transitive information!
2016-07-18 06:50:31 -04:00
this . _ngModuleCache . clear ( ) ;
2016-11-10 17:07:30 -05:00
if ( dirMeta ) {
this . _directiveNormalizer . clearCacheFor ( dirMeta ) ;
}
2016-06-24 11:46:43 -04:00
}
clearCache() {
this . _directiveCache . clear ( ) ;
2016-12-02 13:08:46 -05:00
this . _summaryCache . clear ( ) ;
2016-06-24 11:46:43 -04:00
this . _pipeCache . clear ( ) ;
2016-07-18 06:50:31 -04:00
this . _ngModuleCache . clear ( ) ;
this . _ngModuleOfTypes . clear ( ) ;
2016-11-10 17:07:30 -05:00
this . _directiveNormalizer . clearCache ( ) ;
2016-06-24 11:46:43 -04:00
}
2016-05-26 18:07:51 -04:00
getAnimationEntryMetadata ( entry : AnimationEntryMetadata ) : cpl . CompileAnimationEntryMetadata {
2016-11-10 17:07:30 -05:00
const defs = entry . definitions . map ( def = > this . _getAnimationStateMetadata ( def ) ) ;
2016-05-25 15:46:22 -04:00
return new cpl . CompileAnimationEntryMetadata ( entry . name , defs ) ;
}
2016-11-10 17:07:30 -05:00
private _getAnimationStateMetadata ( value : AnimationStateMetadata ) :
cpl . CompileAnimationStateMetadata {
2016-05-26 18:07:51 -04:00
if ( value instanceof AnimationStateDeclarationMetadata ) {
2016-11-10 17:07:30 -05:00
const styles = this . _getAnimationStyleMetadata ( value . styles ) ;
2016-05-25 15:46:22 -04:00
return new cpl . CompileAnimationStateDeclarationMetadata ( value . stateNameExpr , styles ) ;
2016-09-14 18:58:18 -04:00
}
if ( value instanceof AnimationStateTransitionMetadata ) {
2016-06-08 19:38:52 -04:00
return new cpl . CompileAnimationStateTransitionMetadata (
2016-11-10 17:07:30 -05:00
value . stateChangeExpr , this . _getAnimationMetadata ( value . steps ) ) ;
2016-05-25 15:46:22 -04:00
}
2016-09-14 18:58:18 -04:00
2016-05-25 15:46:22 -04:00
return null ;
}
2016-11-10 17:07:30 -05:00
private _getAnimationStyleMetadata ( value : AnimationStyleMetadata ) :
cpl . CompileAnimationStyleMetadata {
2016-05-25 15:46:22 -04:00
return new cpl . CompileAnimationStyleMetadata ( value . offset , value . styles ) ;
}
2016-11-10 17:07:30 -05:00
private _getAnimationMetadata ( value : AnimationMetadata ) : cpl . CompileAnimationMetadata {
2016-05-26 18:07:51 -04:00
if ( value instanceof AnimationStyleMetadata ) {
2016-11-10 17:07:30 -05:00
return this . _getAnimationStyleMetadata ( value ) ;
2016-09-14 18:58:18 -04:00
}
if ( value instanceof AnimationKeyframesSequenceMetadata ) {
2016-06-08 19:38:52 -04:00
return new cpl . CompileAnimationKeyframesSequenceMetadata (
2016-11-10 17:07:30 -05:00
value . steps . map ( entry = > this . _getAnimationStyleMetadata ( entry ) ) ) ;
2016-09-14 18:58:18 -04:00
}
if ( value instanceof AnimationAnimateMetadata ) {
const animateData =
2016-06-08 19:38:52 -04:00
< cpl.CompileAnimationStyleMetadata | cpl.CompileAnimationKeyframesSequenceMetadata > this
2016-11-10 17:07:30 -05:00
. _getAnimationMetadata ( value . styles ) ;
2016-05-25 15:46:22 -04:00
return new cpl . CompileAnimationAnimateMetadata ( value . timings , animateData ) ;
2016-09-14 18:58:18 -04:00
}
if ( value instanceof AnimationWithStepsMetadata ) {
2016-11-10 17:07:30 -05:00
const steps = value . steps . map ( step = > this . _getAnimationMetadata ( step ) ) ;
2016-09-14 18:58:18 -04:00
2016-05-26 18:07:51 -04:00
if ( value instanceof AnimationGroupMetadata ) {
2016-05-25 15:46:22 -04:00
return new cpl . CompileAnimationGroupMetadata ( steps ) ;
}
2016-09-14 18:58:18 -04:00
return new cpl . CompileAnimationSequenceMetadata ( steps ) ;
2016-05-25 15:46:22 -04:00
}
return null ;
}
2016-12-02 13:08:46 -05:00
private _loadSummary ( type : any , kind : cpl.CompileSummaryKind ) : cpl . CompileTypeSummary {
2016-12-15 12:12:40 -05: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 13:08:46 -05:00
}
2016-12-15 12:12:40 -05:00
return typeSummary && typeSummary . summaryKind === kind ? typeSummary : null ;
2016-12-02 13:08:46 -05:00
}
2016-11-29 18:36:33 -05:00
private _loadDirectiveMetadata ( directiveType : any , isSync : boolean ) : Promise < any > {
2016-11-10 17:07:30 -05:00
if ( this . _directiveCache . has ( directiveType ) ) {
return ;
}
2016-06-28 12:54:42 -04:00
directiveType = resolveForwardRef ( directiveType ) ;
2016-11-23 12:42:19 -05:00
const { annotation , metadata } = this . getNonNormalizedDirectiveMetadata ( directiveType ) ;
2016-11-16 13:22:11 -05:00
const createDirectiveMetadata = ( templateMetadata : cpl.CompileTemplateMetadata ) = > {
const normalizedDirMeta = new cpl . CompileDirectiveMetadata ( {
2016-11-23 12:42:19 -05: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-11-16 13:22:11 -05:00
template : templateMetadata
} ) ;
this . _directiveCache . set ( directiveType , normalizedDirMeta ) ;
2016-12-02 13:08:46 -05:00
this . _summaryCache . set ( directiveType , normalizedDirMeta . toSummary ( ) ) ;
2016-11-16 13:22:11 -05:00
return normalizedDirMeta ;
} ;
2016-11-10 17:07:30 -05:00
2016-11-23 12:42:19 -05:00
if ( metadata . isComponent ) {
2016-11-16 13:22:11 -05:00
const templateMeta = this . _directiveNormalizer . normalizeTemplate ( {
componentType : directiveType ,
2016-11-23 12:42:19 -05:00
module Url : 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-16 13:22:11 -05:00
} ) ;
if ( templateMeta . syncResult ) {
createDirectiveMetadata ( templateMeta . syncResult ) ;
return null ;
2016-07-28 13:39:10 -04:00
} else {
2016-11-16 13:22:11 -05:00
if ( isSync ) {
2016-12-06 20:11:09 -05:00
this . _reportError ( new ComponentStillLoadingError ( directiveType ) , directiveType ) ;
return null ;
2016-07-28 13:39:10 -04:00
}
2016-11-29 18:36:33 -05:00
return templateMeta . asyncResult . then ( createDirectiveMetadata ) ;
2016-01-06 17:13:44 -05:00
}
2016-11-16 13:22:11 -05:00
} else {
// directive
createDirectiveMetadata ( null ) ;
return null ;
}
}
2016-01-06 17:13:44 -05:00
2016-11-23 12:42:19 -05:00
getNonNormalizedDirectiveMetadata ( directiveType : any ) :
{ annotation : Directive , metadata : cpl.CompileDirectiveMetadata } {
2016-11-16 13:22:11 -05:00
directiveType = resolveForwardRef ( directiveType ) ;
const dirMeta = this . _directiveResolver . resolve ( directiveType ) ;
if ( ! dirMeta ) {
return null ;
}
let nonNormalizedTemplateMetadata : cpl.CompileTemplateMetadata ;
2016-11-10 17:07:30 -05:00
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 ;
2016-11-16 13:22:11 -05:00
nonNormalizedTemplateMetadata = new cpl . CompileTemplateMetadata ( {
2016-11-10 17:07:30 -05:00
encapsulation : dirMeta.encapsulation ,
template : dirMeta.template ,
templateUrl : dirMeta.templateUrl ,
styles : dirMeta.styles ,
styleUrls : dirMeta.styleUrls ,
animations : animations ,
interpolation : dirMeta.interpolation
} ) ;
2016-11-16 13:22:11 -05:00
}
let changeDetectionStrategy : ChangeDetectionStrategy = null ;
2016-11-30 13:52:51 -05:00
let viewProviders : cpl.CompileProviderMetadata [ ] = [ ] ;
2016-11-16 13:22:11 -05:00
let entryComponentMetadata : cpl.CompileIdentifierMetadata [ ] = [ ] ;
let selector = dirMeta . selector ;
if ( dirMeta instanceof Component ) {
// Component
changeDetectionStrategy = dirMeta . changeDetection ;
if ( dirMeta . viewProviders ) {
viewProviders = this . _getProvidersMetadata (
dirMeta . viewProviders , entryComponentMetadata ,
2016-12-15 12:12:40 -05:00
` viewProviders for " ${ stringifyType ( directiveType ) } " ` , [ ] , directiveType ) ;
2016-11-16 13:22:11 -05:00
}
if ( dirMeta . entryComponents ) {
2016-11-23 12:42:19 -05:00
entryComponentMetadata = flattenAndDedupeArray ( dirMeta . entryComponents )
. map ( ( type ) = > this . _getIdentifierMetadata ( type ) )
. concat ( entryComponentMetadata ) ;
2016-11-16 13:22:11 -05:00
}
if ( ! selector ) {
selector = this . _schemaRegistry . getDefaultComponentElementName ( ) ;
2016-11-10 17:07:30 -05:00
}
} else {
2016-11-16 13:22:11 -05:00
// Directive
if ( ! selector ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:54:38 -05:00
new SyntaxError (
` Directive ${ stringifyType ( directiveType ) } has no selector, please add it! ` ) ,
2016-12-06 20:11:09 -05:00
directiveType ) ;
selector = 'error' ;
2016-11-16 13:22:11 -05:00
}
2016-11-10 17:07:30 -05:00
}
2016-11-16 13:22:11 -05:00
2016-11-30 13:52:51 -05:00
let providers : cpl.CompileProviderMetadata [ ] = [ ] ;
2016-11-16 13:22:11 -05:00
if ( isPresent ( dirMeta . providers ) ) {
providers = this . _getProvidersMetadata (
2016-12-15 12:12:40 -05:00
dirMeta . providers , entryComponentMetadata ,
` providers for " ${ stringifyType ( directiveType ) } " ` , [ ] , directiveType ) ;
2016-11-16 13:22:11 -05:00
}
let queries : cpl.CompileQueryMetadata [ ] = [ ] ;
let viewQueries : cpl.CompileQueryMetadata [ ] = [ ] ;
if ( isPresent ( dirMeta . queries ) ) {
queries = this . _getQueriesMetadata ( dirMeta . queries , false , directiveType ) ;
viewQueries = this . _getQueriesMetadata ( dirMeta . queries , true , directiveType ) ;
}
2016-11-23 12:42:19 -05:00
const metadata = cpl . CompileDirectiveMetadata . create ( {
2016-11-16 13:22:11 -05:00
selector : selector ,
exportAs : dirMeta.exportAs ,
isComponent : ! ! nonNormalizedTemplateMetadata ,
2016-11-23 12:42:19 -05:00
type : this . _getTypeMetadata ( directiveType ) ,
2016-11-16 13:22:11 -05:00
template : nonNormalizedTemplateMetadata ,
changeDetection : changeDetectionStrategy ,
inputs : dirMeta.inputs ,
outputs : dirMeta.outputs ,
host : dirMeta.host ,
providers : providers ,
viewProviders : viewProviders ,
queries : queries ,
viewQueries : viewQueries ,
entryComponents : entryComponentMetadata
} ) ;
2016-11-23 12:42:19 -05:00
return { metadata , annotation : dirMeta } ;
2016-11-10 17:07:30 -05: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 ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Illegal state: getDirectiveMetadata can only be called after loadNgModuleMetadata for a module that declares it. Directive ${ stringifyType ( directiveType ) } . ` ) ,
2016-12-06 20:11:09 -05:00
directiveType ) ;
2015-12-02 13:35:51 -05:00
}
2016-11-10 17:07:30 -05:00
return dirMeta ;
2015-12-02 13:35:51 -05:00
}
2016-11-10 19:27:53 -05:00
getDirectiveSummary ( dirType : any ) : cpl . CompileDirectiveSummary {
2016-12-02 13:08:46 -05:00
const dirSummary =
< cpl.CompileDirectiveSummary > this . _loadSummary ( dirType , cpl . CompileSummaryKind . Directive ) ;
2016-11-10 19:27:53 -05:00
if ( ! dirSummary ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Illegal state: Could not load the summary for directive ${ stringifyType ( dirType ) } . ` ) ,
2016-12-06 20:11:09 -05:00
dirType ) ;
2016-11-10 19:27:53 -05:00
}
return dirSummary ;
}
2016-11-10 17:07:30 -05:00
isDirective ( type : any ) { return this . _directiveResolver . isDirective ( type ) ; }
isPipe ( type : any ) { return this . _pipeResolver . isPipe ( type ) ; }
2016-11-29 18:36:33 -05:00
getNgModuleSummary ( module Type : any ) : cpl . CompileNgModuleSummary {
2016-12-02 13:08:46 -05:00
let module Summary =
< cpl.CompileNgModuleSummary > this . _loadSummary ( module Type , cpl . CompileSummaryKind . NgModule ) ;
2016-11-29 18:36:33 -05:00
if ( ! module Summary ) {
2016-12-02 13:08:46 -05:00
const module Meta = this . getNgModuleMetadata ( module Type , false ) ;
module Summary = module Meta ? module Meta.toSummary ( ) : null ;
2016-11-29 18:36:33 -05:00
if ( module Summary ) {
2016-12-02 13:08:46 -05:00
this . _summaryCache . set ( module Type , module Summary ) ;
2016-11-29 18:36:33 -05:00
}
}
return module Summary ;
2016-11-10 19:27:53 -05:00
}
2016-11-10 17:07:30 -05:00
/ * *
2016-11-29 18:36:33 -05:00
* Loads the declared directives and pipes of an NgModule .
2016-11-10 17:07:30 -05:00
* /
2016-11-29 11:08:22 -05:00
loadNgModuleDirectiveAndPipeMetadata ( module Type : any , isSync : boolean , throwIfNotFound = true ) :
2016-11-29 18:36:33 -05:00
Promise < any > {
2016-11-29 11:08:22 -05:00
const ngModule = this . getNgModuleMetadata ( module Type , throwIfNotFound ) ;
2016-11-29 18:36:33 -05:00
const loading : Promise < any > [ ] = [ ] ;
2016-11-29 11:08:22 -05:00
if ( ngModule ) {
2016-11-29 18:36:33 -05: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 11:08:22 -05:00
}
2016-11-29 18:36:33 -05:00
return Promise . all ( loading ) ;
2016-11-10 17:07:30 -05:00
}
2016-11-29 11:08:22 -05:00
getNgModuleMetadata ( module Type : any , throwIfNotFound = true ) : cpl . CompileNgModuleMetadata {
2016-06-28 12:54:42 -04:00
module Type = resolveForwardRef ( module Type ) ;
2016-09-14 18:58:18 -04:00
let compileMeta = this . _ngModuleCache . get ( module Type ) ;
2016-11-10 17:07:30 -05:00
if ( compileMeta ) {
return compileMeta ;
}
const meta = this . _ngModuleResolver . resolve ( module Type , throwIfNotFound ) ;
if ( ! meta ) {
return null ;
}
const declaredDirectives : cpl.CompileIdentifierMetadata [ ] = [ ] ;
2016-11-10 19:27:53 -05:00
const exportedNonModuleIdentifiers : cpl.CompileIdentifierMetadata [ ] = [ ] ;
2016-11-10 17:07:30 -05:00
const declaredPipes : cpl.CompileIdentifierMetadata [ ] = [ ] ;
2016-11-10 19:27:53 -05:00
const importedModules : cpl.CompileNgModuleSummary [ ] = [ ] ;
const exportedModules : cpl.CompileNgModuleSummary [ ] = [ ] ;
2016-11-29 11:08:22 -05:00
const providers : cpl.CompileProviderMetadata [ ] = [ ] ;
2016-11-10 17:07:30 -05:00
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 module WithProviders : ModuleWithProviders = importedType ;
importedModuleType = module WithProviders.ngModule ;
if ( module WithProviders.providers ) {
providers . push ( . . . this . _getProvidersMetadata (
module WithProviders.providers , entryComponents ,
2016-12-15 12:12:40 -05:00
` provider for the NgModule ' ${ stringifyType ( importedModuleType ) } ' ` , [ ] ,
importedType ) ) ;
2016-07-18 06:50:31 -04:00
}
2016-11-10 17:07:30 -05:00
}
2016-09-14 18:58:18 -04:00
2016-11-10 17:07:30 -05:00
if ( importedModuleType ) {
2016-11-29 18:36:33 -05:00
const importedModuleSummary = this . getNgModuleSummary ( importedModuleType ) ;
2016-11-10 19:27:53 -05:00
if ( ! importedModuleSummary ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Unexpected ${ this . _getTypeDescriptor ( importedType ) } ' ${ stringifyType ( importedType ) } ' imported by the module ' ${ stringifyType ( module Type ) } ' ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
return ;
2016-07-18 06:50:31 -04:00
}
2016-11-10 19:27:53 -05:00
importedModules . push ( importedModuleSummary ) ;
2016-11-10 17:07:30 -05:00
} else {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Unexpected value ' ${ stringifyType ( importedType ) } ' imported by the module ' ${ stringifyType ( module Type ) } ' ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
return ;
2016-11-10 17:07:30 -05:00
}
} ) ;
}
2016-07-18 06:50:31 -04:00
2016-11-10 17:07:30 -05:00
if ( meta . exports ) {
flattenAndDedupeArray ( meta . exports ) . forEach ( ( exportedType ) = > {
if ( ! isValidType ( exportedType ) ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Unexpected value ' ${ stringifyType ( exportedType ) } ' exported by the module ' ${ stringifyType ( module Type ) } ' ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
return ;
2016-11-10 17:07:30 -05:00
}
2016-11-29 18:36:33 -05:00
const exportedModuleSummary = this . getNgModuleSummary ( exportedType ) ;
2016-11-10 19:27:53 -05:00
if ( exportedModuleSummary ) {
exportedModules . push ( exportedModuleSummary ) ;
2016-11-10 17:07:30 -05:00
} else {
2016-11-23 12:42:19 -05:00
exportedNonModuleIdentifiers . push ( this . _getIdentifierMetadata ( exportedType ) ) ;
2016-11-10 17:07:30 -05:00
}
} ) ;
}
2016-07-18 06:50:31 -04:00
2016-11-10 17:07:30 -05: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 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Unexpected value ' ${ stringifyType ( declaredType ) } ' declared by the module ' ${ stringifyType ( module Type ) } ' ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
return ;
2016-11-10 17:07:30 -05:00
}
2016-11-23 12:42:19 -05:00
const declaredIdentifier = this . _getIdentifierMetadata ( declaredType ) ;
2016-11-10 17:07:30 -05:00
if ( this . _directiveResolver . isDirective ( declaredType ) ) {
2016-12-02 13:08:46 -05:00
transitiveModule . addDirective ( declaredIdentifier ) ;
2016-11-10 17:07:30 -05:00
declaredDirectives . push ( declaredIdentifier ) ;
this . _addTypeToModule ( declaredType , module Type ) ;
} else if ( this . _pipeResolver . isPipe ( declaredType ) ) {
2016-12-02 13:08:46 -05:00
transitiveModule . addPipe ( declaredIdentifier ) ;
2016-11-10 17:07:30 -05:00
transitiveModule . pipes . push ( declaredIdentifier ) ;
declaredPipes . push ( declaredIdentifier ) ;
this . _addTypeToModule ( declaredType , module Type ) ;
} else {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Unexpected ${ this . _getTypeDescriptor ( declaredType ) } ' ${ stringifyType ( declaredType ) } ' declared by the module ' ${ stringifyType ( module Type ) } ' ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
return ;
2016-11-10 17:07:30 -05:00
}
} ) ;
}
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 16:07:17 -04:00
2016-11-10 19:27:53 -05:00
const exportedDirectives : cpl.CompileIdentifierMetadata [ ] = [ ] ;
const exportedPipes : cpl.CompileIdentifierMetadata [ ] = [ ] ;
exportedNonModuleIdentifiers . forEach ( ( exportedId ) = > {
if ( transitiveModule . directivesSet . has ( exportedId . reference ) ) {
exportedDirectives . push ( exportedId ) ;
2016-12-02 13:08:46 -05:00
transitiveModule . addExportedDirective ( exportedId ) ;
2016-11-10 19:27:53 -05:00
} else if ( transitiveModule . pipesSet . has ( exportedId . reference ) ) {
exportedPipes . push ( exportedId ) ;
2016-12-02 13:08:46 -05:00
transitiveModule . addExportedPipe ( exportedId ) ;
2016-11-10 19:27:53 -05:00
} else {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Can't export ${ this . _getTypeDescriptor ( exportedId . reference ) } ${ stringifyType ( exportedId . reference ) } from ${ stringifyType ( module Type ) } as it was neither declared nor imported! ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
2016-11-10 19:27:53 -05:00
}
} ) ;
2016-11-10 17:07:30 -05: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 12:12:40 -05:00
meta . providers , entryComponents ,
` provider for the NgModule ' ${ stringifyType ( module Type ) } ' ` , [ ] , module Type ) ) ;
2016-11-10 17:07:30 -05:00
}
2016-09-14 18:58:18 -04:00
2016-11-10 17:07:30 -05:00
if ( meta . entryComponents ) {
2016-12-15 12:12:40 -05:00
entryComponents . push ( . . . flattenAndDedupeArray ( meta . entryComponents )
. map ( type = > this . _getIdentifierMetadata ( type ) ) ) ;
2016-11-10 17:07:30 -05:00
}
2016-09-14 18:58:18 -04:00
2016-11-10 17:07:30 -05:00
if ( meta . bootstrap ) {
2016-12-06 20:11:09 -05:00
flattenAndDedupeArray ( meta . bootstrap ) . forEach ( type = > {
2016-11-10 17:07:30 -05:00
if ( ! isValidType ( type ) ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Unexpected value ' ${ stringifyType ( type ) } ' used in the bootstrap property of module ' ${ stringifyType ( module Type ) } ' ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
return ;
2016-11-10 17:07:30 -05:00
}
2016-12-15 12:12:40 -05:00
bootstrapComponents . push ( this . _getIdentifierMetadata ( type ) ) ;
2016-11-10 17:07:30 -05:00
} ) ;
}
2016-09-14 18:58:18 -04:00
2016-11-10 17:07:30 -05:00
entryComponents . push ( . . . bootstrapComponents ) ;
2016-09-14 18:58:18 -04:00
2016-11-10 17:07:30 -05:00
if ( meta . schemas ) {
schemas . push ( . . . flattenAndDedupeArray ( meta . schemas ) ) ;
}
2016-07-27 04:52:31 -04:00
2016-11-10 17:07:30 -05:00
compileMeta = new cpl . CompileNgModuleMetadata ( {
2016-11-23 12:42:19 -05:00
type : this . _getTypeMetadata ( module Type ) ,
2016-11-10 17:07:30 -05:00
providers ,
entryComponents ,
bootstrapComponents ,
schemas ,
declaredDirectives ,
exportedDirectives ,
declaredPipes ,
exportedPipes ,
importedModules ,
exportedModules ,
transitiveModule ,
id : meta.id ,
} ) ;
2016-09-14 18:58:18 -04:00
2016-12-02 13:08:46 -05:00
entryComponents . forEach ( ( id ) = > transitiveModule . addEntryComponent ( id ) ) ;
providers . forEach ( ( provider ) = > transitiveModule . addProvider ( provider , compileMeta . type ) ) ;
transitiveModule . addModule ( compileMeta . type ) ;
2016-11-10 17:07:30 -05:00
this . _ngModuleCache . set ( module Type , compileMeta ) ;
2016-06-28 12:54:42 -04:00
return compileMeta ;
}
2016-08-17 18:57:02 -04:00
private _getTypeDescriptor ( type : Type < any > ) : string {
2016-11-10 17:07:30 -05:00
if ( this . _directiveResolver . isDirective ( type ) ) {
2016-08-17 18:57:02 -04:00
return 'directive' ;
2016-09-14 18:58:18 -04:00
}
2016-11-10 17:07:30 -05:00
if ( this . _pipeResolver . isPipe ( type ) ) {
2016-08-17 18:57:02 -04:00
return 'pipe' ;
2016-09-14 18:58:18 -04:00
}
2016-11-10 17:07:30 -05:00
if ( this . _ngModuleResolver . isNgModule ( type ) ) {
2016-08-17 18:57:02 -04:00
return 'module' ;
2016-09-14 18:58:18 -04:00
}
if ( ( type as any ) . provide ) {
2016-08-17 18:57:02 -04:00
return 'provider' ;
}
2016-09-14 18:58:18 -04:00
return 'value' ;
2016-08-17 18:57:02 -04:00
}
2016-11-10 17:07:30 -05:00
2016-08-10 21:21:28 -04:00
private _addTypeToModule ( type : Type < any > , module Type : Type < any > ) {
2016-07-18 06:50:31 -04:00
const oldModule = this . _ngModuleOfTypes . get ( type ) ;
if ( oldModule && oldModule !== module Type ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Type ${ stringifyType ( type ) } is part of the declarations of 2 modules: ${ stringifyType ( oldModule ) } and ${ stringifyType ( module Type ) } ! ` +
` Please consider moving ${ stringifyType ( type ) } to a higher module that imports ${ stringifyType ( oldModule ) } and ${ stringifyType ( module Type ) } . ` +
` You can also create a new NgModule that exports and includes ${ stringifyType ( type ) } then import that NgModule in ${ stringifyType ( oldModule ) } and ${ stringifyType ( module Type ) } . ` ) ,
2016-12-06 20:11:09 -05:00
module Type ) ;
2016-02-18 13:53:21 -05:00
}
2016-07-18 06:50:31 -04:00
this . _ngModuleOfTypes . set ( type , module Type ) ;
}
private _getTransitiveNgModuleMetadata (
2016-11-10 19:27:53 -05:00
importedModules : cpl.CompileNgModuleSummary [ ] ,
exportedModules : cpl.CompileNgModuleSummary [ ] ) : cpl . TransitiveCompileNgModuleMetadata {
2016-07-25 03:36:30 -04:00
// collect `providers` / `entryComponents` from all imported and all exported modules
2016-12-02 13:08:46 -05:00
const result = new cpl . TransitiveCompileNgModuleMetadata ( ) ;
2016-11-29 11:08:22 -05:00
const module sByToken = new Map < any , Set < any > > ( ) ;
importedModules . concat ( exportedModules ) . forEach ( ( modSummary ) = > {
2016-12-02 13:08:46 -05:00
modSummary . module s.forEach ( ( mod ) = > result . addModule ( mod ) ) ;
modSummary . entryComponents . forEach ( ( comp ) = > result . addEntryComponent ( comp ) ) ;
2016-11-29 18:36:33 -05:00
const addedTokens = new Set < any > ( ) ;
2016-11-29 11:08:22 -05:00
modSummary . providers . forEach ( ( entry ) = > {
const tokenRef = cpl . tokenReference ( entry . provider . token ) ;
let prevModules = module sByToken.get ( tokenRef ) ;
if ( ! prevModules ) {
prevModules = new Set < any > ( ) ;
module sByToken.set ( tokenRef , prevModules ) ;
}
const module Ref = entry . module .reference ;
2016-11-29 18:36:33 -05: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 ( module Ref ) ) {
2016-11-29 11:08:22 -05:00
prevModules . add ( module Ref ) ;
2016-11-29 18:36:33 -05:00
addedTokens . add ( tokenRef ) ;
2016-12-02 13:08:46 -05:00
result . addProvider ( entry . provider , entry . module ) ;
2016-11-29 11:08:22 -05:00
}
} ) ;
} ) ;
2016-12-02 13:08:46 -05:00
exportedModules . forEach ( ( modSummary ) = > {
modSummary . exportedDirectives . forEach ( ( id ) = > result . addExportedDirective ( id ) ) ;
modSummary . exportedPipes . forEach ( ( id ) = > result . addExportedPipe ( id ) ) ;
} ) ;
importedModules . forEach ( ( modSummary ) = > {
modSummary . exportedDirectives . forEach ( ( id ) = > result . addDirective ( id ) ) ;
modSummary . exportedPipes . forEach ( ( id ) = > result . addPipe ( id ) ) ;
2016-11-29 11:08:22 -05:00
} ) ;
2016-12-02 13:08:46 -05:00
return result ;
2016-07-18 06:50:31 -04:00
}
2016-11-23 12:42:19 -05:00
private _getIdentifierMetadata ( type : Type < any > ) : cpl . CompileIdentifierMetadata {
2016-11-10 17:07:30 -05:00
type = resolveForwardRef ( type ) ;
2016-11-30 13:52:51 -05:00
return { reference : type } ;
2016-02-18 13:53:21 -05:00
}
2016-12-15 12:12:40 -05: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 12:42:19 -05:00
private _getTypeMetadata ( type : Type < any > , dependencies : any [ ] = null ) : cpl . CompileTypeMetadata {
const identifier = this . _getIdentifierMetadata ( type ) ;
2016-11-30 13:52:51 -05:00
return {
2016-11-10 17:07:30 -05:00
reference : identifier.reference ,
diDeps : this._getDependenciesMetadata ( identifier . reference , dependencies ) ,
lifecycleHooks :
LIFECYCLE_HOOKS_VALUES . filter ( hook = > hasLifecycleHook ( hook , identifier . reference ) ) ,
2016-11-30 13:52:51 -05:00
} ;
2016-01-06 17:13:44 -05:00
}
2016-11-23 12:42:19 -05:00
private _getFactoryMetadata ( factory : Function , dependencies : any [ ] = null ) :
2016-06-18 12:42:34 -04:00
cpl . CompileFactoryMetadata {
2016-06-28 12:54:42 -04:00
factory = resolveForwardRef ( factory ) ;
2016-11-30 13:52:51 -05:00
return { reference : factory , diDeps : this._getDependenciesMetadata ( factory , dependencies ) } ;
2016-01-06 17:13:44 -05:00
}
2016-11-10 17:07:30 -05: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 ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Illegal state: getPipeMetadata can only be called after loadNgModuleMetadata for a module that declares it. Pipe ${ stringifyType ( pipeType ) } . ` ) ,
2016-12-06 20:11:09 -05:00
pipeType ) ;
2016-11-10 17:07:30 -05:00
}
return pipeMeta ;
}
2016-09-14 18:58:18 -04:00
2016-11-10 19:27:53 -05:00
getPipeSummary ( pipeType : any ) : cpl . CompilePipeSummary {
2016-12-02 13:08:46 -05:00
const pipeSummary =
< cpl.CompilePipeSummary > this . _loadSummary ( pipeType , cpl . CompileSummaryKind . Pipe ) ;
2016-11-10 19:27:53 -05:00
if ( ! pipeSummary ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Illegal state: Could not load the summary for pipe ${ stringifyType ( pipeType ) } . ` ) ,
2016-12-06 20:11:09 -05:00
pipeType ) ;
2016-11-10 19:27:53 -05:00
}
return pipeSummary ;
}
2016-11-16 13:22:11 -05:00
getOrLoadPipeMetadata ( pipeType : any ) : cpl . CompilePipeMetadata {
let pipeMeta = this . _pipeCache . get ( pipeType ) ;
2016-11-10 17:07:30 -05:00
if ( ! pipeMeta ) {
2016-11-16 13:22:11 -05:00
pipeMeta = this . _loadPipeMetadata ( pipeType ) ;
2015-09-14 18:59:09 -04:00
}
2016-11-16 13:22:11 -05:00
return pipeMeta ;
}
private _loadPipeMetadata ( pipeType : any ) : cpl . CompilePipeMetadata {
pipeType = resolveForwardRef ( pipeType ) ;
const pipeAnnotation = this . _pipeResolver . resolve ( pipeType ) ;
2016-11-10 17:07:30 -05:00
2016-11-16 13:22:11 -05:00
const pipeMeta = new cpl . CompilePipeMetadata ( {
2016-11-23 12:42:19 -05:00
type : this . _getTypeMetadata ( pipeType ) ,
2016-11-16 13:22:11 -05:00
name : pipeAnnotation.name ,
pure : pipeAnnotation.pure
2016-11-10 17:07:30 -05:00
} ) ;
2016-11-16 13:22:11 -05:00
this . _pipeCache . set ( pipeType , pipeMeta ) ;
2016-12-02 13:08:46 -05:00
this . _summaryCache . set ( pipeType , pipeMeta . toSummary ( ) ) ;
2016-11-16 13:22:11 -05:00
return pipeMeta ;
2015-09-14 18:59:09 -04:00
}
2016-11-10 17:07:30 -05:00
private _getDependenciesMetadata ( typeOrFunc : Type < any > | Function , dependencies : any [ ] ) :
2016-06-08 19:38:52 -04:00
cpl . CompileDiDependencyMetadata [ ] {
2016-06-09 19:07:06 -04:00
let hasUnknownDeps = false ;
2016-11-12 08:08:58 -05:00
const params = dependencies || this . _reflector . parameters ( typeOrFunc ) || [ ] ;
2016-09-14 18:58:18 -04:00
2016-11-12 08:08:58 -05:00
const dependenciesMetadata : cpl.CompileDiDependencyMetadata [ ] = params . map ( ( param ) = > {
2016-02-18 13:53:21 -05:00
let isAttribute = false ;
let isHost = false ;
let isSelf = false ;
let isSkipSelf = false ;
let isOptional = false ;
2016-10-24 16:28:23 -04:00
let token : any = null ;
2016-09-14 18:58:18 -04:00
if ( Array . isArray ( param ) ) {
param . forEach ( ( paramEntry ) = > {
2016-09-12 22:14:17 -04:00
if ( paramEntry instanceof Host ) {
2016-06-08 19:38:52 -04:00
isHost = true ;
2016-09-12 22:14:17 -04:00
} else if ( paramEntry instanceof Self ) {
2016-06-08 19:38:52 -04:00
isSelf = true ;
2016-09-12 22:14:17 -04:00
} else if ( paramEntry instanceof SkipSelf ) {
2016-06-08 19:38:52 -04:00
isSkipSelf = true ;
2016-09-12 22:14:17 -04:00
} else if ( paramEntry instanceof Optional ) {
2016-06-08 19:38:52 -04:00
isOptional = true ;
2016-09-12 22:14:17 -04:00
} else if ( paramEntry instanceof Attribute ) {
2016-06-08 19:38:52 -04:00
isAttribute = true ;
token = paramEntry . attributeName ;
2016-09-12 22:14:17 -04:00
} else if ( paramEntry instanceof Inject ) {
2016-06-08 19:38:52 -04:00
token = paramEntry . token ;
} else if ( isValidType ( paramEntry ) && isBlank ( token ) ) {
token = paramEntry ;
}
} ) ;
2016-01-06 17:13:44 -05:00
} else {
2016-02-18 13:53:21 -05:00
token = param ;
2016-01-06 17:13:44 -05:00
}
2016-02-18 13:53:21 -05:00
if ( isBlank ( token ) ) {
2016-06-09 19:07:06 -04:00
hasUnknownDeps = true ;
2016-02-18 13:53:21 -05:00
return null ;
2016-01-06 17:13:44 -05:00
}
2016-09-14 18:58:18 -04:00
2016-11-30 13:52:51 -05:00
return {
2016-09-14 18:58:18 -04:00
isAttribute ,
isHost ,
isSelf ,
isSkipSelf ,
isOptional ,
2016-11-10 17:07:30 -05:00
token : this._getTokenMetadata ( token )
2016-11-30 13:52:51 -05:00
} ;
2016-02-18 13:53:21 -05:00
2016-01-06 17:13:44 -05:00
} ) ;
2016-06-09 19:07:06 -04:00
if ( hasUnknownDeps ) {
2016-11-12 08:08:58 -05:00
const depsTokens =
2016-12-15 12:12:40 -05:00
dependenciesMetadata . map ( ( dep ) = > dep ? stringifyType ( dep . token ) : '?' ) . join ( ', ' ) ;
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Can't resolve all parameters for ${ stringifyType ( typeOrFunc ) } : ( ${ depsTokens } ). ` ) ,
2016-12-06 20:11:09 -05:00
typeOrFunc ) ;
2016-06-09 19:07:06 -04:00
}
return dependenciesMetadata ;
2016-01-06 17:13:44 -05:00
}
2016-11-10 17:07:30 -05:00
private _getTokenMetadata ( token : any ) : cpl . CompileTokenMetadata {
2016-01-06 17:13:44 -05:00
token = resolveForwardRef ( token ) ;
2016-09-14 18:58:18 -04:00
let compileToken : cpl.CompileTokenMetadata ;
2016-10-19 16:42:39 -04:00
if ( typeof token === 'string' ) {
2016-11-30 13:52:51 -05:00
compileToken = { value : token } ;
2016-01-06 17:13:44 -05:00
} else {
2016-11-30 13:52:51 -05:00
compileToken = { identifier : { reference : token } } ;
2016-01-06 17:13:44 -05:00
}
return compileToken ;
}
2016-11-10 17:07:30 -05:00
private _getProvidersMetadata (
providers : Provider [ ] , targetEntryComponents : cpl.CompileIdentifierMetadata [ ] ,
2016-12-06 20:11:09 -05:00
debugInfo? : string , compileProviders : cpl.CompileProviderMetadata [ ] = [ ] ,
type ? : any ) : cpl . CompileProviderMetadata [ ] {
2016-08-23 19:18:41 -04:00
providers . forEach ( ( provider : any , providerIdx : number ) = > {
2016-09-14 18:58:18 -04:00
if ( Array . isArray ( provider ) ) {
2016-11-30 13:52:51 -05:00
this . _getProvidersMetadata ( provider , targetEntryComponents , debugInfo , compileProviders ) ;
} else {
provider = resolveForwardRef ( provider ) ;
let providerMeta : cpl.ProviderMeta ;
if ( provider && typeof provider == 'object' && provider . hasOwnProperty ( 'provide' ) ) {
providerMeta = new cpl . ProviderMeta ( provider . provide , provider ) ;
} else if ( isValidType ( provider ) ) {
providerMeta = new cpl . ProviderMeta ( provider , { useClass : provider } ) ;
2016-07-07 13:05:55 -04:00
} else {
2016-11-30 13:52:51 -05:00
const providersInfo =
( < string [ ] > providers . reduce (
( soFar : string [ ] , seenProvider : any , seenProviderIdx : number ) = > {
if ( seenProviderIdx < providerIdx ) {
2016-12-15 12:12:40 -05:00
soFar . push ( ` ${ stringifyType ( seenProvider ) } ` ) ;
2016-11-30 13:52:51 -05:00
} else if ( seenProviderIdx == providerIdx ) {
2016-12-15 12:12:40 -05:00
soFar . push ( ` ? ${ stringifyType ( seenProvider ) } ? ` ) ;
2016-11-30 13:52:51 -05:00
} else if ( seenProviderIdx == providerIdx + 1 ) {
soFar . push ( '...' ) ;
}
return soFar ;
} ,
[ ] ) )
. join ( ', ' ) ;
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-06 20:11:09 -05:00
` Invalid ${ debugInfo ? debugInfo : 'provider' } - only instances of Provider and Type are allowed, got: [ ${ providersInfo } ] ` ) ,
type ) ;
2016-11-30 13:52:51 -05:00
}
if ( providerMeta . token === resolveIdentifier ( Identifiers . ANALYZE_FOR_ENTRY_COMPONENTS ) ) {
2016-12-06 20:11:09 -05:00
targetEntryComponents . push ( . . . this . _getEntryComponentsFromProvider ( providerMeta , type ) ) ;
2016-11-30 13:52:51 -05:00
} else {
compileProviders . push ( this . getProviderMetadata ( providerMeta ) ) ;
2016-07-07 13:05:55 -04:00
}
}
} ) ;
return compileProviders ;
}
2016-12-06 20:11:09 -05:00
private _getEntryComponentsFromProvider ( provider : cpl.ProviderMeta , type ? : any ) :
2016-11-10 17:07:30 -05:00
cpl . CompileIdentifierMetadata [ ] {
const components : cpl.CompileIdentifierMetadata [ ] = [ ] ;
2016-09-14 18:58:18 -04:00
const collectedIdentifiers : cpl.CompileIdentifierMetadata [ ] = [ ] ;
2016-07-07 13:05:55 -04:00
if ( provider . useFactory || provider . useExisting || provider . useClass ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError ( ` The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue! ` ) , type ) ;
2016-12-06 20:11:09 -05:00
return [ ] ;
2016-07-07 13:05:55 -04:00
}
2016-09-14 18:58:18 -04:00
2016-07-07 13:05:55 -04:00
if ( ! provider . multi ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError ( ` The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'! ` ) ,
type ) ;
2016-12-06 20:11:09 -05:00
return [ ] ;
2016-07-07 13:05:55 -04:00
}
2016-09-14 18:58:18 -04:00
2016-11-30 13:52:51 -05:00
extractIdentifiers ( provider . useValue , collectedIdentifiers ) ;
2016-07-07 13:05:55 -04:00
collectedIdentifiers . forEach ( ( identifier ) = > {
2016-12-15 12:12:40 -05:00
if ( this . _directiveResolver . isDirective ( identifier . reference ) ||
this . _loadSummary ( identifier . reference , cpl . CompileSummaryKind . Directive ) ) {
2016-11-10 17:07:30 -05:00
components . push ( identifier ) ;
2016-07-07 13:05:55 -04:00
}
2016-01-06 17:13:44 -05:00
} ) ;
2016-07-07 13:05:55 -04:00
return components ;
2016-01-06 17:13:44 -05:00
}
2016-08-15 22:37:42 -04:00
getProviderMetadata ( provider : cpl.ProviderMeta ) : cpl . CompileProviderMetadata {
2016-09-14 18:58:18 -04:00
let compileDeps : cpl.CompileDiDependencyMetadata [ ] ;
let compileTypeMetadata : cpl.CompileTypeMetadata = null ;
let compileFactoryMetadata : cpl.CompileFactoryMetadata = null ;
2016-11-30 13:52:51 -05:00
let token : cpl.CompileTokenMetadata = this . _getTokenMetadata ( provider . token ) ;
2016-06-18 12:42:34 -04:00
2016-09-14 18:58:18 -04:00
if ( provider . useClass ) {
2016-12-15 12:12:40 -05:00
compileTypeMetadata = this . _getInjectableMetadata ( provider . useClass , provider . dependencies ) ;
2016-06-18 12:42:34 -04:00
compileDeps = compileTypeMetadata . diDeps ;
2016-11-30 13:52:51 -05:00
if ( provider . token === provider . useClass ) {
// use the compileTypeMetadata as it contains information about lifecycleHooks...
token = { identifier : compileTypeMetadata } ;
}
2016-09-14 18:58:18 -04:00
} else if ( provider . useFactory ) {
2016-11-23 12:42:19 -05:00
compileFactoryMetadata = this . _getFactoryMetadata ( provider . useFactory , provider . dependencies ) ;
2016-06-18 12:42:34 -04:00
compileDeps = compileFactoryMetadata . diDeps ;
2016-01-06 17:13:44 -05:00
}
2016-06-18 12:42:34 -04:00
2016-11-30 13:52:51 -05:00
return {
token : token ,
2016-06-18 12:42:34 -04:00
useClass : compileTypeMetadata ,
2016-11-30 13:52:51 -05:00
useValue : provider.useValue ,
2016-06-18 12:42:34 -04:00
useFactory : compileFactoryMetadata ,
2016-11-10 17:07:30 -05:00
useExisting : provider.useExisting ? this . _getTokenMetadata ( provider . useExisting ) : null ,
2016-01-06 17:13:44 -05:00
deps : compileDeps ,
multi : provider.multi
2016-11-30 13:52:51 -05:00
} ;
2016-01-06 17:13:44 -05:00
}
2016-11-10 17:07:30 -05:00
private _getQueriesMetadata (
2016-09-12 22:14:17 -04:00
queries : { [ key : string ] : Query } , isViewQuery : boolean ,
2016-08-10 21:21:28 -04:00
directiveType : Type < any > ) : cpl . CompileQueryMetadata [ ] {
2016-09-14 18:58:18 -04:00
const res : cpl.CompileQueryMetadata [ ] = [ ] ;
Object . keys ( queries ) . forEach ( ( propertyName : string ) = > {
const query = queries [ propertyName ] ;
2016-06-22 20:25:42 -04:00
if ( query . isViewQuery === isViewQuery ) {
2016-11-10 17:07:30 -05:00
res . push ( this . _getQueryMetadata ( query , propertyName , directiveType ) ) ;
2016-06-22 20:25:42 -04:00
}
} ) ;
2016-01-06 17:13:44 -05:00
2016-09-14 18:58:18 -04:00
return res ;
2016-09-12 12:44:20 -04:00
}
2016-09-14 18:58:18 -04:00
private _queryVarBindings ( selector : any ) : string [ ] { return selector . split ( /\s*,\s*/ ) ; }
2016-09-12 12:44:20 -04:00
2016-11-10 17:07:30 -05:00
private _getQueryMetadata ( q : Query , propertyName : string , typeOrFunc : Type < any > | Function ) :
2016-06-08 19:38:52 -04:00
cpl . CompileQueryMetadata {
2016-11-12 08:08:58 -05:00
let selectors : cpl.CompileTokenMetadata [ ] ;
2016-09-14 18:58:18 -04:00
if ( typeof q . selector === 'string' ) {
2016-11-10 17:07:30 -05:00
selectors =
this . _queryVarBindings ( q . selector ) . map ( varName = > this . _getTokenMetadata ( varName ) ) ;
2016-01-06 17:13:44 -05:00
} else {
2016-09-14 18:58:18 -04:00
if ( ! q . selector ) {
2016-12-06 20:11:09 -05:00
this . _reportError (
2016-12-15 16:07:12 -05:00
new SyntaxError (
2016-12-15 12:12:40 -05:00
` Can't construct a query for the property " ${ propertyName } " of " ${ stringifyType ( typeOrFunc ) } " since the query selector wasn't defined. ` ) ,
2016-12-06 20:11:09 -05:00
typeOrFunc ) ;
2016-06-04 22:46:03 -04:00
}
2016-11-10 17:07:30 -05:00
selectors = [ this . _getTokenMetadata ( q . selector ) ] ;
2016-01-06 17:13:44 -05:00
}
2016-09-14 18:58:18 -04:00
2016-11-30 13:52:51 -05:00
return {
2016-09-14 18:58:18 -04:00
selectors ,
2016-01-06 17:13:44 -05:00
first : q.first ,
2016-09-14 18:58:18 -04:00
descendants : q.descendants , propertyName ,
2016-11-10 17:07:30 -05:00
read : q.read ? this . _getTokenMetadata ( q . read ) : null
2016-11-30 13:52:51 -05:00
} ;
2016-01-06 17:13:44 -05:00
}
2016-12-06 20:11:09 -05: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 18:59:09 -04:00
}
2016-07-18 06:50:31 -04:00
function flattenArray ( tree : any [ ] , out : Array < any > = [ ] ) : Array < any > {
if ( tree ) {
2016-09-14 18:58:18 -04:00
for ( let i = 0 ; i < tree . length ; i ++ ) {
const item = resolveForwardRef ( tree [ i ] ) ;
if ( Array . isArray ( item ) ) {
2016-07-18 06:50:31 -04:00
flattenArray ( item , out ) ;
} else {
out . push ( item ) ;
}
2015-09-14 18:59:09 -04:00
}
}
2016-06-22 17:06:23 -04:00
return out ;
2015-09-14 18:59:09 -04:00
}
2016-10-28 17:08:54 -04: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 13:53:21 -05:00
function isValidType ( value : any ) : boolean {
2016-12-05 16:26:12 -05:00
return ( value instanceof StaticSymbol ) || ( value instanceof Type ) ;
2016-02-18 13:53:21 -05:00
}
2016-11-23 12:42:19 -05:00
export function componentModuleUrl (
2016-09-14 19:49:13 -04:00
reflector : ReflectorReader , type : Type < any > , cmpMetadata : Component ) : string {
2016-12-05 16:26:12 -05:00
if ( type instanceof StaticSymbol ) {
2016-11-23 12:42:19 -05:00
return type . filePath ;
2016-04-29 00:54:02 -04:00
}
2016-09-14 19:49:13 -04:00
const module Id = cmpMetadata . module Id ;
if ( typeof module Id === 'string' ) {
2016-09-14 18:58:18 -04:00
const scheme = getUrlScheme ( module Id ) ;
return scheme ? module Id : ` package: ${ module Id } ${ MODULE_SUFFIX } ` ;
2016-09-14 19:49:13 -04:00
} else if ( module Id !== null && module Id !== void 0 ) {
2016-12-15 16:07:12 -05:00
throw new SyntaxError (
2016-12-15 12:12:40 -05:00
` moduleId should be a string in " ${ stringifyType ( type ) } ". See https://goo.gl/wIDDiL for more information. \ n ` +
2016-09-14 19:49:13 -04:00
` If you're using Webpack you should inline the template and the styles, see https://goo.gl/X2J8zc. ` ) ;
2015-09-14 18:59:09 -04:00
}
2016-04-29 00:54:02 -04:00
return reflector . importUri ( type ) ;
2015-09-14 18:59:09 -04:00
}
2016-04-30 19:13:03 -04:00
2016-11-30 13:52:51 -05:00
function extractIdentifiers ( value : any , targetIdentifiers : cpl.CompileIdentifierMetadata [ ] ) {
visitValue ( value , new _CompileValueConverter ( ) , targetIdentifiers ) ;
2016-04-30 19:13:03 -04:00
}
class _CompileValueConverter extends ValueTransformer {
2016-07-07 13:05:55 -04:00
visitOther ( value : any , targetIdentifiers : cpl.CompileIdentifierMetadata [ ] ) : any {
2016-11-30 13:52:51 -05:00
targetIdentifiers . push ( { reference : value } ) ;
2016-04-30 19:13:03 -04:00
}
}
2016-12-15 12:12:40 -05:00
function stringifyType ( type : any ) : string {
if ( type instanceof StaticSymbol ) {
return ` ${ type . name } in ${ type . filePath } ` ;
} else {
return stringify ( type ) ;
}
2016-12-15 20:07:26 -05:00
}