A lightning-fast, single-pass command line argument parser with structural validation and elegant JSON configuration.
- Concise JSON Configuration: Define your entire command structure in a single JSON object
- Single-Pass Processing: Parses, validates, and populates all in one efficient scan
- Type Safety: Built-in structure and type validation during parsing
- Error Resilience: Configurable error handling with continue/abort control
- Seamless Subcommand Support: First-class "exit" mechanism for complex command structures
- Zero Dependencies: Pure JavaScript with no external libraries
- Predictable Results: No type errors or undefined values (all variables are initialized)
npm install pargv-lite
import parse from 'pargv-lite';
// Define your application's command structure
const gitReq = {
// Global options
help: {
def: false,
set: ['-h', '--help']
},
verbose: {
def: false,
set: ['-v', '--verbose']
},
// Subcommands (direct string array format for exit options)
command: ['clone', 'push', 'pull', 'commit', 'checkout']
};
// Commit subcommand config
const commitReq = {
message: {
def: '',
set: ['-m', '--message']
},
all: {
def: false,
set: ['-a', '--all']
},
amend: {
def: false,
set: ['--amend']
}
};
function main() {
const gitRes = {};
// First parse to handle global options and identify subcommand
const ret = parse(process.argv, 2, gitReq, gitRes, console.error);
// Handle help flag
if (gitRes.help) {
showHelp();
return;
}
// Check if a subcommand was encountered (returns object with next position)
if (typeof ret === 'object') {
// ret contains { avi, key, opt }:
// - ret.avi is the argv index to continue parsing from
// - ret.key is the variable name in gitReq that triggered the exit ('command')
// - ret.opt is the option string that triggered the exit (subcommand name)
console.error(`Executing ${ret.opt} command...`);
switch (ret.opt) {
case 'commit':
// Parse commit-specific options starting from ret.avi
const commitRes = {};
parse(process.argv, ret.avi, commitReq, commitRes, console.error);
// Use the results
console.error(
`Committing with message: ${commitRes.message}`,
commitRes.all ? '(all files)' : '',
commitRes.amend ? '(amending)' : ''
);
break;
case 'push':
// Handle push command...
break;
// Handle other commands...
}
}
}
parse(argv, i, req, res, err)
- argv: Array of command line arguments (usually
process.argv
) - i: Starting index for parsing (usually
2
) - req: Configuration object defining your command structure
- res: Object that will be populated with parsed results
- err: Error handler function, receives
{msg, avi, opt, key, val}
and returns boolean
The function returns either:
- A number (the next index after parsing completed normally)
- An object
{ avi, key, opt }
when exiting early due to an exit option, where:avi
: The next index to resume parsing from (ArgV Index)key
: The variable name in the req object that triggered the exitopt
: The option string that triggered the exit (e.g., the subcommand name)
{
// Regular variable with default value and option definitions
variableName: {
def: defaultValue, // Boolean, string, or string[]
set: optionDefinition, // Options that set this variable
rst: optionDefinition // Options that reset this variable to default
},
// Exit option (shorthand format) - exits parsing when encountered
exitOptionName: optionDefinition
}
Option definitions can be:
- A string:
'--option'
- An array:
['--option', '-o']
null
refers to the variable name.[null, ...]
is also supported.
// Simple flags (no value needed)
verbose: {
def: false,
set: ['-v', '--verbose']
}
// String option with default value
output: {
def: 'stdout',
set: ['-o', '--output']
}
// Collect multiple values in an array
files: {
def: [],
set: ['-i', '--input'] // -i 1.txt --input 2.txt -i3.txt --input=4.txt
}
// Special option '--' collects all the anonymous arguments.
allFiles: {
def: [],
set: ['--', '-i'] // -i 1.txt 2.txt -- --this-will-be-collected-too
}
// Option to reset value back to default
// For boolean values:
color: {
def: false,
set: ['--color'], // Sets to true (!def)
rst: ['--no-color'] // Resets to false (def)
}
big: {
def: true,
set: ['--small'], // Sets to false (!def)
rst: ['--big'] // Resets to true (def)
}
// For strings or arrays, reset restores the original default:
files: {
def: ['default.txt'],
set: ['--files'], // Adds files to array
rst: ['--no-files'] // Resets back to ['default.txt']
}
Note: Inverting a boolean value is not supported.
const res = {};
parse(['node', 'app.js', '-abc'], 2, {
a: { def: false, set: '-a' },
b: { def: false, set: '-b' },
c: { def: false, set: '-c' }
}, res, console.error);
// res = { a: true, b: true, c: true }
const res = {};
parse(['node', 'app.js', '-abcd'], 2, {
a: { def: false, set: '-a' },
b: { def: [], set: '-b' },
c: { def: false, set: '-c' },
d: { def: false, set: '-d' }
}, res, console.error);
// { a: true, b: [ 'cd' ], c: false, d: false }
The exit feature enables elegant subcommand handling:
// Main CLI configuration
const mainReq = {
help: {
def: false,
set: ['-h', '--help']
},
// Direct array format for exit options
command: ['build', 'serve', 'test']
};
const mainRes = {};
const ret = parse(process.argv, 2, mainReq, mainRes, console.error);
if (typeof ret === 'object') {
// When a command is found via the exit mechanism:
// - ret.avi is already positioned after the subcommand
// - ret.key contains the variable name in req ('command' in this case)
// - ret.opt contains the matched option (the subcommand name)
switch(ret.opt) {
case 'build':
const buildReq = { /* build options */ };
const buildRes = {};
parse(process.argv, ret.avi, buildReq, buildRes, console.error);
break;
}
}
MIT © Chinory