Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(@angular/cli): handle duplicate arguments #22966

Merged
merged 1 commit into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/angular/cli/src/command-builder/command-runner.ts
Expand Up @@ -33,6 +33,7 @@ import { PackageManagerUtils } from '../utilities/package-manager';
import { CommandContext, CommandModuleError, CommandScope } from './command-module';
import { addCommandModuleToYargs, demandCommandFailureMessage } from './utilities/command';
import { jsonHelpUsage } from './utilities/json-help';
import { normalizeOptionsMiddleware } from './utilities/normalize-options-middleware';

const COMMANDS = [
VersionCommandModule,
Expand Down Expand Up @@ -145,6 +146,7 @@ export async function runCommand(args: string[], logger: logging.Logger): Promis
})
.demandCommand(1, demandCommandFailureMessage)
.recommendCommands()
.middleware(normalizeOptionsMiddleware)
.version(false)
.showHelpOnFail(false)
.strict()
Expand Down
@@ -0,0 +1,37 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import * as yargs from 'yargs';

/**
* 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: https://github.com/yargs/yargs-parser/pull/163#issuecomment-516566614
*/
export function normalizeOptionsMiddleware(args: yargs.Arguments): void {
// `getOptions` is not included in the types even though it's public API.
// https://github.com/yargs/yargs/issues/2098
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { array } = (yargs as any).getOptions();
const arrayOptions = new Set(array);

for (const [key, value] of Object.entries(args)) {
if (key !== '_' && Array.isArray(value) && !arrayOptions.has(key)) {
clydin marked this conversation as resolved.
Show resolved Hide resolved
const newValue = value.pop();
// eslint-disable-next-line no-console
console.warn(
`Option '${key}' has been specified multiple times. The value '${newValue}' will be used.`,
);
args[key] = newValue;
}
}
}
19 changes: 19 additions & 0 deletions tests/legacy-cli/e2e/tests/misc/duplicate-command-line-option.ts
@@ -0,0 +1,19 @@
import { ng } from '../../utils/process';
import { expectFileToExist } from '../../utils/fs';

export default async function () {
const { stderr } = await ng(
'generate',
'component',
'test-component',
'--style=scss',
'--style=sass',
);

const warningMatch = `Option 'style' has been specified multiple times. The value 'sass' will be used`;
if (!stderr.includes(warningMatch)) {
throw new Error(`Expected stderr to contain: "${warningMatch}".`);
}

await expectFileToExist('src/app/test-component/test-component.component.sass');
}