1
+ import {
2
+ forEach ,
3
+ omit ,
4
+ noop
5
+ } from 'lodash' ;
1
6
import * as path from 'path' ;
2
7
import * as fs from 'fs-extra' ;
3
8
import * as glob from 'glob' ;
@@ -7,18 +12,14 @@ import { sync as isDirectory } from 'is-directory';
7
12
import requireDir from '../utils/require-dir' ;
8
13
import * as tryRequire from 'try-require' ;
9
14
import * as stripExtension from 'strip-extension' ;
10
- import {
11
- forEach ,
12
- omit ,
13
- noop
14
- } from 'lodash' ;
15
15
import { singularize } from 'inflection' ;
16
16
import * as createDebug from 'debug' ;
17
17
import DenaliObject from '../metal/object' ;
18
18
import Container from './container' ;
19
19
import Logger from './logger' ;
20
20
import Router from './router' ;
21
21
import Application from './application' ;
22
+ import Resolver from './resolver' ;
22
23
23
24
const debug = createDebug ( 'denali:runtime:addon' ) ;
24
25
@@ -32,7 +33,6 @@ export interface AddonOptions {
32
33
environment : string ;
33
34
dir : string ;
34
35
container : Container ;
35
- logger : Logger ;
36
36
pkg ?: any ;
37
37
}
38
38
@@ -85,57 +85,36 @@ export default class Addon extends DenaliObject {
85
85
public dir : string ;
86
86
87
87
/**
88
- * The list of child addons that this addon contains
89
- */
90
- public addons : Addon [ ] ;
91
-
92
- /**
93
- * The application logger instance
88
+ * The package.json for this addon
94
89
*
95
90
* @since 0.1.0
96
91
*/
97
- protected logger : Logger ;
92
+ public pkg : any ;
98
93
99
94
/**
100
- * The package.json for this addon
95
+ * The resolver instance to use with this addon.
96
+ *
97
+ * @since 0.1.0
101
98
*/
102
- public pkg : any ;
99
+ public resolver : Resolver ;
103
100
104
101
/**
105
- * Internal cache of the configuration that is specific to this addon
102
+ * The consuming application container instance
103
+ *
104
+ * @since 0.1.0
106
105
*/
107
- public _config : any ;
106
+ public container : Container ;
108
107
109
108
constructor ( options : AddonOptions ) {
110
109
super ( ) ;
111
110
this . environment = options . environment ;
112
111
this . dir = options . dir ;
112
+ this . pkg = options . pkg || tryRequire ( findup ( 'package.json' , { cwd : this . dir } ) ) ;
113
113
this . container = options . container ;
114
- this . logger = options . logger ;
115
114
116
- this . pkg = options . pkg || tryRequire ( findup ( 'package.json' , { cwd : this . dir } ) ) ;
115
+ this . resolver = this . resolver || new Resolver ( this . dir ) ;
116
+ this . container . addResolver ( this . resolver ) ;
117
117
this . container . register ( `addon:${ this . pkg . name } @${ this . pkg . version } ` , this ) ;
118
- this . _config = this . loadConfig ( ) ;
119
- }
120
-
121
- /**
122
- * The app directory for this addon. Override to customize where the app directory is stored in
123
- * your addon.
124
- *
125
- * @since 0.1.0
126
- */
127
- get appDir ( ) : string {
128
- return path . join ( this . dir , 'app' ) ;
129
- }
130
-
131
- /**
132
- * The config directory for this addon. Override this to customize where the config files are
133
- * stored in your addon.
134
- *
135
- * @since 0.1.0
136
- */
137
- public get configDir ( ) : string {
138
- return path . join ( this . dir , 'config' ) ;
139
118
}
140
119
141
120
/**
@@ -148,131 +127,6 @@ export default class Addon extends DenaliObject {
148
127
return ( this . pkg && this . pkg . name ) || 'anonymous-addon' ;
149
128
}
150
129
151
- /**
152
- * Load the config for this addon. The standard `config/environment.js` file is loaded by default.
153
- * `config/middleware.js` and `config/routes.js` are ignored. All other userland config files are
154
- * loaded into the container under their filenames.
155
- *
156
- * Config files are all .js files, so just the exported functions are loaded here. The functions
157
- * are run later, during application initialization, to generate the actual runtime configuration.
158
- */
159
- protected loadConfig ( ) : any {
160
- let config = this . loadConfigFile ( 'environment' ) || function ( ) {
161
- return { } ;
162
- } ;
163
- if ( isDirectory ( this . configDir ) ) {
164
- let allConfigFiles = requireDir ( this . configDir , { recurse : false } ) ;
165
- let extraConfigFiles = omit ( allConfigFiles , 'environment' , 'middleware' , 'routes' ) ;
166
- forEach ( extraConfigFiles , ( configModule , configFilename ) => {
167
- let configModulename = stripExtension ( configFilename ) ;
168
- this . container . register ( `config:${ configModulename } ` , configModule ) ;
169
- } ) ;
170
- }
171
- return config ;
172
- }
173
-
174
- /**
175
- * Load the addon's various assets. Loads child addons first, meaning that addon loading is
176
- * depth-first recursive.
177
- */
178
- public load ( ) : void {
179
- debug ( `loading ${ this . pkg . name } ` ) ;
180
- this . loadInitializers ( ) ;
181
- this . loadMiddleware ( ) ;
182
- this . loadApp ( ) ;
183
- this . loadRoutes ( ) ;
184
- }
185
-
186
- /**
187
- * Load the initializers for this addon. Initializers live in `config/initializers`.
188
- */
189
- protected loadInitializers ( ) : void {
190
- let initializersDir = path . join ( this . configDir , 'initializers' ) ;
191
- if ( isDirectory ( initializersDir ) ) {
192
- let initializers = requireDir ( initializersDir ) ;
193
- forEach ( initializers , ( initializer , name ) => {
194
- this . container . register ( `initializer:${ name } ` , initializer ) ;
195
- } ) ;
196
- }
197
- }
198
-
199
- /**
200
- * Load the middleware for this addon. Middleware is specified in `config/middleware.js`. The file
201
- * should export a function that accepts the router as it's single argument. You can then attach
202
- * any middleware you'd like to that router, and it will execute before any route handling by
203
- * Denali.
204
- *
205
- * Typically this is useful to register global middleware, i.e. a CORS handler, cookie parser,
206
- * etc.
207
- *
208
- * If you want to run some logic before certain routes only, try using filters on your actions
209
- * instead.
210
- */
211
- protected loadMiddleware ( ) : void {
212
- this . _middleware = this . loadConfigFile ( 'middleware' ) || noop ;
213
- }
214
-
215
- /**
216
- * The middleware factory for this addon.
217
- */
218
- public _middleware : ( router : Router , application : Application ) => void ;
219
-
220
- /**
221
- * Loads the routes for this addon. Routes are defined in `config/routes.js`. The file should
222
- * export a function that defines routes. See the Routing guide for details on how to define
223
- * routes.
224
- */
225
- protected loadRoutes ( ) : void {
226
- this . _routes = this . loadConfigFile ( 'routes' ) || noop ;
227
- }
228
-
229
- /**
230
- * The routes factory for this addon.
231
- */
232
- public _routes : ( router : Router ) => void ;
233
-
234
- /**
235
- * Load the app assets for this addon. These are the various classes that live under `app/`,
236
- * including actions, models, etc., as well as any custom class types.
237
- *
238
- * Files are loaded into the container under their folder's namespace, so `app/roles/admin.js`
239
- * would be registered as 'role:admin' in the container. Deeply nested folders become part of the
240
- * module name, i.e. `app/roles/employees/manager.js` becomes 'role:employees/manager'.
241
- *
242
- * Non-JS files are loaded as well, and their container names include the extension, so
243
- * `app/mailer/welcome.html` becomes `mail:welcome.html`.
244
- */
245
- protected loadApp ( ) : void {
246
- debug ( `loading app for ${ this . pkg . name } ` ) ;
247
- if ( fs . existsSync ( this . appDir ) ) {
248
- eachDir ( this . appDir , ( dirname ) => {
249
- debug ( `loading ${ dirname } for ${ this . pkg . name } ` ) ;
250
- let dir = path . join ( this . appDir , dirname ) ;
251
- let type = singularize ( dirname ) ;
252
-
253
- glob . sync ( '**/*' , { cwd : dir } ) . forEach ( ( filepath ) => {
254
- let modulepath = stripExtension ( filepath ) ;
255
- if ( filepath . endsWith ( '.js' ) ) {
256
- let Class = require ( path . join ( dir , filepath ) ) ;
257
- Class = Class . default || Class ;
258
- this . container . register ( `${ type } :${ modulepath } ` , Class ) ;
259
- } else if ( filepath . endsWith ( '.json' ) ) {
260
- let mod = require ( path . join ( dir , filepath ) ) ;
261
- this . container . register ( `${ type } :${ modulepath } ` , mod . default || mod ) ;
262
- }
263
- } ) ;
264
- } ) ;
265
- }
266
- }
267
-
268
- /**
269
- * Helper to load a file from the config directory
270
- */
271
- protected loadConfigFile ( filename : string ) : any {
272
- let configModule = tryRequire ( path . join ( this . configDir , `${ filename } .js` ) ) ;
273
- return configModule && ( configModule . default || configModule ) ;
274
- }
275
-
276
130
/**
277
131
* A hook to perform any shutdown actions necessary to gracefully exit the application, i.e. close
278
132
* database/socket connections.
0 commit comments