Skip to content

Throw for unsupported option setup #2270

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

Merged

Conversation

shadowspawn
Copy link
Collaborator

@shadowspawn shadowspawn commented Oct 29, 2024

Pull Request

Problem

People who try and use unsupported Option flags do not get an error, and have to discover themselves that there are problems at runtime.

Placeholder issue: #2235
See: #430 #479 #908 #1718 #1862 #2211 #2222 #2227

Solution

Throw for unsupported Option flags, especially for known issues — too many flags, and short flag with more than one character.

This will break some existing programs that had undetected problems. (It broke one of our tests!)

ChangeLog

  • breaking: throw during Option construction for unsupported option flags

@shadowspawn shadowspawn added the semver: major Releasing requires a major version bump, not backwards compatible label Oct 29, 2024
@shadowspawn shadowspawn added the pending release Merged into a branch for a future release, but not released yet label Oct 29, 2024
@shadowspawn shadowspawn merged commit 966720a into tj:release/13.x Oct 29, 2024
9 checks passed
@shadowspawn shadowspawn deleted the feature/stricter-option-flags branch October 29, 2024 08:34
@shadowspawn shadowspawn removed the pending release Merged into a branch for a future release, but not released yet label Dec 30, 2024
@shadowspawn
Copy link
Collaborator Author

Released in Commander v13.0.0

@p3k
Copy link

p3k commented Jan 8, 2025

Hi @shadowspawn! We noticed some of our commands break with v13 because they are configured with more than one long flag. The idea is to provide a shorter version without using a one-letter option, e.g. --es and --ecmascript or --ddsg and --donaudampfschifffahrtsgesellschaft (just kidding with the latter one).

Now that multi-letter options are also throwing an error, this feels quite limiting. I get the point of considering POSIX-compatibility with multi-letter options (I am always confused by those e.g. in Gnu’s find command) – does the same apply to multiple long flags or did you have other considerations?

@shadowspawn
Copy link
Collaborator Author

No, I had not considered multiple long options. Like multi-character short options, they just happened to work. There is an issue open about multiple-character short options, and I'll add a reference to multiple longs: #2307

Hyrum's Law: https://www.hyrumslaw.com

With a sufficient number of users of an API,
it does not matter what you promise in the contract:
all observable behaviors of your system
will be depended on by somebody.

@shadowspawn
Copy link
Collaborator Author

This PR was released in Commander 13.0

Support for dual long options to allow a short-ish flag was added in Commander 13.1: #2312

jelmore1674 pushed a commit to jelmore1674/build-changelog that referenced this pull request Mar 19, 2025
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [commander](https://github.com/tj/commander.js) | devDependencies | major | [`12.1.0` -> `13.0.0`](https://renovatebot.com/diffs/npm/commander/12.1.0/13.0.0) |

---

### Release Notes

<details>
<summary>tj/commander.js (commander)</summary>

### [`v13.0.0`](https://github.com/tj/commander.js/blob/HEAD/CHANGELOG.md#1300-2024-12-30)

[Compare Source](tj/commander.js@v12.1.0...v13.0.0)

##### Added

-   support multiple calls to `.parse()` with default settings (\[[#&#8203;2299](tj/commander.js#2299)])
-   add `.saveStateBeforeParse()` and `.restoreStateBeforeParse()` for use by subclasses (\[[#&#8203;2299](tj/commander.js#2299)])
-   style routines like `styleTitle()` to add color to help using `.configureHelp()` or Help subclass (\[[#&#8203;2251](tj/commander.js#2251)])
-   color related support in `.configureOutput()` for `getOutHasColors()`, `getErrHasColors()`, and `stripColor()` (\[[#&#8203;2251](tj/commander.js#2251)])
-   Help property for `minWidthToWrap` (\[[#&#8203;2251](tj/commander.js#2251)])
-   Help methods for `displayWidth()`, `boxWrap()`, `preformatted()` et al (\[[#&#8203;2251](tj/commander.js#2251)])

##### Changed

-   *Breaking*: excess command-arguments cause an error by default, see migration tips (\[[#&#8203;2223](tj/commander.js#2223)])
-   *Breaking*: throw during Option construction for unsupported option flags, like multiple characters after single `-` (\[[#&#8203;2270](tj/commander.js#2270)])
-   *Breaking*: throw on multiple calls to `.parse()` if `storeOptionsAsProperties: true` (\[[#&#8203;2299](tj/commander.js#2299)])
-   TypeScript: include implicit `this` in parameters for action handler callback (\[[#&#8203;2197](tj/commander.js#2197)])

##### Deleted

-   *Breaking*: `Help.wrap()` refactored into `formatItem()` and `boxWrap()` (\[[#&#8203;2251](tj/commander.js#2251)])

##### Migration Tips

**Excess command-arguments**

It is now an error for the user to specify more command-arguments than are expected. (`allowExcessArguments` is now false by default.)

Old code:

```js
program.option('-p, --port <number>', 'port number');
program.action((options) => {
  console.log(program.args);
});
```

Now shows an error:

```console
$ node example.js a b c
error: too many arguments. Expected 0 arguments but got 3.
```

You can declare the expected arguments. The help will then be more accurate too. Note that declaring
new arguments will change what is passed to the action handler.

```js
program.option('-p, --port <number>', 'port number');
program.argument('[args...]', 'remote command and arguments'); // expecting zero or more arguments
program.action((args, options) => {
  console.log(args);
});
```

Or you could suppress the error, useful for minimising changes in legacy code.

```js
program.option('-p, --port', 'port number');
program.allowExcessArguments();
program.action((options) => {
  console.log(program.args);
});
```

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS44NC4wIiwidXBkYXRlZEluVmVyIjoiMzkuODQuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Reviewed-on: https://git.justinelmore.dev/jelmore1674/build-changelog/pulls/38
Reviewed-by: Justin Elmore <[email protected]>
Co-authored-by: Renovate Bot <[email protected]>
Co-committed-by: Renovate Bot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver: major Releasing requires a major version bump, not backwards compatible
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants