@@ -7,7 +7,10 @@ import {
77} from '../di' ;
88import { ResolvedModule } from '../module/factory' ;
99import { ID } from '../shared/types' ;
10- import { ModuleDuplicatedError } from '../shared/errors' ;
10+ import {
11+ ModuleDuplicatedError ,
12+ ModuleNonUniqueIdError ,
13+ } from '../shared/errors' ;
1114import { flatten , isDefined } from '../shared/utils' ;
1215import { ApplicationConfig , Application } from './types' ;
1316import {
@@ -19,6 +22,7 @@ import { createContextBuilder } from './context';
1922import { executionCreator } from './execution' ;
2023import { subscriptionCreator } from './subscription' ;
2124import { apolloSchemaCreator , apolloExecutorCreator } from './apollo' ;
25+ import { Module } from '../module/types' ;
2226
2327export type ModulesMap = Map < ID , ResolvedModule > ;
2428
@@ -53,92 +57,107 @@ export interface InternalAppContext {
5357 * })
5458 * ```
5559 */
56- export function createApplication ( config : ApplicationConfig ) : Application {
57- const providers =
58- config . providers && typeof config . providers === 'function'
59- ? config . providers ( )
60- : config . providers ;
61- // Creates an Injector with singleton classes at application level
62- const appSingletonProviders = ReflectiveInjector . resolve (
63- onlySingletonProviders ( providers )
64- ) ;
65- const appInjector = ReflectiveInjector . createFromResolved ( {
66- name : 'App (Singleton Scope)' ,
67- providers : appSingletonProviders ,
68- } ) ;
69- // Filter Operation-scoped providers, and keep it here
70- // so we don't do it over and over again
71- const appOperationProviders = ReflectiveInjector . resolve (
72- onlyOperationProviders ( providers )
73- ) ;
74- const middlewareMap = config . middlewares || { } ;
75-
76- // Create all modules
77- const modules = config . modules . map ( ( mod ) =>
78- mod . factory ( {
60+ export function createApplication (
61+ applicationConfig : ApplicationConfig
62+ ) : Application {
63+ function applicationFactory ( cfg ?: ApplicationConfig ) : Application {
64+ const config = cfg || applicationConfig ;
65+ const providers =
66+ config . providers && typeof config . providers === 'function'
67+ ? config . providers ( )
68+ : config . providers ;
69+ // Creates an Injector with singleton classes at application level
70+ const appSingletonProviders = ReflectiveInjector . resolve (
71+ onlySingletonProviders ( providers )
72+ ) ;
73+ const appInjector = ReflectiveInjector . createFromResolved ( {
74+ name : 'App (Singleton Scope)' ,
75+ providers : appSingletonProviders ,
76+ } ) ;
77+ // Filter Operation-scoped providers, and keep it here
78+ // so we don't do it over and over again
79+ const appOperationProviders = ReflectiveInjector . resolve (
80+ onlyOperationProviders ( providers )
81+ ) ;
82+ const middlewareMap = config . middlewares || { } ;
83+
84+ // Validations
85+ ensureModuleUniqueIds ( config . modules ) ;
86+
87+ // Create all modules
88+ const modules = config . modules . map ( ( mod ) =>
89+ mod . factory ( {
90+ injector : appInjector ,
91+ middlewares : middlewareMap ,
92+ } )
93+ ) ;
94+ const modulesMap = createModulesMap ( modules ) ;
95+ const singletonGlobalProvidersMap = createGlobalProvidersMap ( {
96+ modules,
97+ scope : Scope . Singleton ,
98+ } ) ;
99+ const operationGlobalProvidersMap = createGlobalProvidersMap ( {
100+ modules,
101+ scope : Scope . Operation ,
102+ } ) ;
103+
104+ attachGlobalProvidersMap ( {
105+ injector : appInjector ,
106+ globalProvidersMap : singletonGlobalProvidersMap ,
107+ moduleInjectorGetter ( moduleId ) {
108+ return modulesMap . get ( moduleId ) ! . injector ;
109+ } ,
110+ } ) ;
111+
112+ // Creating a schema, flattening the typedefs and resolvers
113+ // is not expensive since it happens only once
114+ const typeDefs = flatten ( modules . map ( ( mod ) => mod . typeDefs ) ) ;
115+ const resolvers = modules . map ( ( mod ) => mod . resolvers ) . filter ( isDefined ) ;
116+ const schema = ( applicationConfig . schemaBuilder || makeExecutableSchema ) ( {
117+ typeDefs,
118+ resolvers,
119+ } ) ;
120+
121+ const contextBuilder = createContextBuilder ( {
122+ appInjector,
123+ appLevelOperationProviders : appOperationProviders ,
124+ modulesMap : modulesMap ,
125+ singletonGlobalProvidersMap,
126+ operationGlobalProvidersMap,
127+ } ) ;
128+
129+ const createSubscription = subscriptionCreator ( { contextBuilder } ) ;
130+ const createExecution = executionCreator ( { contextBuilder } ) ;
131+ const createSchemaForApollo = apolloSchemaCreator ( {
132+ createSubscription,
133+ contextBuilder,
134+ schema,
135+ } ) ;
136+ const createApolloExecutor = apolloExecutorCreator ( {
137+ createExecution,
138+ schema,
139+ } ) ;
140+
141+ instantiateSingletonProviders ( {
142+ appInjector,
143+ modulesMap,
144+ } ) ;
145+
146+ return {
147+ typeDefs,
148+ resolvers,
149+ schema,
79150 injector : appInjector ,
80- middlewares : middlewareMap ,
81- } )
82- ) ;
83- const modulesMap = createModulesMap ( modules ) ;
84- const singletonGlobalProvidersMap = createGlobalProvidersMap ( {
85- modules,
86- scope : Scope . Singleton ,
87- } ) ;
88- const operationGlobalProvidersMap = createGlobalProvidersMap ( {
89- modules,
90- scope : Scope . Operation ,
91- } ) ;
92-
93- attachGlobalProvidersMap ( {
94- injector : appInjector ,
95- globalProvidersMap : singletonGlobalProvidersMap ,
96- moduleInjectorGetter ( moduleId ) {
97- return modulesMap . get ( moduleId ) ! . injector ;
98- } ,
99- } ) ;
100-
101- // Creating a schema, flattening the typedefs and resolvers
102- // is not expensive since it happens only once
103- const typeDefs = flatten ( modules . map ( ( mod ) => mod . typeDefs ) ) ;
104- const resolvers = modules . map ( ( mod ) => mod . resolvers ) . filter ( isDefined ) ;
105- const schema = makeExecutableSchema ( { typeDefs, resolvers } ) ;
106-
107- const contextBuilder = createContextBuilder ( {
108- appInjector,
109- appLevelOperationProviders : appOperationProviders ,
110- modulesMap : modulesMap ,
111- singletonGlobalProvidersMap,
112- operationGlobalProvidersMap,
113- } ) ;
114-
115- const createSubscription = subscriptionCreator ( { contextBuilder } ) ;
116- const createExecution = executionCreator ( { contextBuilder } ) ;
117- const createSchemaForApollo = apolloSchemaCreator ( {
118- createSubscription,
119- contextBuilder,
120- schema,
121- } ) ;
122- const createApolloExecutor = apolloExecutorCreator ( {
123- createExecution,
124- schema,
125- } ) ;
126-
127- instantiateSingletonProviders ( {
128- appInjector,
129- modulesMap,
130- } ) ;
131-
132- return {
133- typeDefs,
134- resolvers,
135- schema,
136- injector : appInjector ,
137- createSubscription,
138- createExecution,
139- createSchemaForApollo,
140- createApolloExecutor,
141- } ;
151+ createSubscription,
152+ createExecution,
153+ createSchemaForApollo,
154+ createApolloExecutor,
155+ ɵfactory : applicationFactory ,
156+ ɵconfig : config ,
157+ } ;
158+ }
159+
160+ return applicationFactory ( ) ;
142161}
143162
144163function createModulesMap ( modules : ResolvedModule [ ] ) : ModulesMap {
@@ -170,3 +189,16 @@ function createModulesMap(modules: ResolvedModule[]): ModulesMap {
170189
171190 return modulesMap ;
172191}
192+
193+ function ensureModuleUniqueIds ( modules : Module [ ] ) {
194+ const collisions = modules
195+ . filter ( ( mod , i , all ) => i !== all . findIndex ( ( m ) => m . id === mod . id ) )
196+ . map ( ( m ) => m . id ) ;
197+
198+ if ( collisions . length ) {
199+ throw new ModuleNonUniqueIdError (
200+ `Modules with non-unique ids: ${ collisions . join ( ', ' ) } ` ,
201+ `All modules should have unique ids, please locate and fix them.`
202+ ) ;
203+ }
204+ }
0 commit comments