Skip to content
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

docs: ordering of positional and option does not matter #46

Merged
merged 9 commits into from
Feb 7, 2022

Conversation

shadowspawn
Copy link
Collaborator

Options can come before or after positional. The option type does not matter for the example given.

(If it is an error or some snowflake result because not withValue, it will still behave the same for both argument orders!)

README.md Show resolved Hide resolved
@@ -150,7 +150,7 @@ const { flags, values, positionals } = parseArgs(argv, options);
### F.A.Qs

- Is `cmd --foo=bar baz` the same as `cmd baz --foo=bar`?
- Yes, if `withValue: ['foo']`, otherwise no
- yes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some commands force positional to come after dashed args. Is this possible to configure?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Short version: no, not possible to configure.

For interest, ordering is a difference between the POSIX specification and what GNU does.

https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html

It is a good idea to follow the POSIX guidelines for the command-line options of a program. The easiest way to do this is to use getopt to parse them. Note that the GNU version of getopt will normally permit options anywhere among the arguments unless the special argument ‘--’ is used. This is not what POSIX specifies; it is a GNU extension.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git forces this; i think people will be surprised if it's not configurable.

Copy link
Collaborator Author

@shadowspawn shadowspawn Feb 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a potential difference between ordering of options relative to subcommands and ordering of options relative to positional.

I did a quick check and not seeing git enforcing order of options and positional:

% git switch --no-guess main
Switched to branch 'main'
Your branch is up to date with 'upstream/main'.

% git switch feature/basic-short
Switched to branch 'feature/basic-short'
Your branch is up to date with 'origin/feature/basic-short'.

% git switch main --no-guess
Switched to branch 'main'
Your branch is up to date with 'upstream/main'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never used git switch; try git diff package.json -w and you'll get fatal: option '-w' must come before non-option arguments.

Copy link
Collaborator Author

@shadowspawn shadowspawn Feb 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Digging into the git behaviour. git switch is fairly new. I do see the error with git diff, interesting thanks. I tried another "old" command, and again ordering not enforced:

 % git clone [email protected]:tj/commander.js.git --bare    
Cloning into bare repository 'commander.js.git'...

I speculate that there is potential for confusion with <path> and options, so git diff has different rules. The help does explicitly show [--] on each of the variations that may take a "path".

SYNOPSIS
       git diff [<options>] [<commit>] [--] [<path>...]
       git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]
       git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]
       git diff [<options>] <commit>...<commit> [--] [<path>...]
       git diff [<options>] <blob> <blob>
       git diff [<options>] --no-index [--] <path> <path>

Copy link
Collaborator Author

@shadowspawn shadowspawn Feb 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the Big Four parsing libraries, all of them support options after positional by default. None of them support making it an error.

Three support a mode where parsing stops after the first non-option, so the remaining arguments can be passed through to another command (say).

  • minimist: opts.stopEarly
  • yargs: halt-at-non-option
  • commander: passThroughOptions

By default argParse allows options before positionals, or options after positionals, but will display an error for inter-mixed options and positionals. You can opt-in to mixing them by using parser.parse_intermixed_args(args). The opt-in is because intermixing interacts with a few of the other opt-in features.

Copy link
Collaborator

@bcoe bcoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if you were to build library with more complex command handling behavior, e.g., a hierarchy of commands like yargs' .command, you will end up needing to pre-process process.argv, at which point you could decide whether or not to remove leading dashed arguments.

For simplicity, I like the decision this PR lands on.

@shadowspawn shadowspawn merged commit f575021 into pkgjs:main Feb 7, 2022
@shadowspawn shadowspawn deleted the feature/ordering branch February 7, 2022 04:43
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.

4 participants