Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

Commit

Permalink
fix: ignore defaulted flags for exclusivity
Browse files Browse the repository at this point in the history
  • Loading branch information
elbandito authored Mar 15, 2019
1 parent 39bf6cc commit 1dfe62a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type Metadata = {
flags: { [key: string]: MetadataFlag }
}

type MetadataFlag = {
setFromDefault?: boolean
}
10 changes: 9 additions & 1 deletion src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Arg} from './args'
import Deps from './deps'
import * as Errors from './errors'
import * as Flags from './flags'
import {Metadata} from './metadata'
import * as Util from './util'

const m = Deps()
Expand All @@ -26,7 +27,8 @@ export type ParserOutput<TFlags extends OutputFlags<any>, TArgs extends OutputAr
flags: TFlags
args: TArgs
argv: string[]
raw: ParsingToken[]
raw: ParsingToken[],
metadata: Metadata
}

export type ArgToken = { type: 'arg'; input: string }
Expand All @@ -47,13 +49,16 @@ export class Parser<T extends ParserInput, TFlags extends OutputFlags<T['flags']
private readonly raw: ParsingToken[] = []
private readonly booleanFlags: { [k: string]: Flags.IBooleanFlag<any> }
private readonly context: any
private readonly metaData: any
private currentFlag?: Flags.IOptionFlag<any>

constructor(private readonly input: T) {
const {pickBy} = m.util
this.context = input.context || {}
this.argv = input.argv.slice(0)
this._setNames()
this.booleanFlags = pickBy(input.flags, f => f.type === 'boolean') as any
this.metaData = {}
}

public parse() {
Expand Down Expand Up @@ -145,6 +150,7 @@ export class Parser<T extends ParserInput, TFlags extends OutputFlags<T['flags']
argv,
flags,
raw: this.raw,
metadata: this.metaData
}
}

Expand All @@ -159,6 +165,7 @@ export class Parser<T extends ParserInput, TFlags extends OutputFlags<T['flags']

private _flags(): TFlags {
const flags = {} as any
this.metaData.flags = {} as any
for (const token of this._flagTokens) {
const flag = this.input.flags[token.flag]
if (!flag) throw new m.errors.CLIError(`Unexpected flag ${token.flag}`)
Expand Down Expand Up @@ -191,6 +198,7 @@ export class Parser<T extends ParserInput, TFlags extends OutputFlags<T['flags']
if (input) flags[k] = flag.parse(input, this.context)
}
if (!(k in flags) && flag.default !== undefined) {
this.metaData.flags[k] = {setFromDefault: true}
if (typeof flag.default === 'function') {
flags[k] = flag.default({options: flag, flags, ...this.context})
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export function validate(parse: { input: ParserInput; output: ParserOutput<any,
}
}
for (let also of flag.exclusive || []) {
// do not enforce exclusivity for flags that were defaulted
if (parse.output.metadata.flags[also] && parse.output.metadata.flags[also].setFromDefault) continue
if (parse.output.metadata.flags[name] && parse.output.metadata.flags[name].setFromDefault) continue
if (parse.output.flags[also]) {
throw new CLIError(`--${also}= cannot also be provided when using --${name}=`)
}
Expand Down
15 changes: 15 additions & 0 deletions test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,21 @@ See more help with --help`)
})

describe('defaults', () => {
it('generates metadata for defaults', () => {
const out = parse(['-n', 'heroku'], {
flags: {
name: flags.string({
char: 'n'
}),
startup: flags.string({
char: 's',
default: 'apero'
}),
},
})
expect(out.metadata.flags).to.deep.equal({startup: {setFromDefault: true}})
})

it('defaults', () => {
const out = parse([], {
args: [{name: 'baz', default: 'BAZ'}],
Expand Down
80 changes: 80 additions & 0 deletions test/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {expect} from 'chai'

import {validate} from '../src/validate'

describe('validate', () => {
const input = {
argv: [],
flags: {
dinner: {
description: 'what you want to eat for dinner',
input: [],
name: 'dinner',
exclusive: ['dessert'],
},
dessert: {
description: 'what you want to eat for dessert',
default: 'cheesecake',
input: [],
name: 'dessert',
exclusive: [],
}
},
args: [],
strict: true,
context: {},
'--': true
}

it('enforces exclusivity for flags', () => {
const output = {
args: {},
argv: [],
flags: {
dinner: 'pizza',
dessert: 'cheesecake'
},
raw: [{
type: 'flag',
flag: 'dinner',
input: 'pizza'
}],
metadata: {
flags: {
dessert: {
setFromDefault: false
}
}
}
}

// @ts-ignore
expect(validate.bind({input, output})).to.throw()
})

it('ignores exclusivity for defaulted flags', () => {
const output = {
args: {},
argv: [],
flags: {
dinner: 'pizza',
dessert: 'cheesecake'
},
raw: [{
type: 'flag',
flag: 'dinner',
input: 'pizza'
}],
metadata: {
flags: {
dessert: {
setFromDefault: true
}
}
}
}

// @ts-ignore
validate({input, output})
})
})

0 comments on commit 1dfe62a

Please sign in to comment.