Skip to content

Commit

Permalink
Added config-dot-notation for config files
Browse files Browse the repository at this point in the history
Default is `false`
  • Loading branch information
Drarig29 committed Aug 16, 2022
1 parent 3aba24c commit c14a08d
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 1 deletion.
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
15 changes: 15 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,20 @@ export class YargsParser {
const value = config[key]
const fullKey = prev ? prev + '.' + key : key

// if the key contains dots and we don't want to split it into objects,
// we ignore the CLI precedence because semi-nested dot-notation isn't supported.
//
// example of semi-nested dot-notation:
// we might want to have `{ parent: { 'foo.bar': true } }`,
// but we would need to address it with parent.foo.bar and
// this would result in `{ 'parent.foo.bar': true }`
// or `{ 'parent': { 'foo': { 'bar': true } } }`
// depending on `configuration['dot-notation']`.
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
}
}
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

0 comments on commit c14a08d

Please sign in to comment.