From eb92f7be7fe33412b1369821fc99ff878abf78e4 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 20 Oct 2026 00:28:38 +0000 Subject: [PATCH] Preserve double dash values during flag alias parsing --- docs/roadmap/remediation.md | 9 ++++++++- internal/cobra/flags.go | 4 ++-- internal/cobra/flags_test.go | 23 +++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index 4c19dbd..fec84c3 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -215,7 +215,7 @@ passed on Go 1.26.8. ## R-6: Keep the flag interpretation pass consistent with value consumption -Status: open. Priority: P2. Category: canonical/alias parsing divergence. +Status: complete. Priority: P2. Category: canonical/alias parsing divergence. **Evidence:** [interpretFlagTokens](../../internal/cobra/flags.go#L28) refuses to consume a following `--` as the value of a value-taking flag in both the long @@ -242,6 +242,13 @@ introducing a different operand/option convention. values. Cover canonical and aliased long/short spellings, and preserve ordinary termination when `--` occurs after a completed value or boolean flag. +**Completed:** The alias interpretation pass now consumes the next token for +value-taking long and short flags even when that value is `--`, matching backend +arity. All four canonical/alias long/short regressions failed before the fix and +now retain the value, later alias occurrences, original spellings, and genuine +post-value terminators. Boolean/value termination cases also pass. No accepted +value was prohibited. The complete offline root suite passed on Go 1.26.8. + ## R-7: Retain entered flag spellings in parser-level usage failures Status: open. Priority: P3. Category: incomplete diagnostic adaptation. diff --git a/internal/cobra/flags.go b/internal/cobra/flags.go index 3938cea..d6c6505 100644 --- a/internal/cobra/flags.go +++ b/internal/cobra/flags.go @@ -56,7 +56,7 @@ func interpretFlagTokens(argv []string, flags []commandmeta.Flag, aliases []comm index++ continue } - if !flag.Boolean && index+1 < len(argv) && argv[index+1] != "--" { + if !flag.Boolean && index+1 < len(argv) { interpreted = append(interpreted, "--"+flag.Name+"="+argv[index+1]) index += 2 continue @@ -101,7 +101,7 @@ func interpretFlagTokens(argv []string, flags []commandmeta.Flag, aliases []comm interpreted = append(interpreted, "--"+flag.Name+"="+value) break } - if index+1 < len(argv) && argv[index+1] != "--" { + if index+1 < len(argv) { interpreted = append(interpreted, "--"+flag.Name+"="+argv[index+1]) index += 2 consumedNext = true diff --git a/internal/cobra/flags_test.go b/internal/cobra/flags_test.go index f77dc6c..fc0fd0f 100644 --- a/internal/cobra/flags_test.go +++ b/internal/cobra/flags_test.go @@ -92,6 +92,29 @@ func TestParseFlagAliasesPreserveValuesAndTerminators(t *testing.T) { } } +func TestParseConsumesDoubleDashAsAFlagValue(t *testing.T) { + for _, spelling := range []string{"--color", "--colour", "-c", "-C"} { + t.Run(spelling, func(t *testing.T) { + result := Parse(flagGrammarTree(), []string{"run", spelling, "--", "--taggy=one", "--colour=red", "--", "--taggy=operand"}, flagGrammarOptions()) + if result.Failure != nil { + t.Fatalf("parse failed: %s", result.Failure.Message) + } + if !reflect.DeepEqual(result.FlagValues[0], []string{"--", "red"}) || !reflect.DeepEqual(result.FlagValues[4], []string{"one"}) { + t.Errorf("flag values = %#v", result.FlagValues) + } + if !reflect.DeepEqual(result.FlagSpellings[0], []string{spelling, "--colour"}) || !reflect.DeepEqual(result.Operands, []string{"--taggy=operand"}) { + t.Errorf("spellings = %#v, operands = %#v", result.FlagSpellings, result.Operands) + } + }) + } + for _, args := range [][]string{{"run", "-v", "--", "--colour"}, {"run", "--color", "blue", "--", "--colour"}} { + result := Parse(flagGrammarTree(), args, flagGrammarOptions()) + if result.Failure != nil || !reflect.DeepEqual(result.Operands, []string{"--colour"}) { + t.Errorf("Parse(%q) = %#v", args, result) + } + } +} + func TestParseHelpAliasAndUnknownShortMembers(t *testing.T) { result := Parse(flagGrammarTree(), []string{"run", "--hlep"}, flagGrammarOptions()) if result.Failure != nil || !result.HelpRequested {