Skip to content

Commit 3e9705f

Browse files
committed
feat(@angular/cli): add warning for overriding flags in arguments
Fixes angular#12948
1 parent f7ac352 commit 3e9705f

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

packages/angular/cli/models/parser.ts

+24-10
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ function _coerceType(str: string | undefined, type: OptionType, v?: Value): Valu
6363
}
6464

6565
case OptionType.Array:
66-
return Array.isArray(v) ? v.concat(str || '') : [str || ''];
66+
return Array.isArray(v)
67+
? v.concat(str || '')
68+
: v === undefined
69+
? [str || '']
70+
: [v + '', str || ''];
6771

6872
default:
6973
return undefined;
@@ -119,14 +123,14 @@ function _removeLeadingDashes(key: string): string {
119123
function _assignOption(
120124
arg: string,
121125
args: string[],
122-
{ options, parsedOptions, leftovers, ignored, errors, deprecations }: {
126+
{ options, parsedOptions, leftovers, ignored, errors, warnings }: {
123127
options: Option[],
124128
parsedOptions: Arguments,
125129
positionals: string[],
126130
leftovers: string[],
127131
ignored: string[],
128132
errors: string[],
129-
deprecations: string[],
133+
warnings: string[],
130134
},
131135
) {
132136
const from = arg.startsWith('--') ? 2 : 1;
@@ -188,11 +192,21 @@ function _assignOption(
188192
} else {
189193
const v = _coerce(value, option, parsedOptions[option.name]);
190194
if (v !== undefined) {
191-
parsedOptions[option.name] = v;
195+
if (parsedOptions[option.name] !== v) {
196+
if (parsedOptions[option.name] !== undefined) {
197+
warnings.push(
198+
`Option ${JSON.stringify(option.name)} was already specified with value `
199+
+ `${JSON.stringify(parsedOptions[option.name])}. The new value ${JSON.stringify(v)} `
200+
+ `will override it.`,
201+
);
202+
}
203+
204+
parsedOptions[option.name] = v;
192205

193-
if (option.deprecated !== undefined && option.deprecated !== false) {
194-
deprecations.push(`Option ${JSON.stringify(option.name)} is deprecated${
206+
if (option.deprecated !== undefined && option.deprecated !== false) {
207+
warnings.push(`Option ${JSON.stringify(option.name)} is deprecated${
195208
typeof option.deprecated == 'string' ? ': ' + option.deprecated : ''}.`);
209+
}
196210
}
197211
} else {
198212
let error = `Argument ${key} could not be parsed using value ${JSON.stringify(value)}.`;
@@ -285,9 +299,9 @@ export function parseArguments(
285299

286300
const ignored: string[] = [];
287301
const errors: string[] = [];
288-
const deprecations: string[] = [];
302+
const warnings: string[] = [];
289303

290-
const state = { options, parsedOptions, positionals, leftovers, ignored, errors, deprecations };
304+
const state = { options, parsedOptions, positionals, leftovers, ignored, errors, warnings };
291305

292306
for (let arg = args.shift(); arg !== undefined; arg = args.shift()) {
293307
if (arg == '--') {
@@ -369,8 +383,8 @@ export function parseArguments(
369383
parsedOptions['--'] = [...positionals, ...leftovers];
370384
}
371385

372-
if (deprecations.length > 0 && logger) {
373-
deprecations.forEach(message => logger.warn(message));
386+
if (warnings.length > 0 && logger) {
387+
warnings.forEach(message => logger.warn(message));
374388
}
375389

376390
if (errors.length > 0) {

packages/angular/cli/models/parser_spec.ts

+37
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*
88
*/
9+
// tslint:disable:no-global-tslint-disable no-big-function
910
import { logging } from '@angular-devkit/core';
1011
import { Arguments, Option, OptionType } from './interface';
1112
import { ParseArgumentException, parseArguments } from './parser';
@@ -64,6 +65,10 @@ describe('parseArguments', () => {
6465
'--str=false val1 val2': { str: 'false', p1: 'val1', p2: 'val2' },
6566
'--str=false val1 val2 --num1': { str: 'false', p1: 'val1', p2: 'val2', '--': ['--num1'] },
6667
'--str=false val1 --num1 val2': { str: 'false', p1: 'val1', '--': ['--num1', 'val2'] },
68+
'--bool --bool=false': { bool: false },
69+
'--bool --bool=false --bool': { bool: true },
70+
'--num=1 --num=2 --num=3': { num: 3 },
71+
'--str=1 --str=2 --str=3': { str: '3' },
6772
'val1 --num=1 val2': { num: 1, p1: 'val1', p2: 'val2' },
6873
'--p1=val1 --num=1 val2': { num: 1, p1: 'val1', p2: 'val2' },
6974
'--p1=val1 --num=1 --p2=val2 val3': { num: 1, p1: 'val1', p2: 'val2', '--': ['val3'] },
@@ -74,6 +79,7 @@ describe('parseArguments', () => {
7479
],
7580
'--bool val1 --etc --num=1 val2 --v': { bool: true, num: 1, p1: 'val1', p2: 'val2',
7681
'--': ['--etc', '--v'] },
82+
'--arr=a d': { arr: ['a'], p1: 'd' },
7783
'--arr=a --arr=b --arr c d': { arr: ['a', 'b', 'c'], p1: 'd' },
7884
'--arr=1 --arr --arr c d': { arr: ['1', '', 'c'], p1: 'd' },
7985
'--arr=1 --arr --arr c d e': { arr: ['1', '', 'c'], p1: 'd', p2: 'e' },
@@ -197,4 +203,35 @@ describe('parseArguments', () => {
197203
expect(messages[1]).toMatch(/\bABCD\b/);
198204
messages.shift();
199205
});
206+
207+
it('handles a flag being added multiple times', () => {
208+
const options = [
209+
{ name: 'bool', aliases: [], type: OptionType.Boolean, description: '' },
210+
];
211+
212+
const logger = new logging.Logger('');
213+
const messages: string[] = [];
214+
215+
logger.subscribe(entry => messages.push(entry.message));
216+
217+
let result = parseArguments(['--bool'], options, logger);
218+
expect(result).toEqual({ bool: true });
219+
expect(messages).toEqual([]);
220+
221+
result = parseArguments(['--bool', '--bool'], options, logger);
222+
expect(result).toEqual({ bool: true });
223+
expect(messages).toEqual([]);
224+
225+
result = parseArguments(['--bool', '--bool=false'], options, logger);
226+
expect(result).toEqual({ bool: false });
227+
expect(messages.length).toEqual(1);
228+
expect(messages[0]).toMatch(/\bbool\b.*\btrue\b.*\bfalse\b/);
229+
messages.shift();
230+
231+
result = parseArguments(['--bool', '--bool=false', '--bool=false'], options, logger);
232+
expect(result).toEqual({ bool: false });
233+
expect(messages.length).toEqual(1);
234+
expect(messages[0]).toMatch(/\bbool\b.*\btrue\b.*\bfalse\b/);
235+
messages.shift();
236+
});
200237
});

0 commit comments

Comments
 (0)