Skip to content

GregBrimble/zodcli

Repository files navigation

zodcli

A CLI parser built with Zod.

Getting Started

npm install --save zodcli zod
import { z } from "zod";
import { argumentParser } from "zodcli";

argumentParser({ options: z.object({ foo: z.string() }).strict() }).parse([
	"--foo=bar",
]);

Using in a CLI

You can get CLI arguments passed to the script by using process.argv.slice(2):

// ./cli.js

import { z } from "zod";
import { argumentParser } from "zodcli";

console.log(
	argumentParser({ options: z.object({ foo: z.string() }).strict() }).parse(
		process.argv.slice(2)
	)
);

// $ node cli.js --foo=bar
// { foo: 'bar' }

API

argumentParser

argumentParser is a function which takes an object with the following properties: options and aliases.

options

options is a required property and must have a value of a strict Zod object (z.object({}).strict()). This ensures that any unrecognized arguments are rejected.

  • All properties must be in 'camelCase' and be exclusively composed of a-z characters. For example:

    • Valid:
      • foo
      • catDog
    • Invalid:
      • Foo
      • cat_dog
      • 5
      • a5

    When parsed, '--kebab-case' arguments are converted to their respective 'camelCase' properties.

    For example:

    import { z } from "zod";
    import { argumentParser } from "zodcli";
    
    const options = z
    	.object({
    		foo: z.string(),
    		catDog: z.string(),
    	})
    	.strict();
    
    const result = argumentParser({
    	options,
    }).parse(["--foo=bar", "--cat-dog=fish"]);
    
    console.log(result);
    // { foo: 'bar', catDog: 'fish' }
  • All values must be one of the following Zod types:

    And these values can be modified/wrapped with any of the following:

aliases

aliases is an optional property which allows you to configure argument aliases for options. It is an object where: the properties are lowercase and composed of exclusively a-z charaters; and the values are 'camelCase' strings and appear as properties in the options object.

Tips and Tricks

Parsing

Parsing requires an explict = between the argument name and its value. For example:

  • Valid:
    • --foo=bar --cat-dog=fish
  • Invalid:
    • --foo bar --cat-dog fish

Implicit Booleans

If an argument value is omitted, it will be set as null. You can use this to accept implicit booleans (boolean arguments whose presence implies true) by using a z.union(). For example:

import { z } from "zod";
import { argumentParser } from "zodcli";

const options = z
	.object({
		foo: z
			.union([
				z.literal("true").transform(() => true),
				z.literal("false").transform(() => false),
				z.null().transform(() => true),
			])
			.default("false"),
	})
	.strict();

const result = argumentParser({
	options,
}).parse(["--foo"]);

console.log(result);
// { foo: true }

Optional Options

You can make options optional by using the .optional() modifier. For example:

import { z } from "zod";
import { argumentParser } from "zodcli";

const options = z
	.object({
		foo: z.string(),
		catDog: z.string().optional(),
	})
	.strict();

const result = argumentParser({
	options,
}).parse(["--foo=bar"]);

console.log(result);
// { foo: 'bar' }

Or, to make all options optional, you can use .partial() on the object. For example:

import { z } from "zod";
import { argumentParser } from "zodcli";

const options = z
	.object({
		foo: z.string(),
		catDog: z.string(),
	})
	.partial()
	.strict();

const result = argumentParser({
	options,
}).parse(["--foo=bar"]);

console.log(result);
// { foo: 'bar' }

Note, however, that for booleans, you will likely want to keep them required and simply provide a .default() false value. For example:

import { z } from "zod";
import { argumentParser } from "zodcli";

const options = z
	.object({
		foo: z
			.union([
				z.literal("true").transform(() => true),
				z.literal("false").transform(() => false),
				z.null().transform(() => true),
			])
			.default("false"),
		catDog: z.string(),
	})
	.partial()
	.required({ foo: true })
	.strict();

const result = argumentParser({
	options,
}).parse([]);

console.log(result);
// { foo: false }

Coercion

You can coerce non-string values using Zod. For example:

import { z } from "zod";
import { argumentParser } from "zodcli";

const options = z
	.object({
		foo: z.coerce.number(),
	})
	.strict();

const result = argumentParser({
	options,
}).parse(["--foo=2.2"]);

console.log(result);
// { foo: 2.2 }

Roadmap

  • Help message
  • Commands support
  • Positionals support
  • Object support
  • Strict typing of aliases
  • Improve optionality/booleans

About

A CLI parser built with Zod.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published