Positionals
Positionals are the leftover inputs that were not matched by a flag or a typed argument. They are plain strings, and you get them only when allowPositionals: true.
Typed arguments are filled first, in order, and whatever is left over becomes positionals.
const cli = defineCLI({ cliName: "example", allowPositionals: true,
arguments: { userId: { schema: z.number(), coerce: coerce.number }, action: { schema: z.string() }, },});
cli.onExecute(({ arguments: args, positionals }) => { console.log(args.userId, args.action); // typed console.log(positionals); // string[]});example 42 delete a.txt b.txt# userId: 42, action: "delete", positionals: ["a.txt", "b.txt"]The two modes
| Setting | Behavior |
|---|---|
allowPositionals: true | Typed arguments are filled first, the rest goes to positionals. No typed argument may be optional in this mode. |
allowPositionals: false | Every input must match a typed argument. Only the last one may be optional. Anything extra is an error. |
With allowPositionals: false, an extra input fails with ParseErrorCode.PositionalArgumentNotAllowed.
Typed arguments compared to positionals
| Typed arguments | Positionals | |
|---|---|---|
| Validation | Validated against the schema | None |
| Type | Whatever the schema produces | Always string |
| Order | Filled left to right, strictly | Everything that is left |
| Optional / default | Controlled by the schema | Never optional, never has defaults |
| Source | The arguments field | Filled automatically when allowed |
Inputs that start with a dash
-- ends option parsing. Everything after it becomes a typed argument or a positional, even when it looks like a flag. For an option value that starts with a dash, use the = form.
listy --name=-weird -- -file.txt --not-an-option# name: "-weird", arguments and positionals: ["-file.txt", "--not-an-option"]