3.13.99 • Published 11 months ago

@hishprorg/itaque-esse-accusamus v3.13.99

Weekly downloads
-
License
MIT
Repository
github
Last release
11 months ago

ZodOpts

NPM Version MIT License CI codecov Minified size

A library that simplifies the process of parsing and validating command-line arguments using the Zod validation library

Installation

npm install @hishprorg/itaque-esse-accusamus # npm

yarn add @hishprorg/itaque-esse-accusamus # yarn

Quick Start

File: simple.ts

import { z } from "zod";
import { parser } from "@hishprorg/itaque-esse-accusamus";

const parsed = parser()
  .options({
    option1: {
      type: z.boolean().default(false),
      alias: "a",
    },
    option2: {
      type: z.string(),
    },
  })
  .parse(); // same with .parse(process.argv.slice(2))

// parsed is inferred as { option1: boolean, option2: string }
console.log(parsed);
# Valid options
$ node simple.js --option1 --option2=str  # or `node simple.js -a --option2 str`
{ option1: true, option2: 'str' }

# Help
$ node simple.js --help
Usage: simple.js [options]

Options:
  -h, --help              Show help
  -a, --option1           (default: false)
      --option2 <string>                    [required]

# Invalid options show help and make exit(1)
$ node simple.js
Required option is missing: option2

Usage: simple.js [options]

Options:
  -h, --help              Show help
  -a, --option1           (default: false)
      --option2 <string>                    [required]

File: complex.ts

import { z } from "zod";
// import { parser } from "@hishprorg/itaque-esse-accusamus";
import { parser } from "../src/index";

const parsed = parser()
  .name("scriptA") // script name on Usage
  .version("1.0.0") // version on Usage
  .options({
    option1: {
      // if default() is specified, it will be optional option.
      type: z.string().describe("description of option").default("default"),
      argumentName: "NameA", // used in Usage.
    },
    option2: {
      type: z
        .string()
        .regex(/[a-z]+/) // you can use zod's various methods.
        .optional(), // if optional() is specified, it will be optional option.
    },
    option3: {
      type: z.number().min(5), // accepts only number and greater than 5.
    },
    option4: {
      type: z.enum(["a", "b", "c"]).default("b"), // accepts only "a", "b", "c" and default is "b".
    },
  })
  .args([
    {
      // And required arguments.
      name: "arg1",
      type: z.string(),
    },
  ])
  .parse();

// parsed is inferred as below.
// const parsed: {
//   option1: string;
//   option2?: string | undefined;
//   option3: number;
//   option4: "a" | "b" | "c";
//   arg1: string;
// }
console.log(parsed);
# Valid options
$  node complex.js --option3=10 arg_str
{
  option1: 'default',
  option2: undefined,
  option3: 10,
  option4: 'b',
  arg1: 'arg_str'
}

# Help
$  node complex.js --help
Usage: scriptA [options] <arg1>

Arguments:
  arg1    [required]

Options:
  -h, --help              Show help
  -V, --version           Show version
      --option1 <NameA>   description of option (default: "default")
      --option2 <string>
      --option3 <number>                                              [required]
      --option4 <string>  (choices: "a", "b", "c") (default: "b")

# Version
$  node complex.js --version
1.0.0

Options

Various option types

boolean types

  • .options() supports boolean type
  • .args() DOES NOT support boolean type

File: boolean.ts

const parsed = parser()
  .options({
    option1: {
      type: z.boolean(), // required option. type is boolean
    },
    option2: {
      type: z.boolean().default(false), // optional option. type is boolean
    },
    option3: {
      type: z.boolean().optional(), // optional option. type is boolean|undefined
    },
    option4: {
      type: z.boolean().default(false).optional(), // optional option. type is boolean|undefined
    },
  })
  .parse();

// parsed is inferred as below:
// const parsed: {
//     option1: boolean;
//     option2: boolean;
//     option3?: boolean;
//     option4?: boolean;
// }
negatable boolean

You can use '--no-' prefix to set false(ex. --no-option1).

const parsed = parser()
  .options({
    option1: {
      type: z.boolean().default(true),
    },
  })
  .parse();
console.log(parsed);
$ node script.js --no-option1
{ option1: false }

enum types

  • .options() supports enum type
  • .args() supports enum type

File: enum.ts

const parsed = parser()
  .options({
    option1: {
      type: z.enum(["a", "b"]), // required option. type is "a"|"b"
    },
    option2: {
      type: z.enum(["a", "b"]).default("b"), // optional option. type is "a"|"b"
    },
    option3: {
      type: z.enum(["a", "b"]).optional(), // optional option. type is "a"|"b"|undefined
    },
    option4: {
      type: z.enum(["a", "b"]).default("b").optional(), // optional option. type is "a"|"b"|undefined
    },
  })
  .args([
    {
      name: "position1",
      type: z.enum(["a", "b"]), // required arg. type is "a"|"b"
    },
  ])
  .parse();

// parsed is inferred as below:
// const parsed: {
//   option1: "a" | "b";
//   option2: "a" | "b";
//   option3?: "a" | "b";
//   option4?: "a" | "b";
//   position1: "a" | "b";
// };
console.log(parsed);

array types

  • .options() supports array type
  • .args() supports array type
array option

CAUTION: program --opt opt_arg1 opt_arg2 pos_arg will be treated as opt=['opt_arg1' 'opt_arg2' 'pos_arg']. In this case, the user should use program --opt opt_arg1 opt_arg2 -- pos_arg.

File: array_option.ts

const parsed = parser()
  .options({
    opt: {
      type: z.array(z.string()), // required option. type is string[]
      //   type: z.array(z.string()).default([]), // optional arg. type is string[] and default is []
    },
  })
  .parse();

// parsed is inferred as below:
// const parsed: {
//   opt: string[];
// };
console.log(parsed);
# Valid options
$ node array_option.js --opt str1 str2
{ opt: [ 'str1', 'str2' ] }

# Invalid options (empty array is not permitted. use `.default([])` instead).
$ node array_option.js --opt
Option 'opt' needs value: opt

Usage: array_option.js [options]

Options:
  -h, --help              Show help
      --opt <string ...>             [required]
array positional arguments

File: array_argument.ts

const parsed = parser()
  .args([
    {
      name: "pos",
      type: z.array(z.string()), // required arg. type is string[]
      //   type: z.array(z.string()).default([]), // optional arg. type is string[] and default is []
    },
  ])
  .parse();

// parsed is inferred as below:
// const parsed: {
//   pos: string[];
// };
console.log(parsed);
# Valid options
$ node array_argument.js str1 str2
{ pos: [ 'str1', 'str2' ] }

# Invalid options (empty array is not permitted. use `.default([])` instead).
$ node array_argument.js
Required argument is missing: pos

Usage: array_argument.js [options] <pos ...>

Arguments:
  pos    [required]

Options:
  -h, --help  Show help

Custom validation

You can use Zod's .refine() method to validate each option(e.g. z.string().refine((v) => v === "foo" || v === "bar", {message: "option1 must be foo or bar"}).

If you want to check combinations of options, you can use .validation() method. .validation() registers the custom validation function. And the function is called after default validation.

File: custom_validation.ts

const parsed = parser()
  .options({
    option1: {
      type: z.number(),
    },
    option2: {
      type: z.number(),
    },
  })
  .validation((parsed) => {
    if (parsed.option1 === parsed.option2) {
      throw Error("option1 and option2 must be different"); // or return "option1 and option2 must be different"
    }
    return true;
  })
  .parse();

console.log(parsed);
# Valid options
$ node custom_validation.js --option1=10 --option2=11
{ option1: 10, option2: 11 }

# Invalid options
$ node custom_validation.js --option1=10 --option2=10
option1 and option2 must be different

Usage: custom_validation.js [options]

Options:
  -h, --help              Show help
      --option1 <number>             [required]
      --option2 <number>             [required]

Variadic arguments

Please refer array types.

Commands

File command.ts

import { z } from "zod";
import { parser } from "@hishprorg/itaque-esse-accusamus";

const command1 = command("command1")
  .options({
    option1: {
      type: z.boolean().default(false),
    },
  })
  .action((parsed) => {
    // parsed is inferred as { option1: boolean }
    console.log("command2", parsed);
  });

const command2 = command("command2")
  .options({
    option1: {
      type: z.string(),
    },
  })
  .action((parsed) => {
    // parsed is inferred as { option1: string }
    console.log("command2", parsed);
  });

parser().subcommand(command1).subcommand(command2).parse();
# Valid options
$ node command.js command1 --option1
command1 { option1: true }

# Invalid options
$  node command.js command2 a
Too many positional arguments

Usage: command.js command2 [options]

Options:
  -h, --help              Show help
      --option1 <string>             [required]

# Global help
$ node command.js --help
Usage: command.js [options] <command>

Commands:
  command1
  command2

Options:
  -h, --help  Show help

# Command help
$ node command.js command1 --help
Usage: command.js command1 [options]

Options:
  -h, --help     Show help
      --option1  (default: false)

Help

You can .showHelp() to show help message. And .getHelp() returns the help message.

Version

If the parser has called with .version() method, The user can show the version with --version or -V option.

$ node complex.js --version
1.0.0

Advanced Usage

Reuse Zod object type

If you want to reuse Zod object type, you can define the type and use it in .options() and .args().

File: map_zod_object.ts

import { z } from "zod";
import { parser } from "@hishprorg/itaque-esse-accusamus";

const OptionsSchema = z.object({
  opt1: z.string(),
  opt2: z.number().optional(),
  pos1: z.enum(["a", "b"]),
});

type Options = z.infer<typeof OptionsSchema>;

function parseOptions(): Options {
  return parser()
    .name("scriptA")
    .version("1.0.0")
    .description("desc")
    .options({
      opt1: { type: OptionsSchema.shape.opt1 },
      opt2: { type: OptionsSchema.shape.opt2 },
    })
    .args([
      {
        name: "pos1",
        type: OptionsSchema.shape.pos1,
      },
    ])
    .parse();
}

const options = parseOptions();
console.log(options);

Future work ideas

  • Support nested commands.
  • Support z.array() type in options().
  • Support custom callback to handle errors, help and exit().
  • asyncParse()
flateslint-pluginless compilerflatMapelbkarmaUnderscorecompile lesspostcss-pluginstartergradients csslintstatelesslruconfigwraptypedarraycommand-linerobusthttpsttycircularslotArraymulti-packageextendarrayselasticacheregular expressionstraverselessio-tsloggerURLSearchParamsrm -rfdefinecloudformationframeworkdescriptoropenpromiseESglobruntimecss variabletoolkitlimitedgetintrinsictypeerroremojiArrayBuffer#slicefast-cloneremovenpmtrimbcryptcloudwatchcolourInt16Arraysyntaxerrorless.jscliboundflagsdeterministicendpointrgbperformantloadingdeep-copycss-in-jsESnextJSON-SchemashellurlmomentasciilinewrapFunction.prototype.namesomeReflect.getPrototypeOflengthshimcollectionfromObject.keyswatchnumberes2015structuredClonetyped arraycheckreducertslibrapidutil.inspectworkerless mixinsenderstyleguideObject.definePropertyRegExp.prototype.flagstypescriptargvqsgradients css3formArray.prototype.findLastcss nestinggetOwnPropertyDescriptorescapefseventsmodulesequence.envtextdeepcopytoSortedutilitiesgetoptconcatMapminimalreact-hook-formObservablegroupjoinativeES3concurrencytypedcompilermatchesmodulessyntaxiteratel10nArrayBuffertrimLeftjsonutilES2015trimRightstoragegatewaydropfpsclassessymlinksfastcloneloggingstylingflattennested cssaccessorimportexportregexprecursivelook-upserializationenumerableUint8ArrayjsRxJSparentformattingcurlWebSocketsunicodelimitchromiumsharedfunctionsshamoptimizerparsei18nbootstrap lessforEachesavaobjectsortedagentCSSprototypeTypeBoxthroatdirectorylocationspeedqueryreadablelinkfastmimetypesbeanstalknamereact-testing-librarytakecssarraybufferownrmfastifyinvariantregularObject.entriesobjcore-jssuperagentdateReactiveXwalkingarktypeaccessibilitycryptostringmocharatewatchFilenegativepackages-0authenticationawesomesaucehas-ownredirectECMAScript 6eslintconfigcolumnsconsoleassigncallboundfixed-widthguidassertsspinnersparserchaicolumnlanguagevisualdataRegExp#flagsschemaECMAScript 2017code pointspasswordimportjQuerytc39bluebirdmake dirpackage.jsonuuidnodestringifymime-dbcall-bindclassnamedescriptorsgroupBydatastructurethrottlepipeES5ecmascriptdeleteastiteratorasyncwritegetes-shim APIproto0classnamesRFC-6455airbnbdebugemitObject.valuesbuffersjwtES2018higher-orderless csstoolswgetIteratorMicrosoftpositiveURLcensorECMAScript 3characterstylemonorepologStyleSheetdiffjsxjapanesecontainsroutefetch256readablestreamquotebreakelectronreuseES2017weakmapsymboltoArraysettingssnsECMAScript 2015createrm -frworkflowReactiveExtensionsreal-timeemrpostcssreducewidth[[Prototype]]sqszodrandomrdshasmkdirpisautoprefixerUint32Arrayarrayenvtypesscheme-validationtapdom-testing-libraryfind-upgetPrototypeOfUint16ArraychromepicomatchvalidObject.getPrototypeOfroute53es2017SymbolmiddlewarevalidateSymbol.toStringTagexecprettyweaksetoncejsdiffmrues-shimscollection.es6sameValueZeroserializeprotocol-buffersdayjsequalpreprocessor_.extenddynamodbmergetddfindLastresolvelastinternalfileregexcall-boundglacierprogress@@toStringTags3makehooksroutingloadbalancingdommobilepushinspectclass-validatorapijsdomajvlibphonenumbermapsuperstructform-validationefficientrfc4122browserslistECMAScript 2023optionfast-deep-cloneECMAScript 2021wordwrapSetFloat32ArrayECMAScript 2020queueMicrotasksortES2021stableelmentriessetdataViewpnpm9lookreplaystringifierebsredux-toolkitcloudsearchhasOwnPropertyfullwidthsescryptpromisesprotobufflagbootstrap cssgenericslazytouchfindLastIndextoobjecteslintpluginwatcherjestchannelArray.prototype.includesECMAScript 2022es6viewString.prototype.matchAllexpressionfast-deep-copyponyfillindicatorPushtimetestingcolorsrangeerrorstreamwordbreakcloudtrailpackagebindtesterclientRxECMAScript 2019ec2buffersetPrototypeOfwaiterrorcss lessreduxoptimistWeakMapschemeECMAScript 2018ieeventsmkdirbatchcoercibletostringtageventEmitterinferenceintrinsicansiterminaldeep-clonerequireajaxinstallercomputed-typespropertiesstateInt32ArrayjavascripttypanionspecfsawaitTypeScriptoutputiterationvalueconfigurablebundlingprivatehasOwnUint8ClampedArraycompareHyBiBigUint64ArrayArray.prototype.flattenfull-widthprefixnodejsmetadataES2020colorECMAScript 5inObject.assignstylesheetjsonpathcloudfrontes5hardlinksmkdirsprunetapebundlerhashassertfullbannermixinscachebyteLengthtypeofuninstallmimeECMAScript 2016symbolsArray.prototype.flatMapdependency managerwritablecorsdirenvironmentfoldersetImmediateshebangcallbindnopetrimEndwatchingtsredactgetterclonebrowserlistcallbacknegative zerosimpledbincludespropquerystring
@hishprorg/ipsa-consectetur-minima@hishprorg/nemo-blanditiis@hishprorg/neque-laborum-vel@hishprorg/quis-quibusdam@hishprorg/quibusdam-dolores@hishprorg/quis-doloribus@hishprorg/quidem-delectus@hishprorg/quidem-et@hishprorg/quis-est@hishprorg/sed-nihil-iusto@hishprorg/sequi-inventore-labore@hishprorg/sed-sunt@hishprorg/temporibus-aliquam-neque@hishprorg/tempore-dolor-ut@hishprorg/accusantium-architecto@hishprorg/ad-labore-dolor@hishprorg/ad-minima@hishprorg/ad-soluta-et@hishprorg/accusantium-consectetur-incidunt@hishprorg/beatae-cumque@hishprorg/beatae-animi-commodi@hishprorg/autem-quo@hishprorg/debitis-quaerat@hishprorg/debitis-qui@hishprorg/cupiditate-ut@hishprorg/dolores-ut@hishprorg/et-esse-quasi@hishprorg/est-odio-laudantium@hishprorg/eum-eos@hishprorg/et-dicta-cum@hishprorg/eum-nihil-maiores@hishprorg/illo-voluptas@hishprorg/impedit-consectetur-dicta@hishprorg/architecto-sequi@hishprorg/architecto-sapiente@hishprorg/asperiores-hic@hishprorg/aspernatur-consequatur@hishprorg/asperiores-voluptates@hishprorg/asperiores-provident@hishprorg/consectetur-sunt@hishprorg/consectetur-ab@hishprorg/consectetur-dolores@hishprorg/deserunt-est@hishprorg/deserunt-velit-quod@hishprorg/deserunt-nihil@hishprorg/deserunt-deleniti@hishprorg/doloremque-soluta@hishprorg/doloremque-mollitia@hishprorg/dolore-suscipit@hishprorg/hic-omnis@hishprorg/hic-perferendis@hishprorg/fuga-repellat@hishprorg/fugiat-accusamus-laboriosam@hishprorg/fugiat-eius@hishprorg/fugiat-libero-itaque@hishprorg/aliquam-quibusdam-repudiandae@hishprorg/aliquid-delectus-nisi@hishprorg/aliquid-ut-debitis@hishprorg/alias-maiores-saepe@hishprorg/amet-qui@hishprorg/beatae-officia@hishprorg/earum-occaecati@hishprorg/earum-sint-veritatis@hishprorg/earum-inventore@hishprorg/earum-consectetur@hishprorg/est-dicta-quis@hishprorg/esse-voluptates-veritatis@hishprorg/id-ab@hishprorg/id-harum@hishprorg/id-modi@hishprorg/id-dignissimos@hishprorg/id-voluptas@hishprorg/id-consequuntur@hishprorg/hic-repellendus-hic@hishprorg/illo-dolores@hishprorg/cumque-optio@hishprorg/cupiditate-quaerat-qui@hishprorg/doloribus-vero@hishprorg/dolorum-commodi-architecto@hishprorg/doloribus-reiciendis@hishprorg/doloribus-minima@hishprorg/dolorum-est@hishprorg/exercitationem-ipsum@hishprorg/distinctio-repudiandae-molestias@hishprorg/distinctio-alias@hishprorg/dignissimos-sunt-quaerat@hishprorg/distinctio-in@hishprorg/eos-enim-voluptate@hishprorg/eos-asperiores@hishprorg/eligendi-laborum@hishprorg/enim-fugiat-quas@hishprorg/eligendi-neque@hishprorg/eveniet-maxime@hishprorg/ex-tempora-libero@hishprorg/architecto-consectetur@hishprorg/culpa-ea-facilis@hishprorg/culpa-ratione-dolores@hishprorg/corrupti-voluptas@hishprorg/corrupti-vero@hishprorg/culpa-iusto-corrupti
2.9.82

12 months ago

1.1.28

1 year ago

2.9.83

12 months ago

2.11.88

11 months ago

2.11.89

11 months ago

2.13.94

11 months ago

2.13.93

11 months ago

2.13.92

11 months ago

2.13.91

11 months ago

2.5.43

1 year ago

2.5.41

1 year ago

2.5.42

1 year ago

3.13.98

11 months ago

3.13.99

11 months ago

2.11.90

11 months ago

2.11.91

11 months ago

3.13.94

11 months ago

2.3.35

1 year ago

3.13.95

11 months ago

2.3.34

1 year ago

3.13.96

11 months ago

3.13.97

11 months ago

2.3.36

1 year ago

2.3.33

1 year ago

2.8.56

1 year ago

2.8.55

1 year ago

1.3.33

1 year ago

1.1.16

1 year ago

2.8.59

1 year ago

2.8.58

1 year ago

2.8.57

1 year ago

1.1.19

1 year ago

1.1.18

1 year ago

1.1.17

1 year ago

2.8.63

1 year ago

2.8.62

1 year ago

2.8.61

1 year ago

2.8.60

1 year ago

2.6.48

1 year ago

2.6.49

1 year ago

2.8.67

12 months ago

2.6.44

1 year ago

1.1.23

1 year ago

2.8.66

12 months ago

2.6.45

1 year ago

1.1.22

1 year ago

2.8.65

1 year ago

2.6.46

1 year ago

1.1.21

1 year ago

2.8.64

1 year ago

2.6.47

1 year ago

1.1.20

1 year ago

1.1.27

1 year ago

1.1.26

1 year ago

2.8.69

12 months ago

1.1.25

1 year ago

2.8.68

12 months ago

2.6.43

1 year ago

1.1.24

1 year ago

2.8.70

12 months ago

2.6.50

1 year ago

1.0.16

1 year ago

2.8.74

12 months ago

2.8.73

12 months ago

2.8.72

12 months ago

2.8.71

12 months ago

2.4.39

1 year ago

2.4.36

1 year ago

2.4.38

1 year ago

2.4.37

1 year ago

2.8.78

12 months ago

2.6.55

1 year ago

2.8.77

12 months ago

2.8.76

12 months ago

2.8.75

12 months ago

2.6.51

1 year ago

2.6.52

1 year ago

2.6.53

1 year ago

2.8.79

12 months ago

2.6.54

1 year ago

2.8.81

12 months ago

2.8.80

12 months ago

2.8.82

12 months ago

2.10.83

12 months ago

2.10.84

11 months ago

2.10.85

11 months ago

2.10.86

11 months ago

2.10.87

11 months ago

2.10.88

11 months ago

2.4.41

1 year ago

2.4.40

1 year ago

1.2.28

1 year ago

1.2.29

1 year ago

1.2.30

1 year ago

1.2.31

1 year ago

2.12.91

11 months ago

2.7.55

1 year ago

1.2.32

1 year ago

1.2.33

1 year ago

1.0.15

1 year ago

1.0.11

1 year ago

1.0.14

1 year ago

1.0.13

1 year ago

1.0.12

1 year ago

1.0.10

1 year ago

1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago