Open elliot-nelson opened 3 years ago
Possible negatives / caveats
If we go ahead with https://github.com/microsoft/rushstack/pull/2784 (allow space-separated arguments for list parameters), then list parameters and positional arguments interact in a way that depends on order. For example, if --color
is a ChoiceList and your command takes positional arguments inputFile
and outputFile
:
bin/my-program in.png out.png --color red green
# -> { color: ['red', 'green'], inputFile: 'in.png', outputFile: 'out.png' }
bin/my-program --color red green in.png out.png
# ERROR: `in.png` is not a valid choice for color
There's several ways for the user to specify what they intend, but this conflict does leave the designer of the CLI with no options if they want to avoid the user running into this error.
Possible approaches in this case:
My vote currently would be Option 4, as I think it gives the user the most flexibility.
Summary
Regardless of whether Rush ever uses positional arguments, if we want
ts-command-line
to be usable outside of rushstack (by folks interested in a robust TypeScript-based command line parser), it needs to have positional argument support.What we'd be interested in is a command syntax like:
Where:
--format markdown
is aCommandLineStringParameter
input.md
is the first positional argumentoutput.html
is the second positional argument--github
is aCommandLineFlagParameter
These positional arguments should be definable using the existing conventions,
defineSomething()
, and have defined types just like the existing parameters.Details
The backing library (
argparse
) already has robust support for positional arguments, so we won't need to move away from that library to make this change. We only need to decide what additional restrictions we want to put on the defined arguments.My proposal would be to make the parsing rules simple by allowing flags to exist anywhere (before and after positional arguments), and to allow both required and optional positional arguments; but, as soon as an optional positional argument is specified, all positional arguments after that must also be optional. You are allowed to create List-type positional arguments, but only as the last positional argument defined. This set of restrictions should support almost all possible desired CLI syntaxes, without requiring any "guesswork" (ambiguity about what argument is assigned to what parameter).
I'd like to be able to define positional arguments as a
String
,StringList
,Choice
,ChoiceList
,Integer
, orIntegerList
(any existing parameter type except forFlag
). Tentatively, I think it would make sense for the user API to just duplicate all existing methods (even though likely we'd just extend existing Parameter types to support positional args instead of parameter names).For example:
An alternative would be to take time to break apart underlying types and parameters/positionals into separate concepts, and define parameters in a new API:
This alternative likely has the disadvantages of (1) more complicated type algebra in ts-command-line, and (2) forces users to import various additional enums and classes from the package in order to make their definitions. (An advantage of today's design is that if you stick to using the
define
andget
methods, you never need to import any extra type names at all.)(Defining parameters and positionals is a big part of the dev experience when using a CLI framework so I'm very interested in additional ideas on improvements!)
Standard questions
Please answer these questions to help us investigate your issue more quickly:
node -v
)?