Skip to content

Commit ff4eba3

Browse files
alan-agius4dgp1130
authored andcommitted
fix(@angular/cli): handle duplicate arguments
With this change we add a Yargs middleware that normalizes non Array options when the argument has been provided multiple times. By default, when an option is non array and it is provided multiple times in the command line, yargs will not override it's value but instead it will be changed to an array unless `duplicate-arguments-array` is disabled. But this option also have an effect on real array options which isn't desired. See: yargs/yargs-parser#163 (comment) Closes #22956
1 parent d87b858 commit ff4eba3

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

packages/angular/cli/src/command-builder/command-runner.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { PackageManagerUtils } from '../utilities/package-manager';
3333
import { CommandContext, CommandModuleError, CommandScope } from './command-module';
3434
import { addCommandModuleToYargs, demandCommandFailureMessage } from './utilities/command';
3535
import { jsonHelpUsage } from './utilities/json-help';
36+
import { normalizeOptionsMiddleware } from './utilities/normalize-options-middleware';
3637

3738
const COMMANDS = [
3839
VersionCommandModule,
@@ -145,6 +146,7 @@ export async function runCommand(args: string[], logger: logging.Logger): Promis
145146
})
146147
.demandCommand(1, demandCommandFailureMessage)
147148
.recommendCommands()
149+
.middleware(normalizeOptionsMiddleware)
148150
.version(false)
149151
.showHelpOnFail(false)
150152
.strict()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import * as yargs from 'yargs';
10+
11+
/**
12+
* A Yargs middleware that normalizes non Array options when the argument has been provided multiple times.
13+
*
14+
* By default, when an option is non array and it is provided multiple times in the command line, yargs
15+
* will not override it's value but instead it will be changed to an array unless `duplicate-arguments-array` is disabled.
16+
* But this option also have an effect on real array options which isn't desired.
17+
*
18+
* See: https://github.com/yargs/yargs-parser/pull/163#issuecomment-516566614
19+
*/
20+
export function normalizeOptionsMiddleware(args: yargs.Arguments): void {
21+
// `getOptions` is not included in the types even though it's public API.
22+
// https://github.com/yargs/yargs/issues/2098
23+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
24+
const { array } = (yargs as any).getOptions();
25+
const arrayOptions = new Set(array);
26+
27+
for (const [key, value] of Object.entries(args)) {
28+
if (key !== '_' && Array.isArray(value) && !arrayOptions.has(key)) {
29+
const newValue = value.pop();
30+
// eslint-disable-next-line no-console
31+
console.warn(
32+
`Option '${key}' has been specified multiple times. The value '${newValue}' will be used.`,
33+
);
34+
args[key] = newValue;
35+
}
36+
}
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { ng } from '../../utils/process';
2+
import { expectFileToExist } from '../../utils/fs';
3+
4+
export default async function () {
5+
const { stderr } = await ng(
6+
'generate',
7+
'component',
8+
'test-component',
9+
'--style=scss',
10+
'--style=sass',
11+
);
12+
13+
const warningMatch = `Option 'style' has been specified multiple times. The value 'sass' will be used`;
14+
if (!stderr.includes(warningMatch)) {
15+
throw new Error(`Expected stderr to contain: "${warningMatch}".`);
16+
}
17+
18+
await expectFileToExist('src/app/test-component/test-component.component.sass');
19+
}

0 commit comments

Comments
 (0)