From 173b5a602d135aab745e4221f6da6379391d8961 Mon Sep 17 00:00:00 2001 From: Ivan Krivonos Date: Fri, 30 Oct 2026 16:06:58 +0300 Subject: [PATCH] fix(@angular/cli): allow schematic arguments named help The initial argv parse treated bare `help` as the global help flag, so commands like `ng generate m help` showed help instead of running the schematic. Fixes angular/angular-cli#25705 --- .../cli/src/command-builder/command-runner.ts | 24 ++++++++++-- .../command-builder/command-runner_spec.ts | 38 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 packages/angular/cli/src/command-builder/command-runner_spec.ts diff --git a/packages/angular/cli/src/command-builder/command-runner.ts b/packages/angular/cli/src/command-builder/command-runner.ts index 62de365dee99..c7ae4188bc12 100644 --- a/packages/angular/cli/src/command-builder/command-runner.ts +++ b/packages/angular/cli/src/command-builder/command-runner.ts @@ -33,23 +33,41 @@ import { import { jsonHelpUsage } from './utilities/json-help'; import { createNormalizeOptionsMiddleware } from './utilities/normalize-options-middleware'; -export async function runCommand(args: string[], logger: logging.Logger): Promise { +export function parseInitialCommandArguments(args: string[]) { const { $0, _, - help = false, dryRun = false, jsonHelp = false, getYargsCompletions = false, ...rest } = yargsParser(args, { - boolean: ['help', 'json-help', 'get-yargs-completions', 'dry-run'], + // Do not treat bare `help` as the help flag; it can be a schematic argument (e.g. `ng g m help`). + boolean: ['json-help', 'get-yargs-completions', 'dry-run'], alias: { 'collection': 'c' }, }); + const help = + jsonHelp || args.some((arg) => arg === '--help' || arg === '-h' || arg.startsWith('--help=')); + // When `getYargsCompletions` is true the scriptName 'ng' at index 0 is not removed. const positional = getYargsCompletions ? _.slice(1) : _; + return { + $0, + positional, + help, + dryRun, + jsonHelp, + getYargsCompletions, + rest, + }; +} + +export async function runCommand(args: string[], logger: logging.Logger): Promise { + const { positional, help, dryRun, jsonHelp, getYargsCompletions, rest } = + parseInitialCommandArguments(args); + let workspace: AngularWorkspace | undefined; let globalConfiguration: AngularWorkspace; try { diff --git a/packages/angular/cli/src/command-builder/command-runner_spec.ts b/packages/angular/cli/src/command-builder/command-runner_spec.ts new file mode 100644 index 000000000000..7b7a2e2bb2fc --- /dev/null +++ b/packages/angular/cli/src/command-builder/command-runner_spec.ts @@ -0,0 +1,38 @@ +/** + * @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.dev/license + */ + +import { parseInitialCommandArguments } from './command-runner'; + +describe('parseInitialCommandArguments', () => { + it('should not treat a schematic argument named help as the help flag', () => { + const { help, positional } = parseInitialCommandArguments(['generate', 'm', 'help']); + + expect(help).toBeFalse(); + expect(positional).toEqual(['generate', 'm', 'help']); + }); + + it('should treat --help as the help flag', () => { + const { help, positional } = parseInitialCommandArguments(['generate', 'm', '--help']); + + expect(help).toBeTrue(); + expect(positional).toEqual(['generate', 'm']); + }); + + it('should treat -h as the help flag', () => { + const { help } = parseInitialCommandArguments(['generate', '-h']); + + expect(help).toBeTrue(); + }); + + it('should treat --json-help as the help flag', () => { + const { help, jsonHelp } = parseInitialCommandArguments(['generate', '--json-help']); + + expect(jsonHelp).toBeTrue(); + expect(help).toBeTrue(); + }); +});