diff --git a/archetype/config/main.js b/archetype/config/main.js index e2c184f..69966cf 100644 --- a/archetype/config/main.js +++ b/archetype/config/main.js @@ -22,6 +22,13 @@ module.exports = { require('<%- trailpacks %>') ], + /** + * Override trailspacks configurations for modify based on custom requirements + */ + packsConfig: { + + }, + /** * Define application paths here. "root" is the only required path. */ diff --git a/lib/trails.js b/lib/trails.js index 7982ad8..e25cd05 100644 --- a/lib/trails.js +++ b/lib/trails.js @@ -6,6 +6,32 @@ const lib = require('.') module.exports = { + /** + * Detect if the item is a Object. + */ + isObject (item) { + return (item && typeof item === 'object' && + !Array.isArray(item) && item !== null) + }, + + /** + * Deep Merge Objects + */ + deepMerge (target, source) { + if (this.isObject(target) && this.isObject(source)) { + Object.keys(source).forEach(key => { + if (this.isObject(source[key])) { + if (!target[key]) Object.assign(target, { [key]: {} }) + this.deepMerge(target[key], source[key]) + } + else { + Object.assign(target, { [key]: source[key] }) + } + }) + } + return target + }, + /** * Copy and merge the provided configuration into a new object, decorated with * necessary default and environment-specific values. @@ -15,6 +41,7 @@ module.exports = { main: { maxListeners: 128, packs: (config.main || { }).packs || [ ], + packsConfig: (config.main || { }).packsConfig || {}, paths: { root: path.resolve(path.dirname(require.main.filename)), temp: path.resolve(path.dirname(require.main.filename), '.tmp') @@ -26,23 +53,25 @@ module.exports = { }, log: { } } - const envConfig = (config.env && config.env[process.env.NODE_ENV]) || { } + + // merge config.env + config = this.deepMerge( + (config || { }), + ((config.env && config.env[process.env.NODE_ENV]) || { }) + ) // merge config.main.paths Object.assign( - configTemplate.main.paths, (config.main || { }).paths, (envConfig.main || { }).paths + configTemplate.main.paths, (config.main || { }).paths ) // merge config.main.timeouts Object.assign( - configTemplate.main.timeouts, (config.main || { }).timeouts, (envConfig.main || { }).timeouts + configTemplate.main.timeouts, (config.main || { }).timeouts ) - // override config.main.packs with env config - configTemplate.main.packs = (envConfig.main || { }).packs || (config.main || { }).packs || [ ] - // merge application log - Object.assign(configTemplate.log, config.log, envConfig.log) + Object.assign(configTemplate.log, config.log) // merge remaining environment-specific config properties return Object.assign({ }, config, configTemplate) diff --git a/test/lib/trails.test.js b/test/lib/trails.test.js index b7d702a..7c6cc8e 100644 --- a/test/lib/trails.test.js +++ b/test/lib/trails.test.js @@ -18,6 +18,14 @@ describe('lib.Trails', () => { log: { merged: 'yes', extraneous: 'assigned' + }, + customObject: { + string: 'b', + int: 2, + array: [2, 3, 4], + subobj: { + attr: 'b' + } } }, envTest2: { @@ -28,6 +36,12 @@ describe('lib.Trails', () => { }, merged: 'yes', extraneous: 'assigned' + }, + customObject: { + subobj: { + attr: 'b' + }, + int2: 2 } }, envTest3: { @@ -54,6 +68,14 @@ describe('lib.Trails', () => { } }, normal: 'yes' + }, + customObject: { + string: 'a', + int: 1, + array: [1, 2, 3], + subobj: { + attr: 'a' + } } } }) @@ -112,6 +134,49 @@ describe('lib.Trails', () => { assert.equal(config.main.maxListeners, 128) }) + it('should merge full custom env config', () => { + process.env.NODE_ENV = 'envTest1' + const config = lib.Trails.buildConfig(testConfig) + + assert(config) + assert(typeof config.customObject === 'object') + assert.equal(config.customObject.string, 'b') + assert.equal(config.customObject.int, 2) + assert(Array.isArray(config.customObject.array)) + assert.equal(config.customObject.array[0], 2) + assert(typeof config.customObject.subobj === 'object') + assert.equal(config.customObject.subobj.attr, 'b') + }) + + it('should merge partial custom env config', () => { + process.env.NODE_ENV = 'envTest2' + const config = lib.Trails.buildConfig(testConfig) + + assert(config) + assert(typeof config.customObject === 'object') + assert.equal(config.customObject.string, 'a') + assert.equal(config.customObject.int, 1) + assert(Array.isArray(config.customObject.array)) + assert.equal(config.customObject.array[0], 1) + assert(typeof config.customObject.subobj === 'object') + assert.equal(config.customObject.subobj.attr, 'b') + }) + + it('should merge new custom attr in env config', () => { + process.env.NODE_ENV = 'envTest2' + const config = lib.Trails.buildConfig(testConfig) + + assert(config) + assert(typeof config.customObject === 'object') + assert.equal(config.customObject.string, 'a') + assert.equal(config.customObject.int, 1) + assert(Array.isArray(config.customObject.array)) + assert.equal(config.customObject.array[0], 1) + assert(typeof config.customObject.subobj === 'object') + assert.equal(config.customObject.subobj.attr, 'b') + assert.equal(config.customObject.int2, 2) + }) + it('should not override any configs if NODE_ENV matches no env', () => { process.env.NODE_ENV = 'notconfigured' const config = lib.Trails.buildConfig(testConfig) @@ -119,6 +184,7 @@ describe('lib.Trails', () => { assert(config) assert.equal(config.log.merged, 'no') assert.equal(config.log.normal, 'yes') + assert.equal(config.customObject, testConfig.customObject) assert(!config.log.extraneous) assert(config.env)