From 00d27bb640fe5248c60be3de2fa2adf9df12af3a Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sat, 4 Jul 2020 14:27:44 +0530 Subject: [PATCH] feat(webpack-cli): allow negative property for cli-flags --- .../webpack-cli/__tests__/arg-parser.test.js | 75 ++++++++++--------- packages/webpack-cli/lib/utils/arg-parser.js | 9 ++- packages/webpack-cli/lib/utils/cli-flags.js | 2 + 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/packages/webpack-cli/__tests__/arg-parser.test.js b/packages/webpack-cli/__tests__/arg-parser.test.js index b11d87fbb60..4dd9101e6e2 100644 --- a/packages/webpack-cli/__tests__/arg-parser.test.js +++ b/packages/webpack-cli/__tests__/arg-parser.test.js @@ -17,25 +17,20 @@ const basicOptions = [ type: Boolean, description: 'boolean flag', }, - { - name: 'specific-bool', - alias: 's', - usage: '--specific-bool', - type: Boolean, - description: 'boolean flag', - }, - { - name: 'no-specific-bool', - usage: '--no-specific-bool', - type: Boolean, - description: 'boolean flag', - }, { name: 'num-flag', usage: '--num-flag ', type: Number, description: 'number flag', }, + { + name: 'neg-flag', + alias: 'n', + usage: '--neg-flag', + type: Boolean, + negative: true, + description: 'boolean flag', + }, { name: 'string-flag', usage: '--string-flag ', @@ -150,67 +145,77 @@ describe('arg-parser', () => { expect(warnMock.mock.calls.length).toEqual(0); }); - it('parses specified negated boolean flag', () => { - const res = argParser(basicOptions, ['--no-specific-bool'], true); + it('parses --neg-flag', () => { + const res = argParser(basicOptions, ['--neg-flag'], true); expect(res.unknownArgs.length).toEqual(0); expect(res.opts).toEqual({ - specificBool: false, + negFlag: true, stringFlagWithDefault: 'default-value', }); expect(warnMock.mock.calls.length).toEqual(0); }); - it('parses multi type flag as Boolean', () => { - const res = argParser(basicOptions, ['--multi-type'], true); + it('parses --no-neg-flag', () => { + const res = argParser(basicOptions, ['--no-neg-flag'], true); expect(res.unknownArgs.length).toEqual(0); expect(res.opts).toEqual({ - multiType: true, + negFlag: false, stringFlagWithDefault: 'default-value', }); expect(warnMock.mock.calls.length).toEqual(0); }); - it('parses multi type flag as String', () => { - const res = argParser(basicOptions, ['--multi-type', 'value'], true); + it('warns on usage of both --neg and --no-neg flag, setting it to false', () => { + const res = argParser(basicOptions, ['--neg-flag', '--no-neg-flag'], true); expect(res.unknownArgs.length).toEqual(0); expect(res.opts).toEqual({ - multiType: 'value', + negFlag: false, stringFlagWithDefault: 'default-value', }); - expect(warnMock.mock.calls.length).toEqual(0); + expect(warnMock.mock.calls.length).toEqual(1); + expect(warnMock.mock.calls[0][0]).toContain('You provided both --neg-flag and --no-neg-flag'); }); - it('warns on usage of both flag and same negated flag, setting it to false', () => { - const res = argParser(basicOptions, ['--specific-bool', '--no-specific-bool'], true); + it('warns on usage of both flag and same negated flag, setting it to true', () => { + const res = argParser(basicOptions, ['--no-neg-flag', '--neg-flag'], true); expect(res.unknownArgs.length).toEqual(0); expect(res.opts).toEqual({ - specificBool: false, + negFlag: true, stringFlagWithDefault: 'default-value', }); expect(warnMock.mock.calls.length).toEqual(1); - expect(warnMock.mock.calls[0][0]).toContain('You provided both --specific-bool and --no-specific-bool'); + expect(warnMock.mock.calls[0][0]).toContain('You provided both --neg-flag and --no-neg-flag'); }); - it('warns on usage of both flag and same negated flag, setting it to true', () => { - const res = argParser(basicOptions, ['--no-specific-bool', '--specific-bool'], true); + it('parses multi type flag as Boolean', () => { + const res = argParser(basicOptions, ['--multi-type'], true); expect(res.unknownArgs.length).toEqual(0); expect(res.opts).toEqual({ - specificBool: true, + multiType: true, stringFlagWithDefault: 'default-value', }); - expect(warnMock.mock.calls.length).toEqual(1); - expect(warnMock.mock.calls[0][0]).toContain('You provided both --specific-bool and --no-specific-bool'); + expect(warnMock.mock.calls.length).toEqual(0); + }); + + it('parses multi type flag as String', () => { + const res = argParser(basicOptions, ['--multi-type', 'value'], true); + expect(res.unknownArgs.length).toEqual(0); + expect(res.opts).toEqual({ + multiType: 'value', + stringFlagWithDefault: 'default-value', + }); + expect(warnMock.mock.calls.length).toEqual(0); }); it('warns on usage of both flag alias and same negated flag, setting it to true', () => { - const res = argParser(basicOptions, ['--no-specific-bool', '-s'], true); + const res = argParser(basicOptions, ['--no-neg-flag', '-n'], true); expect(res.unknownArgs.length).toEqual(0); expect(res.opts).toEqual({ - specificBool: true, + negFlag: true, stringFlagWithDefault: 'default-value', }); expect(warnMock.mock.calls.length).toEqual(1); - expect(warnMock.mock.calls[0][0]).toContain('You provided both -s and --no-specific-bool'); + expect(warnMock.mock.calls[0][0]).toContain('You provided both -n and --no-neg-flag'); }); it('parses string flag using equals sign', () => { diff --git a/packages/webpack-cli/lib/utils/arg-parser.js b/packages/webpack-cli/lib/utils/arg-parser.js index 0598d33bb0d..1adf7c80d68 100644 --- a/packages/webpack-cli/lib/utils/arg-parser.js +++ b/packages/webpack-cli/lib/utils/arg-parser.js @@ -62,7 +62,14 @@ function argParser(options, args, argsOnly = false, name = '', helpFunction = un if (option.type === Boolean || option.type === String) { if (!option.multiple) { // Prevent default behavior for standalone options - parserInstance.option(flagsWithType, option.description, option.defaultValue).action(() => {}); + if (!option.name.startsWith('no-')) { + parserInstance.option(flagsWithType, option.description, option.defaultValue).action(() => {}); + } + if (option.negative) { + // commander requires explicitly adding the negated version of boolean flags + const negatedFlag = `--no-${option.name}`; + parserInstance.option(negatedFlag, `negates ${option.name}`).action(() => {}); + } } else { const multiArg = (value, previous = []) => previous.concat([value]); parserInstance.option(flagsWithType, option.description, multiArg, option.defaultValue).action(() => {}); diff --git a/packages/webpack-cli/lib/utils/cli-flags.js b/packages/webpack-cli/lib/utils/cli-flags.js index a19529c5963..09ee360ea19 100644 --- a/packages/webpack-cli/lib/utils/cli-flags.js +++ b/packages/webpack-cli/lib/utils/cli-flags.js @@ -155,6 +155,7 @@ module.exports = { usage: '--hot', alias: 'h', type: Boolean, + negative: true, group: ADVANCED_GROUP, description: 'Enables Hot Module Replacement', link: 'https://webpack.js.org/concepts/hot-module-replacement/', @@ -242,6 +243,7 @@ module.exports = { usage: '--stats ', type: [String, Boolean], group: DISPLAY_GROUP, + negative: true, description: 'It instructs webpack on how to treat the stats e.g. verbose', link: 'https://webpack.js.org/configuration/stats/#stats', },