Skip to content

fix(option): register kebab-case names with the parser#169

Open
MukundaKatta wants to merge 1 commit intocacjs:mainfrom
MukundaKatta:fix/kebab-boolean-aliases
Open

fix(option): register kebab-case names with the parser#169
MukundaKatta wants to merge 1 commit intocacjs:mainfrom
MukundaKatta:fix/kebab-boolean-aliases

Conversation

@MukundaKatta
Copy link
Copy Markdown

Summary

Option names were only stored in their camelCased form, so the underlying mri parser never learned that the original kebab form (e.g. include-locked) was a boolean flag, nor that it aliased the camelCase one.

This produced two user-visible bugs:

1. Kebab-case boolean options swallowed the next positional arg

cli.command('[mode]').option('--include-locked, -l', 'desc')

cli.parse(['node', 'bin', '--include-locked', 'latest'])
// Before: { options: { includeLocked: 'latest' }, args: [] }     ❌
// After:  { options: { includeLocked: true,  l: true }, args: ['latest'] } ✅

cli.parse(['node', 'bin', '-l', 'latest'])
// Already worked before; still works.

2. Long hyphenated aliases didn't propagate (#119)

cli.option('-c, --clear, --clear-screen')

cli.parse(['node', 'bin', '--clear-screen'])
// Before: { clearScreen: true }                          ❌
// After:  { c: true, clear: true, clearScreen: true }    ✅

Fix

Option now tracks the original (pre-camelcase) names on rawNames, and getMriOptions registers both the camelCased and kebab-case forms in mri's alias and boolean arrays. The canonical name (used as the alias key) is still the shortest entry, preserving existing alias-key behavior.

Test plan

  • pnpm vitest run — 19 tests pass (2 new):
    • kebab-case boolean does not consume next positional
    • long hyphenated alias propagates to short and camelCase aliases
  • pnpm lint
  • pnpm exec tsdown — clean build, manual smoke-tested all four invocation forms

Downstream impact

This also fixes antfu/taze#187 (--include-locked and -l work differently) and similar bugs in any cac-based CLI that uses kebab-case boolean options.

Fixes #119

Option names were stored only in their camelCased form, so the
underlying mri parser never learned that the original kebab form (e.g.
`include-locked`) was a boolean flag or an alias of the camelCase one.
Two user-visible bugs followed:

- `--include-locked latest` was parsed as `{ includeLocked: 'latest' }`
  with `latest` removed from the positional args, instead of as a
  boolean with `latest` left untouched.
- Long hyphenated aliases (e.g. `--clear-screen` aliased to `-c` /
  `--clear`) didn't propagate the value back to the camelCased and
  short-flag aliases.

Track the original (pre-camelcase) names on `Option.rawNames` and
register both the camelCased and kebab-case forms with mri's `alias`
and `boolean` arrays.

Fixes cacjs#119
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--include-locked and -l works differently Long hyphenated options aren't recognised as aliases

1 participant