decopin-cli

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

Getting startedProject structure

Project structure

The three kinds of files, where each may go, and what each one adds to the types.

app/
├── env.tsx               root-only: the environment, validated once at startup
├── version.tsx           root-only: what --version prints
├── global-error.tsx      root-only: the last resort
├── not-found.tsx         root-only when at the root: the view for an unknown command
├── hello/
│   ├── argv.tsx          convention: arguments and options
│   └── cmd.tsx           convention: the view
└── user/                 a directory without cmd.tsx is a group
    ├── error.tsx         inherited: list/ and import/ fail through here
    ├── layout.tsx        inherited: wraps their output
    ├── middleware.tsx    inherited: wraps their execution
    ├── list/
    │   ├── argv.tsx
    │   └── cmd.tsx
    └── import/
        ├── stdin.tsx     convention: this command reads stdin, and only this one
        └── cmd.tsx

Directories starting with _ never become commands. Put shared code there.

Conventions

A convention file sits next to cmd.tsx and applies to that command only.

FileWhat it does
cmd.tsxthe view. The only required file
argv.tsxarguments and options: validation, --help, and types
data.tsxcomputes; the return value arrives as data, and as --json
output.tsxdeclares what data.tsx promises, and checks it at run time
stdin.tsxopts the command in to reading stdin, and says what it is
help.tsxoverrides --help for this command or group
shell.tsxwhat the parent shell should do afterwards (cd, export)
complete.tsxcompletion candidates that only exist at run time

Inherited

An inherited file applies to every command below the directory it is in. The closest one wins, and the chain continues outward.

FileWhat it does
layout.tsxwraps the output
middleware.tsxwraps the execution. Nothing inside runs until you call next()
error.tsxthe view for a failure
not-found.tsxthe view for notFound() and for an unknown subcommand

Root-only

A root-only file lives in app/ and applies to the whole CLI. Placing one anywhere else is a build error.

FileWhat it does
env.tsxdeclares environment variables, validated at startup
version.tsxwhat --version prints
global-error.tsxthe last error view when no error.tsx caught it

Where the types come from

decopin build and decopin dev write .decopin/types.d.ts from the files above. CmdProps<'user/import'> is the command's path, and each prop on it traces back to one file:

PropComes fromWhen the file is absent
args<Arg> in argv.tsx{}
options<Option> in argv.tsx{}
stdinstdin.tsxnever, and stdin is never read
envenv.tsx at the root{}
datadata.tsx (or output.tsx)never
dryRunthe reserved --dry-run flagalways boolean
argvwhat was left after routingalways readonly string[]
cwdthe working directoryalways string

The generated file is a module augmentation of decopin-cli, so the same import works before and after the first build. Before it, args and options are Record<string, unknown>; after it they are exact.