Skip to content
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

Added config-dot-notation for config files #459

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,36 @@ $ node example.js --foo.bar
{ _: [], "foo.bar": true }
```

_Note: as of [email protected], `dot-notation` has been split into `dot-notation` (**for CLI args**) and `config-dot-notation`_

### config-dot-notation

* default: `false`
* key: `config-dot-notation`

Should keys in the config file that contain `.` split into objects?

example config.json:
```json
{
"foo.bar": true,
"parent": {
"foo.bar": true
}
}
```

```console
$ node example.js --config config.json
{ _: [], "foo.bar": true, parent: { "foo.bar": true } }
```

_if enabled:_
```console
$ node example.js --config config.json
{ _: [], foo: { bar: true }, parent: { foo: { bar: true } } }
```

### parse numbers

* default: `true`
Expand Down
2 changes: 2 additions & 0 deletions lib/yargs-parser-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export interface Configuration {
'combine-arrays': boolean;
/** Should keys that contain `.` be treated as objects? Default is `true` */
'dot-notation': boolean;
/** Should keys in the config file that contain `.` split into objects? Default is `false` */
'config-dot-notation': boolean;
/** Should arguments be coerced into an array when duplicated? Default is `true` */
'duplicate-arguments-array': boolean;
/** Should array arguments be coerced into a single array when duplicated? Default is `true` */
Expand Down
8 changes: 8 additions & 0 deletions lib/yargs-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class YargsParser {
'camel-case-expansion': true,
'combine-arrays': false,
'dot-notation': true,
'config-dot-notation': false,
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': true,
'greedy-arrays': true,
Expand Down Expand Up @@ -698,6 +699,13 @@ export class YargsParser {
const value = config[key]
const fullKey = prev ? prev + '.' + key : key

// shortcut the process below if the key includes `.` because `setArg()` would do
// additional processing with aliases and splitting the key, when we don't need to.
if (key.includes('.') && !configuration['config-dot-notation'] && !hasKey(argv, fullKey.split('.'))) {
setKey(argv, prev ? [prev, key] : [key], value)
return
}

// if the value is an inner object and we have dot-notation
// enabled, treat inner objects in config the same as
// heavily nested dot notations (foo.bar.apple).
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/config_with_dot_notation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"a": "a",
"nested": {
"b": "b"
},
"hello.world": true,
"parent": {
"foo.bar": true
}
}
2 changes: 1 addition & 1 deletion test/fixtures/nested_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"bar": "bar"
},
"b": "b"
}
}
102 changes: 101 additions & 1 deletion test/yargs-parser.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ describe('yargs-parser', function () {
argv.should.have.property('foo').and.deep.equal('bar')
})

it('should load options and values from a JS file when config has .js extention', function () {
it('should load options and values from a JS file when config has .js extension', function () {
const jsPath = path.resolve(__dirname, './fixtures/settings.cjs')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
config: ['settings']
Expand Down Expand Up @@ -662,6 +662,106 @@ describe('yargs-parser', function () {
})
})

it('should respect cli precedence when config-dot-notation option is disabled', function () {
const jsonPath = path.resolve(__dirname, './fixtures/config_with_dot_notation.json')
const argv = parser(["--settings", jsonPath, "--nested.b", "cli"], {
config: ["settings"],
default: {
"hello.world": false,
parent: {
"foo.bar": false,
},
},
});

argv.should.have.property('a', 'a')
argv.should.have.property('nested').and.deep.equal({
b: 'cli'
})
argv.should.have.property('hello.world').and.equal(true)
argv.should.have.property('parent').and.deep.equal({
"foo.bar": true
})
})

it('should respect cli precedence when dot-notation and config-dot-notation option are disabled', function () {
const jsonPath = path.resolve(__dirname, './fixtures/config_with_dot_notation.json')
const argv = parser(["--settings", jsonPath, "--hello.world", "cli", "--parent.foo.bar", "cli"], {
config: ["settings"],
default: {
"hello.world": false,
parent: {
"foo.bar": false,
},
},
configuration: {
'dot-notation': false,
}
});

argv.should.have.property('a', 'a')
argv.should.have.property('nested').and.deep.equal({
b: 'b'
})
argv.should.have.property('hello.world').and.equal('cli')
argv.should.have.property('parent').and.deep.equal({
"foo.bar": true
})
})

it('should split into objects when config-dot-notation is enabled', function () {
const jsonPath = path.resolve(__dirname, './fixtures/config_with_dot_notation.json')
const argv = parser(["--settings", jsonPath], {
config: ["settings"],
default: {
"hello.world": false,
parent: {
"foo.bar": false,
},
},
configuration: {
"config-dot-notation": true,
}
});

argv.should.have.property('a', 'a')
argv.should.have.property('nested').and.deep.equal({
b: 'b'
})
argv.should.have.property('hello').and.deep.equal({
"world": true,
})
argv.should.have.property('parent').and.deep.equal({
"foo": { "bar": true }
})
})

it('should disable config-dot-notation when dot-notation is disabled', function () {
const jsonPath = path.resolve(__dirname, './fixtures/config_with_dot_notation.json')
const argv = parser(["--settings", jsonPath], {
config: ["settings"],
default: {
"hello.world": false,
parent: {
"foo.bar": false,
},
},
configuration: {
"config-dot-notation": true,
"dot-notation": false,
}
});

argv.should.have.property('a', 'a')
argv.should.have.property('nested').and.deep.equal({
b: 'b'
})
argv.should.have.property('hello.world').and.equal(true)
argv.should.have.property('parent').and.deep.equal({
"foo.bar": true
})
})

it('allows a custom parsing function to be provided', function () {
const jsPath = path.resolve(__dirname, './fixtures/config.txt')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
Expand Down