3.13.99 • Published 12 months ago

@hishprorg/itaque-esse-accusamus v3.13.99

Weekly downloads
-
License
MIT
Repository
github
Last release
12 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

1 year ago

1.1.28

1 year ago

2.9.83

1 year ago

2.11.88

1 year ago

2.11.89

12 months ago

2.13.94

12 months ago

2.13.93

12 months ago

2.13.92

12 months ago

2.13.91

12 months ago

2.5.43

1 year ago

2.5.41

1 year ago

2.5.42

1 year ago

3.13.98

12 months ago

3.13.99

12 months ago

2.11.90

12 months ago

2.11.91

12 months ago

3.13.94

12 months ago

2.3.35

1 year ago

3.13.95

12 months ago

2.3.34

1 year ago

3.13.96

12 months ago

3.13.97

12 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

1 year ago

2.6.44

1 year ago

1.1.23

1 year ago

2.8.66

1 year 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

1 year ago

1.1.25

1 year ago

2.8.68

1 year ago

2.6.43

1 year ago

1.1.24

1 year ago

2.8.70

1 year ago

2.6.50

1 year ago

1.0.16

1 year ago

2.8.74

1 year ago

2.8.73

1 year ago

2.8.72

1 year ago

2.8.71

1 year 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

1 year ago

2.6.55

1 year ago

2.8.77

1 year ago

2.8.76

1 year ago

2.8.75

1 year ago

2.6.51

1 year ago

2.6.52

1 year ago

2.6.53

1 year ago

2.8.79

1 year ago

2.6.54

1 year ago

2.8.81

1 year ago

2.8.80

1 year ago

2.8.82

1 year ago

2.10.83

1 year ago

2.10.84

1 year ago

2.10.85

1 year ago

2.10.86

1 year ago

2.10.87

1 year ago

2.10.88

1 year 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

12 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