Skip to content

Commit

Permalink
feat: make it possible to merge configurations when extending other c…
Browse files Browse the repository at this point in the history
…onfig. (#1411)
  • Loading branch information
soulgalore authored and bcoe committed Sep 6, 2019
1 parent a5d1c75 commit 5d7ad98
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 5 deletions.
3 changes: 2 additions & 1 deletion docs/advanced.md
Expand Up @@ -439,7 +439,8 @@ yargs.parserConfiguration({
"camel-case-expansion": true,
"dot-notation": true,
"parse-numbers": true,
"boolean-negation": true
"boolean-negation": true,
"deep-merge-config": false
})
```

Expand Down
18 changes: 16 additions & 2 deletions lib/apply-extends.js
Expand Up @@ -16,7 +16,21 @@ function getPathToDefaultConfig (cwd, pathToExtend) {
return path.resolve(cwd, pathToExtend)
}

function applyExtends (config, cwd) {
function mergeDeep (config1, config2) {
const target = {}
const isObject = obj => obj && typeof obj === 'object' && !Array.isArray(obj)
Object.assign(target, config1)
for (let key of Object.keys(config2)) {
if (isObject(config2[key]) && isObject(target[key])) {
target[key] = mergeDeep(config1[key], config2[key])
} else {
target[key] = config2[key]
}
}
return target
}

function applyExtends (config, cwd, mergeExtends) {
let defaultConfig = {}

if (Object.prototype.hasOwnProperty.call(config, 'extends')) {
Expand Down Expand Up @@ -47,7 +61,7 @@ function applyExtends (config, cwd) {

previouslyVisitedConfigs = []

return Object.assign({}, defaultConfig, config)
return mergeExtends ? mergeDeep(defaultConfig, config) : Object.assign({}, defaultConfig, config)
}

module.exports = applyExtends
12 changes: 12 additions & 0 deletions test/fixtures/extends/config_deep.json
@@ -0,0 +1,12 @@
{
"a": {
"b": 15,
"c": 12,
"d": [1,2,3],
"e": [1],
"f": "yes"
},
"test": {
"yes": 1
}
}
50 changes: 50 additions & 0 deletions test/yargs.js
Expand Up @@ -1374,6 +1374,56 @@ describe('yargs dsl tests', () => {
argv.c.should.equal(201)
argv.z.should.equal(15)
})

it('deep merge objects when extending when configured', () => {
const argv = yargs()
.parserConfiguration({ 'deep-merge-config': true })
.config({
extends: './test/fixtures/extends/config_deep.json',
a: {
b: 11,
d: [5, 2],
f: 'no',
g: {
h: 122
},
i: [1, 2]
}
})
.parse()

argv.a.b.should.equal(11)
argv.a.c.should.equal(12)
argv.a.d.should.deep.equal([5, 2])
argv.a.e.should.equal(1)
argv.a.f.should.equal('no')
argv.a.g.h.should.equal(122)
argv.a.i.should.deep.equal([1, 2])
argv.test.yes.should.equal(1)
})

it('do not merge objects by default when extending', () => {
const argv = yargs()
.config({
extends: './test/fixtures/extends/config_deep.json',
a: {
b: 11,
d: [5, 2],
f: 'no',
g: {
h: 122
}
}
})
.parse()

argv.a.b.should.equal(11)
argv.a.should.not.have.property('c')
argv.a.d.should.deep.equal([5, 2])
argv.a.should.not.have.property('e')
argv.a.f.should.equal('no')
argv.a.g.h.should.equal(122)
})
})
})

Expand Down
4 changes: 2 additions & 2 deletions yargs.js
Expand Up @@ -330,7 +330,7 @@ function Yargs (processArgs, cwd, parentRequire) {
argsert('[object|string] [string|function] [function]', [key, msg, parseFn], arguments.length)
// allow a config object to be provided directly.
if (typeof key === 'object') {
key = applyExtends(key, cwd)
key = applyExtends(key, cwd, self.getParserConfiguration()['deep-merge-config'])
options.configObjects = (options.configObjects || []).concat(key)
return self
}
Expand Down Expand Up @@ -504,7 +504,7 @@ function Yargs (processArgs, cwd, parentRequire) {

// If an object exists in the key, add it to options.configObjects
if (obj[key] && typeof obj[key] === 'object') {
conf = applyExtends(obj[key], rootPath || cwd)
conf = applyExtends(obj[key], rootPath || cwd, self.getParserConfiguration()['deep-merge-config'])
options.configObjects = (options.configObjects || []).concat(conf)
}

Expand Down

0 comments on commit 5d7ad98

Please sign in to comment.