Skip to content

Commit e7b46c2

Browse files
snitin315anshumanv
andauthored
feat(webpack-cli): allow negative property for cli-flags (#1668)
* feat(webpack-cli): allow negative property for cli-flags * refactor: suggestion * chore: concat negatedFlags with options Co-authored-by: Anshuman Verma <anshu.av97@gmail.com>
1 parent 4d2f7f1 commit e7b46c2

File tree

4 files changed

+71
-68
lines changed

4 files changed

+71
-68
lines changed

packages/webpack-cli/__tests__/arg-parser.test.js

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,20 @@ const basicOptions = [
1717
type: Boolean,
1818
description: 'boolean flag',
1919
},
20-
{
21-
name: 'specific-bool',
22-
alias: 's',
23-
usage: '--specific-bool',
24-
type: Boolean,
25-
description: 'boolean flag',
26-
},
27-
{
28-
name: 'no-specific-bool',
29-
usage: '--no-specific-bool',
30-
type: Boolean,
31-
description: 'boolean flag',
32-
},
3320
{
3421
name: 'num-flag',
3522
usage: '--num-flag <value>',
3623
type: Number,
3724
description: 'number flag',
3825
},
26+
{
27+
name: 'neg-flag',
28+
alias: 'n',
29+
usage: '--neg-flag',
30+
type: Boolean,
31+
negative: true,
32+
description: 'boolean flag',
33+
},
3934
{
4035
name: 'string-flag',
4136
usage: '--string-flag <value>',
@@ -150,16 +145,6 @@ describe('arg-parser', () => {
150145
expect(warnMock.mock.calls.length).toEqual(0);
151146
});
152147

153-
it('parses specified negated boolean flag', () => {
154-
const res = argParser(basicOptions, ['--no-specific-bool'], true);
155-
expect(res.unknownArgs.length).toEqual(0);
156-
expect(res.opts).toEqual({
157-
specificBool: false,
158-
stringFlagWithDefault: 'default-value',
159-
});
160-
expect(warnMock.mock.calls.length).toEqual(0);
161-
});
162-
163148
it('parses multi type flag as Boolean', () => {
164149
const res = argParser(basicOptions, ['--multi-type'], true);
165150
expect(res.unknownArgs.length).toEqual(0);
@@ -180,37 +165,15 @@ describe('arg-parser', () => {
180165
expect(warnMock.mock.calls.length).toEqual(0);
181166
});
182167

183-
it('warns on usage of both flag and same negated flag, setting it to false', () => {
184-
const res = argParser(basicOptions, ['--specific-bool', '--no-specific-bool'], true);
185-
expect(res.unknownArgs.length).toEqual(0);
186-
expect(res.opts).toEqual({
187-
specificBool: false,
188-
stringFlagWithDefault: 'default-value',
189-
});
190-
expect(warnMock.mock.calls.length).toEqual(1);
191-
expect(warnMock.mock.calls[0][0]).toContain('You provided both --specific-bool and --no-specific-bool');
192-
});
193-
194-
it('warns on usage of both flag and same negated flag, setting it to true', () => {
195-
const res = argParser(basicOptions, ['--no-specific-bool', '--specific-bool'], true);
196-
expect(res.unknownArgs.length).toEqual(0);
197-
expect(res.opts).toEqual({
198-
specificBool: true,
199-
stringFlagWithDefault: 'default-value',
200-
});
201-
expect(warnMock.mock.calls.length).toEqual(1);
202-
expect(warnMock.mock.calls[0][0]).toContain('You provided both --specific-bool and --no-specific-bool');
203-
});
204-
205168
it('warns on usage of both flag alias and same negated flag, setting it to true', () => {
206-
const res = argParser(basicOptions, ['--no-specific-bool', '-s'], true);
169+
const res = argParser(basicOptions, ['--no-neg-flag', '-n'], true);
207170
expect(res.unknownArgs.length).toEqual(0);
208171
expect(res.opts).toEqual({
209-
specificBool: true,
172+
negFlag: true,
210173
stringFlagWithDefault: 'default-value',
211174
});
212175
expect(warnMock.mock.calls.length).toEqual(1);
213-
expect(warnMock.mock.calls[0][0]).toContain('You provided both -s and --no-specific-bool');
176+
expect(warnMock.mock.calls[0][0]).toContain('You provided both -n and --no-neg-flag');
214177
});
215178

216179
it('parses string flag using equals sign', () => {
@@ -286,4 +249,46 @@ describe('arg-parser', () => {
286249
expect(res.opts.stats).toEqual(true);
287250
expect(warnMock.mock.calls.length).toEqual(0);
288251
});
252+
253+
it('parses --neg-flag', () => {
254+
const res = argParser(basicOptions, ['--neg-flag'], true);
255+
expect(res.unknownArgs.length).toEqual(0);
256+
expect(res.opts).toEqual({
257+
negFlag: true,
258+
stringFlagWithDefault: 'default-value',
259+
});
260+
expect(warnMock.mock.calls.length).toEqual(0);
261+
});
262+
263+
it('parses --no-neg-flag', () => {
264+
const res = argParser(basicOptions, ['--no-neg-flag'], true);
265+
expect(res.unknownArgs.length).toEqual(0);
266+
expect(res.opts).toEqual({
267+
negFlag: false,
268+
stringFlagWithDefault: 'default-value',
269+
});
270+
expect(warnMock.mock.calls.length).toEqual(0);
271+
});
272+
273+
it('warns on usage of both --neg and --no-neg flag, setting it to false', () => {
274+
const res = argParser(basicOptions, ['--neg-flag', '--no-neg-flag'], true);
275+
expect(res.unknownArgs.length).toEqual(0);
276+
expect(res.opts).toEqual({
277+
negFlag: false,
278+
stringFlagWithDefault: 'default-value',
279+
});
280+
expect(warnMock.mock.calls.length).toEqual(1);
281+
expect(warnMock.mock.calls[0][0]).toContain('You provided both --neg-flag and --no-neg-flag');
282+
});
283+
284+
it('warns on usage of both flag and same negated flag, setting it to true', () => {
285+
const res = argParser(basicOptions, ['--no-neg-flag', '--neg-flag'], true);
286+
expect(res.unknownArgs.length).toEqual(0);
287+
expect(res.opts).toEqual({
288+
negFlag: true,
289+
stringFlagWithDefault: 'default-value',
290+
});
291+
expect(warnMock.mock.calls.length).toEqual(1);
292+
expect(warnMock.mock.calls[0][0]).toContain('You provided both --neg-flag and --no-neg-flag');
293+
});
289294
});

packages/webpack-cli/lib/groups/HelpGroup.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ class HelpGroup {
8484
const { underline, bold } = chalk.white;
8585
const o = (s) => chalk.keyword('orange')(s);
8686
const options = require('../utils/cli-flags');
87+
const negatedFlags = options.core
88+
.filter((flag) => flag.negative)
89+
.reduce((allFlags, flag) => {
90+
return [...allFlags, { name: `no-${flag.name}`, description: `Negates ${flag.name}`, type: Boolean }];
91+
}, []);
8792
const title = bold('⬡ ') + underline('webpack') + bold(' ⬡');
8893
const desc = 'The build tool for modern web applications';
8994
const websitelink = ' ' + underline('https://webpack.js.org');
@@ -110,10 +115,12 @@ class HelpGroup {
110115
},
111116
{
112117
header: 'Options',
113-
optionList: options.core.map((e) => {
114-
if (e.type.length > 1) e.type = e.type[0];
115-
return e;
116-
}),
118+
optionList: options.core
119+
.map((e) => {
120+
if (e.type.length > 1) e.type = e.type[0];
121+
return e;
122+
})
123+
.concat(negatedFlags),
117124
},
118125
]);
119126
return {

packages/webpack-cli/lib/utils/arg-parser.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ function argParser(options, args, argsOnly = false, name = '', helpFunction = un
7878
parserInstance.option(flagsWithType, option.description, option.type, option.defaultValue).action(() => {});
7979
}
8080
}
81+
if (option.negative) {
82+
// commander requires explicitly adding the negated version of boolean flags
83+
const negatedFlag = `--no-${option.name}`;
84+
parserInstance.option(negatedFlag, `negates ${option.name}`).action(() => {});
85+
}
8186

8287
return parserInstance;
8388
}, parser);

packages/webpack-cli/lib/utils/cli-flags.js

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -155,18 +155,11 @@ module.exports = {
155155
usage: '--hot',
156156
alias: 'h',
157157
type: Boolean,
158+
negative: true,
158159
group: ADVANCED_GROUP,
159160
description: 'Enables Hot Module Replacement',
160161
link: 'https://webpack.js.org/concepts/hot-module-replacement/',
161162
},
162-
{
163-
name: 'no-hot',
164-
usage: '--no-hot',
165-
type: Boolean,
166-
group: ADVANCED_GROUP,
167-
description: 'Disables Hot Module Replacement',
168-
link: 'https://webpack.js.org/concepts/hot-module-replacement/',
169-
},
170163
{
171164
name: 'sourcemap',
172165
usage: '--sourcemap <sourcemap | eval>',
@@ -242,17 +235,10 @@ module.exports = {
242235
usage: '--stats <value>',
243236
type: [String, Boolean],
244237
group: DISPLAY_GROUP,
238+
negative: true,
245239
description: 'It instructs webpack on how to treat the stats e.g. verbose',
246240
link: 'https://webpack.js.org/configuration/stats/#stats',
247241
},
248-
{
249-
name: 'no-stats',
250-
usage: '--no-stats',
251-
type: Boolean,
252-
group: DISPLAY_GROUP,
253-
description: 'Disables stats output',
254-
link: 'https://webpack.js.org/configuration/stats/#stats',
255-
},
256242
{
257243
name: 'verbose',
258244
usage: '--verbose',

0 commit comments

Comments
 (0)