decopin-cli

↑ ↓ to navigate · Enter to open · Esc to close

Conventionsargv.tsx

argv.tsx

Declare arguments and options once; validation, --help, and types follow.

What you write in argv.tsx drives all three of validation, --help, and types. You never write the validation library by hand.

// app/hello/argv.tsx
import { Arg, Argv, Option, Type } from 'decopin-cli';

export default function DefineArgv() {
  return (
    <Argv description="Greet someone.">
      {/* the shorthand covers types without constraints */}
      <Arg
        name="name"
        type="string"
        default="world"
        description="who to greet"
      />
      <Option
        name="loud"
        alias="l"
        type="boolean"
        default={false}
        description="shout it"
      />

      {/* nest a Type.* child when you need constraints */}
      <Option name="times" alias="t" default={1} description="repeat count">
        <Type.Number min={1} max={5} integer />
      </Option>
      <Option name="style" default="plain" description="how to decorate">
        <Type.Enum values={['plain', 'bold', 'rainbow']} />
      </Option>
    </Argv>
  );
}

Nesting is what you want when the type itself recurses.

// app/user/list/argv.tsx (excerpt)
<Option name="tag" description="filter by tag (repeatable)">
  <Type.Array>
    <Type.String minLength={1} />
  </Type.Array>
</Option>

Dates

Dates come in two flavours, because a moment and a calendar day accept different input and are not interchangeable.

<Option name="at">
  <Type.Instant />        {/* 2026-08-28T14:30:00Z  -> Temporal.Instant */}
</Option>

<Option name="since">
  <Type.PlainDate min="2020-01-01" />  {/* 2026-08-28 -> Temporal.PlainDate */}
</Option>

Type.Instant needs an offset (Z or +09:00); Type.PlainDate refuses one.

Type.Date still works and still gives you a Date, but it is deprecated: decopin build warns, and it is removed after 2027-08-29.

Type and presence live at different levels

What it decidesWhere it goes
the type and its constraintschildren (Type.*) or the type shorthand
whether it can be omittedprops on <Arg> / <Option> (required / default)

required and default cannot both be set (with neither, the value is optional).

The declaration is where your types come from

import type { CmdProps } from 'decopin-cli';

export default function Command({ args, options }: CmdProps<'hello'>) {
  args.name; // string
  options.times; // number
  options.style; // "plain" | "bold" | "rainbow"
  return null;
}

So does --help.

$ ./dist/index.js hello --help
Usage: decopin-cli hello [name] [options]

Greet someone.

Arguments:
  name                              who to greet (default: "world")

Options:
  -l, --loud                        shout it (default: false)
  -t, --times <number>              repeat count (default: 1)
      --style <plain|bold|rainbow>  how to decorate (default: "plain")
  -h, --help                        show this help

Boolean aliases bundle: -nu is -n -u.

Reserved names

--help, -h, --version, --no-color, --json and --dry-run belong to the framework. Declaring any of them here is a build error. See Reserved options.