@@ -7,6 +7,12 @@ const publicMetadataKey = Symbol('public');
77const envMetadataKey = Symbol ( 'env' ) ;
88const arrayMetadataKey = Symbol ( 'arrayType' ) ;
99
10+ type DSpaceEnvVar = `DSPACE_${string } `;
11+
12+ type DeepEnvSpec = {
13+ [ k : string ] : DeepEnvSpec | DSpaceEnvVar | [ DSpaceEnvVar , ( val : string ) => any ] ;
14+ }
15+
1016export class Config {
1117 /**
1218 * Decorator that marks a config property as public
@@ -31,10 +37,14 @@ export class Config {
3137 * value of the environment variable and returns the appropriate
3238 * type to use for the config property.
3339 */
34- static env ( name : `DSPACE_${ string } ` , loader ?: ( val : string ) => any ) {
40+ static env ( name : DSapceEnvVar , loader ?: ( val : string ) => any ) {
3541 return Reflect . metadata ( envMetadataKey , { name, loader } ) ;
3642 }
3743
44+ static deepEnv ( spec : DeepEnvSpec ) {
45+ return Reflect . metadata ( envMetadataKey , { deep : true , spec } ) ;
46+ }
47+
3848 /**
3949 * Decorator to mark a config property as an array of another type of Config
4050 *
@@ -152,6 +162,29 @@ export class Config {
152162 // be a map of environment variable names to their values, such as
153163 // in `process.env`.
154164 protected applyEnvironment ( env : { [ k : string ] : string } ) {
165+ const deepEnv = (
166+ target : any , spec : any , envObj : { [ k : string ] : string } ,
167+ ) => {
168+ Object . keys ( spec ) . forEach ( k => {
169+ if ( spec . hasOwnProperty ( k ) ) {
170+ if ( typeof spec [ k ] === 'string' ) {
171+ const val = envObj [ spec [ k ] ] ;
172+ if ( isNotEmpty ( val ) ) {
173+ target [ k ] = val ;
174+ }
175+ } else if ( Array . isArray ( spec [ k ] )
176+ && ( typeof spec [ k ] [ 0 ] === 'string' ) ) {
177+ const val = envObj [ spec [ k [ 0 ] ] ] ;
178+ if ( isNotEmpty ( val ) ) {
179+ target [ k ] = spec [ k [ 1 ] ] ( val ) ;
180+ }
181+ } else {
182+ deepEnv ( target [ k ] , spec [ k ] , envObj ) ;
183+ }
184+ }
185+ } ) ;
186+ } ;
187+
155188 Object . keys ( this ) . forEach ( k => {
156189 if ( this [ k ] instanceof Config ) {
157190 this [ k ] . applyEnvironment ( env ) ;
@@ -160,9 +193,13 @@ export class Config {
160193 } else {
161194 const envMeta = Reflect . getMetadata ( envMetadataKey , this , k ) ;
162195 if ( envMeta ) {
163- const val = env [ envMeta . name ] ;
164- if ( isNotEmpty ( val ) ) {
165- this [ k ] = envMeta . loader ? envMeta . loader ( val ) : val ;
196+ if ( envMeta . deep ) {
197+ deepEnv ( this [ k ] , envMeta . spec , env ) ;
198+ } else {
199+ const val = env [ envMeta . name ] ;
200+ if ( isNotEmpty ( val ) ) {
201+ this [ k ] = envMeta . loader ? envMeta . loader ( val ) : val ;
202+ }
166203 }
167204 }
168205 }
0 commit comments