Options
Declare flags with defineOptions — aliases, kebab-case keys, arrays, defaults, and coercion.
Options are the flags a command accepts. defineOptions pairs a Zod object schema with an optional alias map:
import { z } from 'zod';
import { defineOptions } from 'zodline';
const options = defineOptions(
z.object({
name: z.string().describe('Name to greet'),
loud: z.boolean().default(false).describe('Use uppercase'),
}),
{ n: 'name', l: 'loud' },
);
The alias map is { shortFlag: schemaKey } — read it as “-n means --name”.
Values arrive as strings
zodline hands Zod exactly what the shell produced: every flag value is a string, and a flag with no
value is the boolean true. Schemas that expect other types need coercion.
z.object({
port: z.coerce.number().default(3000).describe('Port to listen on'),
retries: z.coerce.number().int().min(0).default(3).describe('Retry count'),
since: z.coerce.date().optional().describe('Only include entries after this date'),
});
my-cli serve --port 8080 # options.port === 8080 (number)
Boolean flags
A flag whose next argument is absent or starts with - becomes true. That makes z.boolean() right for
presence-only switches:
z.object({
loud: z.boolean().default(false).describe('Use uppercase'),
});
my-cli greet --name World --loud # loud: true
my-cli greet --name World # loud: false (from the default)
To accept an explicit value, use z.stringbool(), which parses "true"/"false" and friends:
z.object({
color: z.stringbool().default(true).describe('Colorize output'),
});
my-cli build --color false # color: false
kebab-case keys
Schema keys are camelCase; command lines are kebab-case. zodline maps between them, so no extra
configuration is needed:
z.object({
androidMax: z.coerce.number().optional().describe('Maximum Android version'),
dryRun: z.boolean().default(false).describe('Do not write anything'),
});
my-cli deploy --android-max 34 --dry-run
# { androidMax: 34, dryRun: true }
Both spellings are accepted. If both appear in one invocation, the camelCase one wins.
Aliases
Any option can have a short form. Aliases are resolved before validation, so the schema only ever sees the long key:
defineOptions(
z.object({
verbose: z.boolean().default(false).describe('Show detailed output'),
output: z.string().optional().describe('Write results to this file'),
}),
{ v: 'verbose', o: 'output' },
);
my-cli build -v -o out.json
Short flags cluster: -abc is three boolean flags, a, b and c. If both -v and --verbose are passed,
the alias wins.
Arrays
Repeat a flag to collect values. A single occurrence is wrapped into an array automatically, so the schema does not need a union:
z.object({
customProperty: z.array(z.string()).default([]).describe('key=value pair, repeatable'),
});
my-cli deploy --custom-property key1=value1 --custom-property key2=value2
# { customProperty: ['key1=value1', 'key2=value2'] }
my-cli deploy --custom-property key1=value1
# { customProperty: ['key1=value1'] }
Normalization looks through .optional() and .default() wrappers, so z.array(z.string()).optional()
behaves the same way.
Defaults and optionality
.default() fills a value in when the flag is absent and shows up in the generated help as
(default: …). .optional() leaves the key undefined.
z.object({
format: z.enum(['json', 'text']).default('text').describe('Output format'),
config: z.string().optional().describe('Path to a config file'),
});
Unknown options are rejected
Any flag that is not a schema key (in either spelling), an alias, or help/version throws before
validation runs:
my-cli greet --name World --shout
# Error: Unknown option: --shout
This holds for commands that declare no options at all. See Error handling for the error types.
Resolution order
Understanding the pipeline explains most edge cases:
Unknown-option check
Alias resolution
-v becomes verbose; the alias value wins over an explicit long form.kebab-case conversion
android-max becomes androidMax, unless androidMax is already set.Array normalization
Schema validation
schema.parse() applies coercion, defaults and refinements.Next: Arguments
Validate positional arguments with tuples, arrays and unions.