Skip to content

Commit 63730d2

Browse files
committed
v3.2.0-beta :: All Clear: code, doc, example, test, manifest
1 parent cb9a685 commit 63730d2

File tree

7 files changed

+847
-100
lines changed

7 files changed

+847
-100
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules
22
package-lock.json
3-
/doc/
3+
/doc/
4+
/.vscode/

.npmignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
.gitignore
22
.npmignore
3-
LICENSE
3+
LICENSE
4+
examples
5+
test.js
6+
README.md

README.md

Lines changed: 265 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,265 @@
1-
# pargv-lite
2-
3-
JSON configurable command-line options parser
4-
5-
3.x Under developing... not tested yet
6-
7-
```javascript
8-
/**
9-
* @typedef {string} VarKey Variable name
10-
* @typedef {string | boolean | string[]} VarVal Variable value
11-
* @typedef {string} OptStr Option string, e.g. '--', '-o', '--option'
12-
* @typedef {OptStr | null} OptDef Option definitions, e.g. '--', '-o', '--option', or `null` to refer to the variable name
13-
* @typedef {OptDef | OptDef[]} OptKit one or more option definitions
14-
*
15-
* @typedef {object} VarKit Variable configuration object
16-
* @property {VarVal} def Variable **def**inition & **def**ault value (pun intended)
17-
* @property {OptKit} [set] Array of options to set the variable value
18-
* @property {OptKit} [rst] Array of options to reset the variable value
19-
*
20-
* @typedef {OptKit} HaltKit Halt options, identical to `OptKit`, for now...
21-
* @typedef {{opt: OptStr, key: VarKey}} HaltRes
22-
* @typedef {Record<VarKey, VarKit | HaltKit>} KeyKitMap
23-
* @typedef {Record<VarKey, VarVal>} KeyValMap
24-
*
25-
* @callback CanQuit
26-
* @param {{msg: string, i: number, opt: OptStr, key?: VarKey, val?: VarVal }} err
27-
* @returns {boolean} Whether the parsing should continue (false) or quit (true)
28-
* @typedef {Record<OptStr, VarKey>} OptKeyMap internal type
29-
*/
30-
/**
31-
* Command line argument parser function
32-
* @param {string[]} argv Command line arguments array
33-
* @param {number} i Index of current argument being processed
34-
* @param {KeyKitMap} req Options structure definition
35-
* @param {KeyValMap} res Object to store parsed results
36-
* @param {CanQuit} err Error handler function
37-
* @returns {{ i: number, halt?: HaltRes }}
38-
* @example
39-
*/
40-
export default function parse(argv, i, req, res, err);
41-
```
1+
# 🚀 pargv-lite
2+
3+
A lightning-fast, single-pass command line argument parser with structural validation and elegant JSON configuration.
4+
5+
## ✨ Features
6+
7+
- **Concise JSON Configuration**: Define your entire command structure in a single JSON object
8+
- **Single-Pass Processing**: Parses, validates, and populates all in one efficient scan
9+
- **Type Safety**: Built-in structure and type validation during parsing
10+
- **Error Resilience**: Configurable error handling with continue/abort control
11+
- **Seamless Subcommand Support**: First-class "exit" mechanism for complex command structures
12+
- **Zero Dependencies**: Pure JavaScript with no external libraries
13+
- **Predictable Results**: No type errors or undefined values (all variables are initialized)
14+
15+
## 📦 Installation
16+
17+
```bash
18+
npm install pargv-lite
19+
```
20+
21+
## 🔍 Elegant Usage Example
22+
23+
```javascript
24+
import parse from 'pargv-lite';
25+
26+
// Define your application's command structure
27+
const gitReq = {
28+
// Global options
29+
help: {
30+
def: false,
31+
set: ['-h', '--help']
32+
},
33+
verbose: {
34+
def: false,
35+
set: ['-v', '--verbose']
36+
},
37+
// Subcommands (direct string array format for exit options)
38+
command: ['clone', 'push', 'pull', 'commit', 'checkout']
39+
};
40+
41+
// Commit subcommand config
42+
const commitReq = {
43+
message: {
44+
def: '',
45+
set: ['-m', '--message']
46+
},
47+
all: {
48+
def: false,
49+
set: ['-a', '--all']
50+
},
51+
amend: {
52+
def: false,
53+
set: ['--amend']
54+
}
55+
};
56+
57+
function main() {
58+
const gitRes = {};
59+
60+
// First parse to handle global options and identify subcommand
61+
const ret = parse(process.argv, 2, gitReq, gitRes, errorHandler);
62+
63+
// Handle help flag
64+
if (gitRes.help) {
65+
showHelp();
66+
return;
67+
}
68+
69+
// Check if a subcommand was encountered (returns object with next position)
70+
if (typeof ret === 'object') {
71+
// ret contains { i, key, opt }:
72+
// - ret.i is the index to continue parsing from (already incremented)
73+
// - ret.key is the variable name in gitReq that triggered the exit ('command')
74+
// - ret.opt is the option string that triggered the exit (subcommand name)
75+
76+
console.log(`Executing ${ret.opt} command...`);
77+
78+
switch (ret.opt) {
79+
case 'commit':
80+
// Parse commit-specific options starting from ret.i
81+
const commitRes = {};
82+
parse(process.argv, ret.i, commitReq, commitRes, errorHandler);
83+
84+
// Use the results
85+
console.log(
86+
`Committing with message: ${commitRes.message}`,
87+
commitRes.all ? '(all files)' : '',
88+
commitRes.amend ? '(amending)' : ''
89+
);
90+
break;
91+
92+
case 'push':
93+
// Handle push command...
94+
break;
95+
96+
// Handle other commands...
97+
}
98+
}
99+
}
100+
101+
// Error handler
102+
function errorHandler(err) {
103+
console.error(`Error at arg ${err.i}: ${err.msg}`);
104+
return false; // Continue parsing
105+
}
106+
```
107+
108+
## 🛠️ API
109+
110+
```javascript
111+
parse(argv, i, req, res, err)
112+
```
113+
114+
- **argv**: Array of command line arguments (usually `process.argv`)
115+
- **i**: Starting index for parsing (usually 2)
116+
- **req**: Configuration object defining your command structure
117+
- **res**: Object that will be populated with parsed results
118+
- **err**: Error handler function, receives `{msg, i, opt, key, val}` and returns boolean
119+
120+
### Return Value
121+
122+
The function returns either:
123+
- A number (the next index after parsing completed normally)
124+
- An object `{ i, key, opt }` when exiting early due to an exit option, where:
125+
- `i`: The next index to resume parsing from (already incremented past the exit option)
126+
- `key`: The variable name in the req object that triggered the exit
127+
- `opt`: The option string that triggered the exit (e.g., the subcommand name)
128+
129+
### Configuration Format
130+
131+
```javascript
132+
{
133+
// Regular variable with default value and option definitions
134+
variableName: {
135+
def: defaultValue, // Required: Boolean, string, or string[]
136+
set: optionDefinition, // Options that set this variable
137+
rst: optionDefinition // Options that reset this variable to default
138+
},
139+
140+
// Exit option (shorthand format) - exits parsing when encountered
141+
exitOptionName: optionDefinition
142+
}
143+
```
144+
145+
Option definitions can be:
146+
- A string: `'--option'`
147+
- An array of strings: `['--option', '-o']`
148+
- Include `null` in an array to use the variable name as an option: `[null, '-o']`
149+
150+
## ⚡ Powerful Features
151+
152+
### Boolean Options
153+
154+
```javascript
155+
// Simple flags (no value needed)
156+
verbose: {
157+
def: false,
158+
set: ['-v', '--verbose']
159+
}
160+
```
161+
162+
### String Options
163+
164+
```javascript
165+
// String option with default value
166+
output: {
167+
def: 'stdout',
168+
set: ['-o', '--output']
169+
}
170+
```
171+
172+
### Array Collection
173+
174+
```javascript
175+
// Collect multiple values in an array
176+
files: {
177+
def: [],
178+
set: ['-i', '--input'] // -i 1.txt --input 2.txt -i3.txt --input=4.txt
179+
}
180+
181+
// '--' automatically collects all the anonymous arguments.
182+
// If you write it out, it collects all the rest arguments.
183+
allFiles: {
184+
def: [],
185+
set: ['--', '-i'] // -i 1.txt 2.txt -- --this-will-be-collected-too
186+
}
187+
```
188+
189+
### Reset Options
190+
191+
```javascript
192+
// Option to reset value back to default
193+
// For boolean values:
194+
color: {
195+
def: false,
196+
set: ['--color'], // Sets to true (!def)
197+
rst: ['--no-color'] // Resets to false (def)
198+
}
199+
200+
big: {
201+
def: true,
202+
set: ['--small'] // Sets to false (!def)
203+
rst: ['--big'], // Resets to true (def)
204+
}
205+
206+
// For strings or arrays, reset restores the original default:
207+
files: {
208+
def: ['default.txt'],
209+
set: ['--files'], // Adds files to array
210+
rst: ['--no-files'] // Resets back to ['default.txt']
211+
}
212+
```
213+
214+
Note: Inverting a boolean value is not supported now.
215+
216+
### Combined Short Options
217+
218+
```javascript
219+
// -abc is equivalent to -a -b -c
220+
const res = {};
221+
parse(['node', 'app.js', '-abc'], 2, {
222+
a: { def: false, set: '-a' },
223+
b: { def: false, set: '-b' },
224+
c: { def: false, set: '-c' }
225+
}, res, errorHandler);
226+
// res = { a: true, b: true, c: true }
227+
```
228+
229+
## 🔄 Subcommand Handling
230+
231+
The exit feature enables elegant subcommand handling:
232+
233+
```javascript
234+
// Main CLI configuration
235+
const mainReq = {
236+
help: {
237+
def: false,
238+
set: ['-h', '--help']
239+
},
240+
// Direct array format for exit options
241+
command: ['build', 'serve', 'test']
242+
};
243+
244+
const mainRes = {};
245+
const ret = parse(process.argv, 2, mainReq, mainRes, errorHandler);
246+
247+
if (typeof ret === 'object') {
248+
// When a command is found via the exit mechanism:
249+
// - ret.i is already positioned after the subcommand
250+
// - ret.key contains the variable name in req ('command' in this case)
251+
// - ret.opt contains the matched option (the subcommand name)
252+
253+
switch(ret.opt) {
254+
case 'build':
255+
const buildReq = { /* build options */ };
256+
const buildRes = {};
257+
parse(process.argv, ret.i, buildReq, buildRes, errorHandler);
258+
break;
259+
}
260+
}
261+
```
262+
263+
## 📜 License
264+
265+
MIT

0 commit comments

Comments
 (0)