cli-nano
v1.4.0
Published
Small command-line tool similar to `yargs` or `parseArgs` from Node.js to create a CLI accepting positional arguments, flags and options.
Readme
cli-nano
Small library to create command-line tool (aka CLI) which is quite similar to Yargs, it is as configurable as Yargs but is a fraction of its size. The library is also inspired by NodeJS parseArgs() but is a lot more configurable in order to get what we would expect from a more complete CLI builder tool.
Features
- Parses arguments
- Supports defining Positional arguments (input args)
- Supports Variadic arguments (1 or more positional args)
- Interleaved positionals — positionals may appear anywhere in the arg list (enabled by default). Set
command.allowInterleaved = falseto disable.
- Automatically converts flags to camelCase to match config options
- accepts both
--camelCaseand--kebab-case
- accepts both
- Negates flags when using the
--no-prefix - Clustered short flags (e.g.
-adbehaves like-a -d) - Outputs version, when defined, by using
--version - Outputs description and supplied help text by using
--help - Supports defining
requiredoptions - Supports
defaultvalues - Supports
groupfor grouping command options in help - No dependencies and very lightweight!
Recent additions
- Interleaved positionals: positional arguments may appear anywhere in the argument list, interleaved with option flags — e.g.
cmd --flag pos1 --other pos2. This behavior is enabled by default. Setcommand.allowInterleaved = falseto opt out. - Grouped short flags: clustered short aliases (e.g.
-adbehaves like-a -d); the last short in the cluster may consume the next token as its value. Kebab/camel duplication (default): parsed options are available under bothcamelCaseandkebab-casekeys (e.g. bothdryRunanddry-run). Equivalent in yargs:camel-case-expansion(enabled by default). --passthrough: tokens after--are exposed onresult['--']and are not parsed as options.- Raw argv exposure: the original argv slice is available on
result.__rawArgsfor diagnostics or passthrough adapters. - Bare long-form behavior: a bare long option with no following value is treated as an empty string (e.g.
--opt→''); a bare long array option becomes['']. - Boolean negation parity: negated booleans expose both
noFooandno-fookeys (e.g.--no-dry-runsetsdryRun=falseand also exposesnoDryRun=trueandno-dry-run=true).
npm install cli-nanoUsage
#!/usr/bin/env node
import { type Config, parseArgs } from 'cli-nano';
const config: Config = {
command: {
name: 'serve',
describe: 'Start a server with the given options',
examples: [
{ cmd: '$0 ./www/index.html 8080 --open', describe: 'Start web server on port 8080 and open browser' },
{
cmd: '$0 ./index.html 8081 --no-open --verbose',
describe: 'Start web server on port 8081 without opening browser and print more debugging logging to the console',
},
],
positionals: [
{
name: 'input',
describe: 'serving files or directory',
type: 'string',
variadic: true, // 1 or more
required: true,
},
{
name: 'port',
type: 'number',
describe: 'port to bind on',
required: false,
default: 5000, // optional default value
},
],
},
options: {
dryRun: {
alias: 'd',
type: 'boolean',
describe: 'Show what would be executed but without starting the server',
default: false, // optional default value
},
display: {
group: 'Advanced Options',
alias: 'D',
required: true,
type: 'boolean',
describe: 'a required display option',
},
exclude: {
alias: 'e',
type: 'array',
describe: 'pattern or glob to exclude (may be passed multiple times)',
},
verbose: {
alias: 'V',
type: 'boolean',
describe: 'print more information to console',
},
open: {
alias: 'o',
type: 'boolean',
describe: 'open browser when starting server',
default: true,
},
cache: {
type: 'number',
describe: 'Set cache time (in seconds) for cache-control max-age header',
default: 3600,
},
address: {
type: 'string',
describe: 'Address to use',
required: true,
},
rainbow: {
group: 'Advanced Options',
type: 'boolean',
alias: 'r',
describe: 'Enable rainbow mode',
default: true,
},
},
version: '0.1.6',
helpFlagCasing: 'camel', // show help flag option in which casing (camel/kebab) (defaults to 'kebab')
helpDescMinLength: 40, // min description length shown in help (defaults to 50)
helpDescMaxLength: 120, // max description length shown in help (defaults to 100), will show ellipsis (...) when greater
helpUsageSeparator: ':', // defaults to "→"
};
const args = parseArgs(config);
console.log(args);
// do something with parsed arguments, for example
const { input, port, open } = args;
startServer({ input, port, open });Usage with Type Inference
For full TypeScript auto-inference and intelliSense of parsed arguments, define your config as a const and cast it as const:
const config = {
... // your config object as shown above
} as const;
const args = parseArgs<typeof config>(config);
// TypeScript will infer the correct types:
args.input; // [string, ...string[]] (required, variadic)
args.port; // number (optional, has default)
args.verbose; // boolean (optional)
args.display; // boolean (required)Tip:
Usingas constpreserves literal types and tuple information, so TypeScript can infer required/optional fields and argument types automatically.
If you useconst config: Config = { ... }, you get type checking but not full intelliSense for parsed arguments.
[!NOTE] For required+variadic positionals, the type is
[string, ...string[]](at least one value required). For optional variadic, it'sstring[]. And Finally for non-variadic, it'sstring.
Example CLI Calls
# Show help guide (creates it by reading CLI config)
serve --help
# Show version (when defined)
serve --version
# Uses default port 5000
serve dist/index.html
# With required and optional positional args
serve index1.html index2.html 8080 -D value
# With boolean and array options entered as camelCase (kebab-case works too)
serve index.html 7000 --dryRun --exclude pattern1 --exclude pattern2 -D value
# With negated boolean entered as kebab-case
serve index.html 7000 --no-dryRun -D value
# With short aliases (case sensitive)
serve index.html 7000 -d -e pattern1 -e pattern2 -D value
# With number option
serve index.html 7000 --up 2 -D value
# Clustered short flags / last-short consumption
serve index.html 7000 -ad
serve index.html 7000 -ab value
# Equals form and bare-long
serve index.html 7000 --opt=value
serve index.html 7000 --opt=
serve index.html 7000 --bar
# Negation parity and passthrough
serve index.html 7000 --no-dry-run
serve index.html 7000 -- file.txt --not-a-flag
# Interleaved positionals (enabled by default)
serve --dryRun index.html 7000 -D value
serve index.html --exclude dist 7000 -D valueNotes
Default values: Use the
defaultproperty in an option or positional argument to specify a value when the user does not provide one.- Example for option:
{ type: 'boolean', default: false } - Example for positional:
{ name: 'port', type: 'number', default: 5000 }
- Example for option:
Variadic positionals: Use
variadic: truefor arguments that accept multiple values.Required options: Add
required: trueto enforce presence of an option.Negated booleans: Use
--no-flagto set a boolean option tofalse.Array options: Repeat the flag to collect multiple values (e.g.,
--exclude a --exclude b).Aliases: Use
aliasfor short flags (e.g.,-dfor--dryRun).Groups: Use
groupfor grouping some commands in help (e.g.,{ group: 'Extra Commands' }).Equals form:
--opt=valueand--opt=are supported; an empty value after=yields an empty string.Passthrough: Tokens after
--are not parsed and are available onresult['--'].Raw argv: The original argv slice is available on
result.__rawArgsfor diagnostics or passthrough adapters.Negation duplicates: Using
--no-foosetsfoo=falseand also exposesnoFooandno-fookeys.Alias:
aliasmust be a single string (multi-char aliases are supported). Array-style aliases are not supported and will be rejected.Interleaved positionals: Positional arguments may appear anywhere alongside option flags by default. Set
command.allowInterleaved = falseto require positionals-first parsing.- Yargs equivalent: to stop at the first non-option use
parserConfiguration({ 'halt-at-non-option': true }).
- Yargs equivalent: to stop at the first non-option use
See examples/ for more usage patterns.
Clarifications
- Subcommand parsing (modes): cli-nano can be used to parse either a top-level command or a subcommand. When parsing a subcommand, attach the subcommand's options under
command.optionsin that subcommand'sConfigso flags are recognized for that subcommand invocation. Example shape:
const config = {
command: {
name: 'exec',
positionals: [ /* ... */ ],
options: { // subcommand-specific options live here
parallel: { type: 'boolean', describe: 'run in parallel' },
},
},
options: { /* top-level options */ },
};Subcommand options tip: If you only add flags to the top-level
optionsobject but intend them for a subcommand, parsing will not recognize them for that subcommand. Put subcommand flags onconfig.command.options.Interleaving vs yargs: Interleaved positionals are enabled by default in cli-nano (positionals may appear anywhere). To opt out and require positionals-first (yargs' typical
halt-at-non-optionbehavior), set:
command.allowInterleaved = false;This makes cli-nano behave like yargs configured with parserConfiguration({ 'halt-at-non-option': true }).
Help Example
You can see below an example of a CLI help (which is the result of calling --help with the config shown above).
Please note the following expectations:
<option>→ required[option]→ optional
Usage:
serve <input..> [port] [options] → Start a server with the given options
Examples:
serve ./www/index.html 8080 --open → Start web server on port 8080 and open browser
serve ./index.html 8081 --no-open --verbose → Start web server on port 8081 without opening browser and print more debugging logging to the console
Arguments:
input serving files or directory <string..>
port port to bind on [number]
Options:
-d, --dry-run Show what would be executed but without starting the server [boolean]
-e, --exclude pattern or glob to exclude (may be passed multiple times) [array]
-V, --verbose print more information to console [boolean]
-o, --open open browser when starting server [boolean]
--cache Set cache time (in seconds) for cache-control max-age header [number]
--address Address to use <string>
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Advanced Options:
-D, --display a required display option <boolean>
-r, --rainbow Enable rainbow mode [boolean]Used by
cli-nano is currently being used by the following projects, which is actually why I created this CLI tool, that I currently maintain as well (feel free to edit this list):
