项目作者: asgerf

项目描述 :
💪Strongly typed CLI parser
高级语言: TypeScript
项目地址: git://github.com/asgerf/strongcli.git
创建时间: 2020-02-24T20:26:06Z
项目社区:https://github.com/asgerf/strongcli

开源协议:MIT License

下载


strongcli

A convenient but strict command-line parser with strong type checking for TypeScript.

Highlights

  • Options never have unexpected types.
  • Helpful error messages and usage text.
  • Easy transition to subcommands if so desired.
  • No dependencies.

Install

  1. $ npm install @asgerf/strongcli

Usage

  1. import * as cli from '@asgerf/strongcli';
  2. interface Options {
  3. name?: string;
  4. count?: number;
  5. }
  6. let { options, args } = cli.main<Options>({
  7. name: { value: String },
  8. count: { value: Number }
  9. });

More examples

  1. import * as cli from '@asgerf/strongcli';
  2. interface Options {
  3. names: string[];
  4. count: number;
  5. force: boolean;
  6. }
  7. let { options, args } = cli.main<Options>({
  8. name: {
  9. value: String,
  10. repeatable: true, // can be repeated, always maps to an array
  11. },
  12. count: {
  13. value: Number, // Parses the value of the option
  14. alias: '-c', // Examples: --count 5 --count=5 -c 5 -c5
  15. default: 1, // Set to 1 if not specified.
  16. },
  17. force: {} // no args needed for boolean flags
  18. });
  19. console.log(options.names.join(', '));

Type checking

By passing your Options interface as a type argument to cli.main, the
object literal you pass in will be checked.

For example, the following errors are found at compile-time:

  1. interface Options {
  2. foo?: string;
  3. bar?: number;
  4. baz: number[];
  5. }
  6. cli.main<Options>({
  7. foo: {
  8. value: Number; // Error: expected return type 'string'
  9. },
  10. bar: {
  11. value: Number;
  12. repeatable: true; // Error: type of 'bar' is not an array
  13. },
  14. baz: {
  15. value: Number;
  16. repeatable: true; // OK
  17. }
  18. })

Configuration

Instead of calling cli.main directly, you can prefix it with calls to program and/or parser:

  1. cli.main(); // for lazy people
  2. cli.parser().main(); // create parser separately
  3. cli.program().parser().main(); // configure parser first

For example:

  1. let parser = cli.program('myprogram').parser<Options>({
  2. foo: {
  3. value: String
  4. }
  5. });
  6. let { options, args } = parser.main();
  7. if (args.length === 0) {
  8. parser.help();
  9. }

If you don’t want strongcli to call process.exit or print directly to the console, avoid calling main and help, instead use parse and getHelp:

  1. parser.main(); // on error, print and exit
  2. parser.help(); // print and exit
  3. parser.parse(); // on error, throw exception
  4. parser.getHelp(); // return a string

Subcommands

To use subcommands, call .commandSet():

  1. cli.commandSet()
  2. cli.program().commandSet()

Then follow with .command() and .main(). For example:

  1. let program = cli.commandSet();
  2. interface AddOptions {
  3. name?: string;
  4. count?: number;
  5. }
  6. program.command<AddOptions>({
  7. name: 'add',
  8. options: {
  9. name: {
  10. value: String,
  11. },
  12. count: {
  13. alias: '-c',
  14. value: Number,
  15. },
  16. },
  17. callback(options, args) {
  18. /* execute 'add' command */
  19. }
  20. });
  21. /* ... more program.command() calls ... */
  22. program.main();

Defaults

Set default to the value to use for an option that was omitted:

  1. interface Options {
  2. baseDir: string;
  3. }
  4. let { options, args } = cli.main<Options>({
  5. baseDir: {
  6. value: String,
  7. default: '.'
  8. }
  9. })

If no default is specified, value options will be undefined, flags will be false,
and repeatable value options will be empty arrays.

The default can also be a function creating the default value:

  1. interface Options {
  2. pathMappings: Map<string, string>;
  3. }
  4. let { options, args } = cli.main<Options>({
  5. baseDir: {
  6. value: s => parsePathMappings(s),
  7. default: () => new Map()
  8. }
  9. })

Required options

To mark an option as required, set its default to cli.required:

  1. interface Options {
  2. name: string;
  3. }
  4. let { options, args } = cli.main<Options>({
  5. name: {
  6. value: String,
  7. default: cli.required
  8. }
  9. });

Strict mode

If using TypeScript in strict mode, all value options must have a type that permits undefined (possibly by being optional) or have a default value.
The default value can be cli.required (see above).

  1. interface Options {
  2. foo: string;
  3. bar?: string;
  4. baz: boolean;
  5. }
  6. let { options, args } = cli.main<Options>({
  7. foo: {
  8. value: String,
  9. default: cli.required
  10. },
  11. bar: {
  12. value: String,
  13. // doesn't need a default as type is `bar?: string`
  14. },
  15. baz: {} // flags don't need to be marked as required
  16. });

Repeatable options need no default as they default to an empty array.