Skip to content

Command line arguments fail to override --flags-dir values when flag has short/char form but long form is used #3486

@jon-freed

Description

@jon-freed

Summary

When using --flags-dir, command line arguments should override values from the flags directory for single-value flags (as documented in PR #1536). This works correctly in most cases, but fails when:

  1. A flag has a short/char form defined (e.g., -o for --target-org)
  2. The user specifies the long form on the command line (e.g., --target-org my-org)
  3. A file exists in the flags-dir for that flag

In this scenario, the flags-dir value is incorrectly appended instead of being overridden.

Steps To Reproduce

See the automated tests in the accompanying PR: salesforcecli/cli#2554

The PR includes 14 test scenarios covering all combinations of flag types and short/char usage. The 5 scenarios that fail when the bug is present are:

# Scenario
3 String (single), has short/char, command line uses long form --flagname
9 Boolean, has short/char, command line uses long form --flagname
11 Boolean (allowNo), no short/char, command line uses --no-flagname
13 Boolean (allowNo), has short/char, command line uses long form --flagname
14 Boolean (allowNo), has short/char, command line uses long form --no-flagname

Simple manual reproduction:

  1. Create a flags directory:

    mkdir my-flags
    echo "default-org" > my-flags/target-org
  2. Run a command using the long form of a flag that has a short form:

    sf org display --flags-dir ./my-flags --target-org other-org
  3. Expected: other-org is used (command line value overrides flags-dir value)

  4. Actual: Both values are passed to the command, causing "flag can only be specified once" errors or unexpected behavior

Note: The bug does NOT occur if you use the short form (-o other-org) on the command line - only the long form (--target-org other-org) is affected.

Expected Result

Command line arguments should always override --flags-dir values for single-value flags, regardless of whether the user types the short form (-o) or long form (--target-org).

Actual Result

When a flag has a short/char form defined but the user types the long form on the command line, the override check fails and both the command line value and the flags-dir value are passed to the command.

Root Cause

In commit c83f81a ("chore: bump wireit, fix types"), the logical OR operators (||) in src/hooks/preparse.ts were changed to nullish coalescing operators (??). This was likely an unintended side effect of accepting a linter auto-fix suggestion from the @typescript-eslint/prefer-nullish-coalescing rule.

This change is incorrect because argv.includes() returns false (not null/undefined) when the flag isn't found. With ??, the false return value doesn't trigger evaluation of subsequent conditions, so the long-form check is skipped when a short/char form exists for the flag.

Before (correct):

(flagOptions.char && argv.includes(`-${flagOptions.char}`)) ||
argv.includes(`--${flagName}`) ||
(flagOptions.type === 'boolean' && flagOptions.allowNo && argv.includes(`--no-${flagName}`))

After c83f81a (buggy):

(flagOptions.char && argv.includes(`-${flagOptions.char}`)) ??
argv.includes(`--${flagName}`) ??
(flagOptions.type === 'boolean' && flagOptions.allowNo && argv.includes(`--no-${flagName}`))

Affected Scenarios

The bug affects two categories of cases:

1. Flag has short/char defined, but user types long form on command line:

Flag Type short/char? Command Line Usage Affected?
String (single) yes --flagname value Yes (#3)
Boolean yes --flagname Yes (#9)
Boolean (allowNo) yes --flagname Yes (#13)
Boolean (allowNo) yes --no-flagname Yes (#14)

2. Boolean (allowNo) using --no-flagname form (third condition never evaluated):

Flag Type short/char? Command Line Usage Affected?
Boolean (allowNo) no --no-flagname Yes (#11)

Not affected:

  • Flags without short/char using long form (first condition is falsy, ?? works correctly)
  • Flags where user types the short form (-f) on the command line
  • Multiple-value flags (combine as expected)

Additional Information

The original --flags-dir feature was added in PR #1536, which documents this expected behavior:

"Flags/values provided by the user will override any flag/values found by --flags-dir -- unless the flag supports multiple, in which case they will all be combined."

Proposed Fix

Restore the || operators with an eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing comment explaining why ?? is incorrect here. This will prevent the linter from "fixing" it back to ?? in the future.

A PR with the fix and comprehensive tests will be submitted to salesforcecli/cli.

System Information

  • Affected versions: Any version containing commit c83f81a (April 2025 onwards)
  • OS: All platforms

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssue or pull request that identifies or fixes a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions