New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow provided config object to extend other configs #779
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
root = true | ||
|
||
[*.js] | ||
end_of_line = lf | ||
indent_style = space | ||
indent_size = 2 | ||
insert_final_newline = true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
var fs = require('fs') | ||
var path = require('path') | ||
var assign = require('./assign') | ||
var YError = require('./yerror') | ||
|
||
var previouslyVisitedConfigs = [] | ||
|
||
function checkForCircularExtends (path) { | ||
if (previouslyVisitedConfigs.indexOf(path) > -1) { | ||
throw new YError("Circular extended configurations: '" + path + "'.") | ||
} | ||
} | ||
|
||
function applyExtends (config, cwd, subKey) { | ||
var defaultConfig = {} | ||
|
||
if (config.hasOwnProperty('extends')) { | ||
var pathToDefault = path.join(cwd, config.extends) | ||
|
||
checkForCircularExtends(pathToDefault) | ||
|
||
previouslyVisitedConfigs.push(pathToDefault) | ||
delete config.extends | ||
|
||
defaultConfig = JSON.parse(fs.readFileSync(pathToDefault, 'utf8')) | ||
if (subKey) { | ||
defaultConfig = defaultConfig[subKey] || {} | ||
} | ||
defaultConfig = applyExtends(defaultConfig, path.dirname(pathToDefault), subKey) | ||
} | ||
|
||
previouslyVisitedConfigs = [] | ||
|
||
return assign(defaultConfig, config) | ||
} | ||
|
||
module.exports = applyExtends |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"a": 44, | ||
"extends": "./circular_2.json" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"b": "any", | ||
"extends": "./circular_1.json" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"a": 30, | ||
"b": 22, | ||
"extends": "./config_2.json" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"z": 15 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"foo": { | ||
"a": 80, | ||
"extends": "../packageB/package.json" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"foo": { | ||
"a": 90, | ||
"b": "riffiwobbles" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ var fs = require('fs') | |
var path = require('path') | ||
var checkOutput = require('./helpers/utils').checkOutput | ||
var yargs = require('../') | ||
var YError = require('../lib/yerror') | ||
|
||
require('chai').should() | ||
|
||
|
@@ -1155,6 +1156,27 @@ describe('yargs dsl tests', function () { | |
argv.foo.should.equal(1) | ||
argv.bar.should.equal(2) | ||
}) | ||
|
||
describe('extends', function () { | ||
it('applies default configurations when given config object', function () { | ||
var argv = yargs | ||
.config({ | ||
extends: './test/fixtures/extends/config_1.json', | ||
a: 1 | ||
}) | ||
.argv | ||
|
||
argv.a.should.equal(1) | ||
argv.b.should.equal(22) | ||
argv.z.should.equal(15) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔥 this is great. my only nitpick is about the indenting on line 1162. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
}) | ||
|
||
it('protects against circular extended configurations', function () { | ||
expect(function () { | ||
yargs.config({extends: './test/fixtures/extends/circular_1.json'}) | ||
}).to.throw(YError) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('normalize', function () { | ||
|
@@ -1411,6 +1433,13 @@ describe('yargs dsl tests', function () { | |
|
||
argv.foo.should.equal('a') | ||
}) | ||
|
||
it('should apply default configurations from extended packages', function () { | ||
var argv = yargs().pkgConf('foo', 'test/fixtures/extends/packageA').argv | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Perhaps we should change line 479 of yargs.js to this: conf = applyExtends(obj[key], path || cwd, key) // <-- add the `|| cwd` part and maybe add a test for this scenario as well? Otherwise, this is looking really good! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done with your help in 5353a2b. |
||
|
||
argv.a.should.equal(80) | ||
argv.b.should.equals('riffiwobbles') | ||
}) | ||
}) | ||
|
||
describe('skipValidation', function () { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ const Validation = require('./lib/validation') | |
const Y18n = require('y18n') | ||
const objFilter = require('./lib/obj-filter') | ||
const setBlocking = require('set-blocking') | ||
const applyExtends = require('./lib/apply-extends') | ||
const YError = require('./lib/yerror') | ||
|
||
var exports = module.exports = Yargs | ||
|
@@ -304,6 +305,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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Tweak 3/3] Then we can make use of self.pkgConf = function (key, path) {
argsert('<string> [string]', [key, path], arguments.length)
var conf = null
var obj = pkgUp(path)
// If an object exists in the key, add it to options.configObjects
if (obj[key] && typeof obj[key] === 'object') {
conf = applyExtends(obj[key], cwd, key) // <-- this line changed
options.configObjects = (options.configObjects || []).concat(conf)
}
return self
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
options.configObjects = (options.configObjects || []).concat(key) | ||
return self | ||
} | ||
|
@@ -319,6 +321,7 @@ function Yargs (processArgs, cwd, parentRequire) { | |
;(Array.isArray(key) ? key : [key]).forEach(function (k) { | ||
options.config[k] = parseFn || true | ||
}) | ||
|
||
return self | ||
} | ||
|
||
|
@@ -473,7 +476,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 = obj[key] | ||
conf = applyExtends(obj[key], path, key) | ||
options.configObjects = (options.configObjects || []).concat(conf) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Comment] I like @JaKXz's idea of supporting modules by name as well (e.g.
"extends": "my-lib"
instead of just"extends": "node_modules/my-lib/some-file"
), but since yargs isn't always loading the original "some-file" and doesn't know its path, I like your general approach as the next best thing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel yargs is too general of a tool to make assumptions for shorthand extends like
my-lib
. For more context, my use case in nyc probably won't even extend a root.nycrc
in another package. Rather, it will extend something likemy-lib/configs/.nycrc
.