0
# Action Execution
1
2
Action handler system for command execution, argument parsing, and lazy evaluation support.
3
4
## Capabilities
5
6
### Action Method
7
8
Attach callback handlers to commands that execute when the command is invoked.
9
10
```javascript { .api }
11
/**
12
* Attach callback handler to current command
13
* @param {function} handler - Command handler function
14
* @returns {Sade} Chainable instance
15
*/
16
action(handler);
17
18
/**
19
* Command handler function signature
20
* @param {...*} args - Positional arguments based on command usage pattern
21
* @param {object} opts - Parsed options and flags
22
*/
23
type Handler = (...args: any[], opts: object) => any;
24
```
25
26
**Parameters:**
27
28
- `handler` (function, required): Callback function executed when command runs
29
- Receives positional arguments based on command usage pattern
30
- Final parameter is always an options object with parsed flags
31
- Optional arguments may be `undefined` if not provided
32
33
**Usage Examples:**
34
35
```javascript
36
// Basic command handler
37
prog.command('greet <name>')
38
.action((name, opts) => {
39
console.log(`Hello, ${name}!`);
40
});
41
42
// Handler with optional arguments
43
prog.command('serve [dir] [port]')
44
.option('-w, --watch', 'Watch for changes')
45
.action((dir = '.', port = 3000, opts) => {
46
console.log(`Serving ${dir} on port ${port}`);
47
if (opts.watch) console.log('Watching for changes...');
48
});
49
50
// Handler with multiple required arguments
51
prog.command('copy <src> <dest>')
52
.option('-f, --force', 'Overwrite existing files')
53
.action((src, dest, opts) => {
54
console.log(`Copying ${src} to ${dest}`);
55
console.log('Options:', opts);
56
// opts = { _: [], force: true/false, f: true/false }
57
});
58
```
59
60
### Parse Method
61
62
Parse command line arguments and execute the appropriate command handler.
63
64
```javascript { .api }
65
/**
66
* Parse command line arguments and execute appropriate handler
67
* @param {string[]} arr - Command line arguments (typically process.argv)
68
* @param {object} [opts] - Parsing configuration options
69
* @returns {void|LazyOutput} Void (executes handler) or LazyOutput if opts.lazy = true
70
*/
71
parse(arr, opts);
72
73
interface ParseOptions {
74
/** Return execution info instead of running handler */
75
lazy?: boolean;
76
/** Additional flag aliases */
77
alias?: Record<string, string | string[]>;
78
/** Additional default values */
79
default?: Record<string, any>;
80
/** Handler for unknown flags */
81
unknown?: (flag: string) => string | void;
82
}
83
84
interface LazyOutput {
85
/** Command name that was matched */
86
name: string;
87
/** Handler function to execute */
88
handler: Handler;
89
/** Arguments array to pass to handler */
90
args: any[];
91
}
92
```
93
94
**Parameters:**
95
96
- `arr` (string[], required): Command line arguments array (usually `process.argv`)
97
- `opts` (object, optional): Parsing configuration options
98
99
**Basic Usage:**
100
101
```javascript
102
// Standard usage - executes handler immediately
103
prog.parse(process.argv);
104
105
// With custom arguments (for testing)
106
prog.parse(['node', 'script.js', 'build', 'src', 'dist', '--watch']);
107
```
108
109
### Lazy Execution
110
111
Use lazy parsing to defer command execution and gain control over when handlers run.
112
113
**Usage Examples:**
114
115
```javascript
116
// Get execution information without running
117
const result = prog.parse(process.argv, { lazy: true });
118
119
console.log('Command:', result.name);
120
console.log('Arguments:', result.args);
121
122
// Execute later (optionally modify args first)
123
result.handler.apply(null, result.args);
124
125
// Or with modified arguments
126
const modifiedArgs = result.args.map(arg =>
127
typeof arg === 'string' ? arg.toUpperCase() : arg
128
);
129
result.handler.apply(null, modifiedArgs);
130
```
131
132
### Parse Options Override
133
134
Override or extend option parsing behavior with custom configuration.
135
136
**Alias Override:**
137
138
```javascript
139
prog.command('build')
140
.option('-f, --force', 'Force build');
141
142
// Override aliases at parse time
143
prog.parse(process.argv, {
144
alias: {
145
f: ['foo', 'fizz'], // -f now maps to --foo and --fizz instead of --force
146
v: ['verbose'] // Add new -v -> --verbose alias
147
}
148
});
149
```
150
151
**Default Value Override:**
152
153
```javascript
154
prog.command('start')
155
.option('-p, --port', 'Server port', 3000);
156
157
// Override defaults at parse time
158
prog.parse(process.argv, {
159
default: {
160
port: 8080, // Override default port
161
env: 'development' // Add new default value
162
}
163
});
164
```
165
166
**Unknown Flag Handling:**
167
168
```javascript
169
prog.parse(process.argv, {
170
unknown: (flag) => {
171
if (flag.startsWith('--experimental-')) {
172
return; // Allow experimental flags without error
173
}
174
return `Unknown flag: ${flag}. Did you mean --help?`;
175
}
176
});
177
178
// Example output:
179
// $ my-cli build --typo
180
// ERROR: Unknown flag: --typo. Did you mean --help?
181
```
182
183
### Argument Parsing Behavior
184
185
Sade follows specific rules for parsing arguments and options.
186
187
**Argument Order and Types:**
188
189
```javascript
190
prog.command('deploy <env> [version] [region]')
191
.option('-f, --force', 'Force deployment')
192
.option('--timeout', 'Deployment timeout', 300)
193
.action((env, version, region, opts) => {
194
// env: always provided (required)
195
// version: string or undefined (optional)
196
// region: string or undefined (optional)
197
// opts: { force: boolean, timeout: number, ... }
198
});
199
200
// Examples:
201
// $ my-cli deploy prod
202
// → env='prod', version=undefined, region=undefined
203
// $ my-cli deploy prod v1.2.0
204
// → env='prod', version='v1.2.0', region=undefined
205
// $ my-cli deploy prod v1.2.0 us-east-1 --force
206
// → env='prod', version='v1.2.0', region='us-east-1', opts.force=true
207
```
208
209
**Options Object Structure:**
210
211
```javascript
212
prog.command('build')
213
.option('-w, --watch', 'Watch mode')
214
.option('-o, --output', 'Output file', 'dist.js')
215
.action((opts) => {
216
console.log(opts);
217
// {
218
// _: [], // Remaining arguments
219
// w: true, // Short flag alias
220
// watch: true, // Long flag name
221
// o: 'custom.js', // Short flag alias with value
222
// output: 'custom.js' // Long flag name with value
223
// }
224
});
225
```
226
227
### Error Handling
228
229
Parse method handles various error conditions and provides helpful error messages.
230
231
**Common Errors:**
232
233
- **Insufficient arguments**: Required arguments not provided
234
- **Invalid command**: Command name not found
235
- **Unknown options**: Unrecognized flags (unless handled by `unknown` option)
236
- **No command specified**: Multi-command CLI called without a command
237
238
**Error Examples:**
239
240
```javascript
241
// Insufficient arguments
242
// $ my-cli copy file1
243
// ERROR: Insufficient arguments!
244
// Run `$ my-cli copy --help` for more info.
245
246
// Invalid command
247
// $ my-cli invalid-command
248
// ERROR: Invalid command: invalid-command
249
// Run `$ my-cli --help` for more info.
250
251
// No command (multi-command mode)
252
// $ my-cli
253
// ERROR: No command specified.
254
// Run `$ my-cli --help` for more info.
255
```
256
257
### Execution Flow
258
259
The parse method follows a specific execution flow:
260
261
1. **Parse arguments** using mri library
262
2. **Detect command** from positional arguments
263
3. **Resolve aliases** to actual command names
264
4. **Validate arguments** against command usage pattern
265
5. **Merge options** (global + command + parse-time)
266
6. **Execute action** or return lazy output
267
7. **Handle help/version** flags automatically