diff --git a/packages/breadc/src/parser/parser.ts b/packages/breadc/src/parser/parser.ts index f269f238..901d659e 100644 --- a/packages/breadc/src/parser/parser.ts +++ b/packages/breadc/src/parser/parser.ts @@ -36,6 +36,7 @@ export function parseOption( ): TreeNode | false { const o = token.option(); const [key, rawV] = o.split('='); + if (context.options.has(key)) { const option = context.options.get(key)!; const name = camelCase(option.name); @@ -45,7 +46,17 @@ export function parseOption( return option.parse(cursor, token, context); } else if (option.type === 'boolean') { // Parse boolean option - context.result.options[name] = !key.startsWith('no-') ? true : false; + const negative = key.startsWith('no-'); + if ( + rawV === undefined || + ['true', 'yes', 't', 'y'].includes(rawV.toLowerCase()) + ) { + context.result.options[name] = !negative ? true : false; + } else if (['false', 'no', 'f', 'n'].includes(rawV.toLowerCase())) { + context.result.options[name] = !negative ? false : true; + } else { + throw new ParseError(`Unexpected value ${rawV} for ${option.format}`); + } } else if (option.type === 'string') { // Parse string option if (rawV !== undefined) { diff --git a/packages/breadc/test/parse.test.ts b/packages/breadc/test/parse.test.ts index 481b07cc..682f10b9 100644 --- a/packages/breadc/test/parse.test.ts +++ b/packages/breadc/test/parse.test.ts @@ -491,6 +491,82 @@ describe('Option Parser', () => { `); }); + it('should parse boolean option with value', async () => { + const cli = breadc('cli'); + cli.option('--open'); + cli.command('').action((o) => o); + + expect(await cli.run(['--open=true'])).toMatchInlineSnapshot(` + { + "--": [], + "open": true, + } + `); + + expect(await cli.run(['--open=YES'])).toMatchInlineSnapshot(` + { + "--": [], + "open": true, + } + `); + + expect(await cli.run(['--open=T'])).toMatchInlineSnapshot(` + { + "--": [], + "open": true, + } + `); + + expect(await cli.run(['--open=y'])).toMatchInlineSnapshot(` + { + "--": [], + "open": true, + } + `); + + expect(await cli.run(['--open=false'])).toMatchInlineSnapshot(` + { + "--": [], + "open": false, + } + `); + + expect(await cli.run(['--open=No'])).toMatchInlineSnapshot(` + { + "--": [], + "open": false, + } + `); + + expect(await cli.run(['--open=f'])).toMatchInlineSnapshot(` + { + "--": [], + "open": false, + } + `); + + expect(await cli.run(['--open=N'])).toMatchInlineSnapshot(` + { + "--": [], + "open": false, + } + `); + + expect(await cli.run(['--no-open=true'])).toMatchInlineSnapshot(` + { + "--": [], + "open": false, + } + `); + + expect(await cli.run(['--no-open=false'])).toMatchInlineSnapshot(` + { + "--": [], + "open": true, + } + `); + }); + it('should parse string option', async () => { const cli = breadc('cli'); cli.option('--flag');