@moostjs/event-cli 0.5.33 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -3
- package/dist/index.cjs +32 -9
- package/dist/index.d.ts +12 -12
- package/dist/index.mjs +15 -10
- package/package.json +38 -32
- package/scripts/setup-skills.js +78 -0
- package/skills/moostjs-event-cli/SKILL.md +38 -0
- package/skills/moostjs-event-cli/advanced.md +202 -0
- package/skills/moostjs-event-cli/commands.md +152 -0
- package/skills/moostjs-event-cli/controllers.md +142 -0
- package/skills/moostjs-event-cli/core.md +114 -0
- package/skills/moostjs-event-cli/help.md +160 -0
- package/skills/moostjs-event-cli/interceptors.md +160 -0
- package/skills/moostjs-event-cli/options.md +180 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Help system — @moostjs/event-cli
|
|
2
|
+
|
|
3
|
+
> Auto-generated help output, help interceptor configuration, and unknown command handling.
|
|
4
|
+
|
|
5
|
+
## Concepts
|
|
6
|
+
|
|
7
|
+
Moost CLI auto-generates `--help` output from decorator metadata: `@Description()` on methods and parameters, `@CliExample()` for usage patterns, `@Value()` for sample values, and `@CliGlobalOption()` for global flags. The help system is powered by `cliHelpInterceptor`, which intercepts `--help` flags and renders formatted help.
|
|
8
|
+
|
|
9
|
+
## API Reference
|
|
10
|
+
|
|
11
|
+
### `cliHelpInterceptor(opts?)`
|
|
12
|
+
|
|
13
|
+
Factory function that returns a before-interceptor at `BEFORE_ALL` priority. Intercepts commands with `--help` and prints help output.
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
- `helpOptions?: string[]` — flag names that trigger help (default: `['help']`)
|
|
17
|
+
- `colors?: boolean` — enable colored output
|
|
18
|
+
- `lookupLevel?: number` — depth for "did you mean?" fuzzy matching on unknown commands
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { cliHelpInterceptor } from '@moostjs/event-cli'
|
|
22
|
+
import { Moost } from 'moost'
|
|
23
|
+
|
|
24
|
+
const app = new Moost()
|
|
25
|
+
app.applyGlobalInterceptors(
|
|
26
|
+
cliHelpInterceptor({
|
|
27
|
+
helpOptions: ['help', 'h'],
|
|
28
|
+
colors: true,
|
|
29
|
+
lookupLevel: 3,
|
|
30
|
+
}),
|
|
31
|
+
)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `@CliHelpInterceptor(opts?)`
|
|
35
|
+
|
|
36
|
+
Decorator form of `cliHelpInterceptor`. Apply to a controller or method to scope help behavior:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { CliHelpInterceptor } from '@moostjs/event-cli'
|
|
40
|
+
|
|
41
|
+
@CliHelpInterceptor({ colors: true, lookupLevel: 3 })
|
|
42
|
+
@Controller()
|
|
43
|
+
export class AppController {
|
|
44
|
+
@Cli('deploy')
|
|
45
|
+
deploy() { return 'Deploying...' }
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `useHelp(opts)` on CliApp
|
|
50
|
+
|
|
51
|
+
The simplest way to enable help. Calls `cliHelpInterceptor` internally:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
new CliApp()
|
|
55
|
+
.controllers(AppController)
|
|
56
|
+
.useHelp({
|
|
57
|
+
name: 'my-cli', // shown in usage: "$ my-cli ..."
|
|
58
|
+
title: 'My CLI Tool', // title at top of help
|
|
59
|
+
colors: true, // colored output (default: true)
|
|
60
|
+
lookupLevel: 3, // fuzzy lookup depth (default: 3)
|
|
61
|
+
maxWidth: 80, // max help output width
|
|
62
|
+
maxLeft: 30, // max left column width
|
|
63
|
+
mark: '>', // prefix marker for sections
|
|
64
|
+
})
|
|
65
|
+
.start()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Help options reference
|
|
69
|
+
|
|
70
|
+
| Option | Default | Description |
|
|
71
|
+
|--------|---------|-------------|
|
|
72
|
+
| `name` | — | CLI app name shown in usage examples |
|
|
73
|
+
| `title` | — | Title displayed at the top of help |
|
|
74
|
+
| `colors` | `true` | Enable colored terminal output |
|
|
75
|
+
| `lookupLevel` | `3` | Depth for "did you mean?" suggestions |
|
|
76
|
+
| `maxWidth` | — | Maximum width of help output |
|
|
77
|
+
| `maxLeft` | — | Maximum width of the left column |
|
|
78
|
+
| `mark` | — | Prefix marker for help sections |
|
|
79
|
+
|
|
80
|
+
## Common Patterns
|
|
81
|
+
|
|
82
|
+
### Pattern: Full help setup with CliApp
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
new CliApp()
|
|
86
|
+
.controllers(AppController)
|
|
87
|
+
.useHelp({ name: 'my-cli' })
|
|
88
|
+
.useOptions([
|
|
89
|
+
{ keys: ['help'], description: 'Display instructions for the command.' },
|
|
90
|
+
{ keys: ['verbose', 'v'], description: 'Enable verbose output.' },
|
|
91
|
+
])
|
|
92
|
+
.start()
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Pattern: Documenting a command
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
@Description('Deploy application to a target environment')
|
|
99
|
+
@Cli('deploy/:env')
|
|
100
|
+
@CliExample('deploy dev -p my-app', 'Deploy "my-app" to development')
|
|
101
|
+
@CliExample('deploy prod -p my-app --verbose', 'Deploy with verbose logging')
|
|
102
|
+
deploy(
|
|
103
|
+
@Description('Environment')
|
|
104
|
+
@Param('env')
|
|
105
|
+
env: string,
|
|
106
|
+
|
|
107
|
+
@Description('Project name')
|
|
108
|
+
@CliOption('project', 'p')
|
|
109
|
+
@Value('<my-app>')
|
|
110
|
+
project: string,
|
|
111
|
+
) {
|
|
112
|
+
return `Deploying ${project} to ${env}`
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Running `my-cli deploy --help` produces:
|
|
117
|
+
```
|
|
118
|
+
DESCRIPTION
|
|
119
|
+
Deploy application to a target environment
|
|
120
|
+
|
|
121
|
+
USAGE
|
|
122
|
+
$ my-cli deploy <env>
|
|
123
|
+
|
|
124
|
+
ARGUMENTS
|
|
125
|
+
<env> - Environment
|
|
126
|
+
|
|
127
|
+
OPTIONS
|
|
128
|
+
--help - Display instructions for the command.
|
|
129
|
+
-p, --project <my-app> - Project name
|
|
130
|
+
|
|
131
|
+
EXAMPLES
|
|
132
|
+
# Deploy "my-app" to development
|
|
133
|
+
$ my-cli deploy dev -p my-app
|
|
134
|
+
# Deploy with verbose logging
|
|
135
|
+
$ my-cli deploy prod -p my-app --verbose
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Pattern: Unknown command handling
|
|
139
|
+
|
|
140
|
+
When `lookupLevel` is set, typing a wrong command triggers suggestions:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
$ my-cli depoly
|
|
144
|
+
Did you mean "deploy"?
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Integration
|
|
148
|
+
|
|
149
|
+
- `@Description()` on methods fills the DESCRIPTION section
|
|
150
|
+
- `@Description()` on parameters fills ARGUMENTS and OPTIONS sections
|
|
151
|
+
- `@CliExample()` fills the EXAMPLES section
|
|
152
|
+
- `@Value()` shows sample values next to options
|
|
153
|
+
- `@CliGlobalOption()` adds options to every command's help in that controller
|
|
154
|
+
|
|
155
|
+
## Best Practices
|
|
156
|
+
|
|
157
|
+
- Always call `.useHelp({ name: 'my-cli' })` — the name makes usage examples clear
|
|
158
|
+
- Add `@Description()` to every command and parameter — it's the primary documentation
|
|
159
|
+
- Use `@CliExample()` for non-obvious usage patterns
|
|
160
|
+
- Set `lookupLevel: 3` for helpful "did you mean?" suggestions
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Interceptors — @moostjs/event-cli
|
|
2
|
+
|
|
3
|
+
> Guards, error handlers, timing, and cross-cutting CLI logic.
|
|
4
|
+
|
|
5
|
+
## Concepts
|
|
6
|
+
|
|
7
|
+
Interceptors wrap command execution with cross-cutting logic. They have three lifecycle hooks: `before`, `after`, and `error`. Each runs at a configurable priority level. They work identically to Moost interceptors but are applied in a CLI context.
|
|
8
|
+
|
|
9
|
+
Use the `define*` helpers from `moost` (re-exported by `@moostjs/event-cli`) to create functional interceptors.
|
|
10
|
+
|
|
11
|
+
## API Reference
|
|
12
|
+
|
|
13
|
+
### `defineBeforeInterceptor(fn, priority?)`
|
|
14
|
+
|
|
15
|
+
Creates an interceptor that runs before the handler. Call `reply(value)` to short-circuit and skip the handler.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { defineBeforeInterceptor, TInterceptorPriority } from '@moostjs/event-cli'
|
|
19
|
+
|
|
20
|
+
const guard = defineBeforeInterceptor((reply) => {
|
|
21
|
+
if (!process.env.CI_TOKEN) {
|
|
22
|
+
console.error('Error: CI_TOKEN required')
|
|
23
|
+
process.exit(1)
|
|
24
|
+
}
|
|
25
|
+
}, TInterceptorPriority.GUARD)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### `defineAfterInterceptor(fn, priority?)`
|
|
29
|
+
|
|
30
|
+
Creates an interceptor that runs after the handler. Receives the response.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { defineAfterInterceptor } from '@moostjs/event-cli'
|
|
34
|
+
|
|
35
|
+
const logger = defineAfterInterceptor((response) => {
|
|
36
|
+
console.log('Command returned:', response)
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `defineErrorInterceptor(fn, priority?)`
|
|
41
|
+
|
|
42
|
+
Creates an interceptor that runs on error. Call `reply(value)` to recover.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { defineErrorInterceptor, TInterceptorPriority } from '@moostjs/event-cli'
|
|
46
|
+
|
|
47
|
+
const errorHandler = defineErrorInterceptor((error, reply) => {
|
|
48
|
+
console.error(`Error: ${error.message}`)
|
|
49
|
+
reply('')
|
|
50
|
+
}, TInterceptorPriority.CATCH_ERROR)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `defineInterceptor(hooks, priority?)`
|
|
54
|
+
|
|
55
|
+
Combines all hooks in one interceptor:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { defineInterceptor, TInterceptorPriority } from '@moostjs/event-cli'
|
|
59
|
+
|
|
60
|
+
const myInterceptor = defineInterceptor({
|
|
61
|
+
before(reply) { /* ... */ },
|
|
62
|
+
after(response, reply) { /* ... */ },
|
|
63
|
+
error(error, reply) { /* ... */ },
|
|
64
|
+
}, TInterceptorPriority.INTERCEPTOR)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Priority levels
|
|
68
|
+
|
|
69
|
+
| Priority | Value | Typical use |
|
|
70
|
+
|----------|-------|-------------|
|
|
71
|
+
| `BEFORE_ALL` | 0 | Help interceptor, early logging |
|
|
72
|
+
| `BEFORE_GUARD` | 1 | Setup before guards |
|
|
73
|
+
| `GUARD` | 2 | Permission checks, env validation |
|
|
74
|
+
| `AFTER_GUARD` | 3 | Post-auth setup |
|
|
75
|
+
| `INTERCEPTOR` | 4 | General-purpose (default) |
|
|
76
|
+
| `CATCH_ERROR` | 5 | Error formatting |
|
|
77
|
+
| `AFTER_ALL` | 6 | Timing, cleanup |
|
|
78
|
+
|
|
79
|
+
## Common Patterns
|
|
80
|
+
|
|
81
|
+
### Pattern: CLI guard
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { Cli, Controller, Intercept } from '@moostjs/event-cli'
|
|
85
|
+
import { defineBeforeInterceptor, TInterceptorPriority } from '@moostjs/event-cli'
|
|
86
|
+
|
|
87
|
+
const requireEnvGuard = defineBeforeInterceptor(() => {
|
|
88
|
+
if (!process.env.CI_TOKEN) {
|
|
89
|
+
console.error('Error: CI_TOKEN environment variable is required')
|
|
90
|
+
process.exit(1)
|
|
91
|
+
}
|
|
92
|
+
}, TInterceptorPriority.GUARD)
|
|
93
|
+
|
|
94
|
+
@Controller()
|
|
95
|
+
export class DeployController {
|
|
96
|
+
@Intercept(requireEnvGuard)
|
|
97
|
+
@Cli('deploy/:env')
|
|
98
|
+
deploy(@Param('env') env: string) {
|
|
99
|
+
return `Deploying to ${env}...`
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Pattern: Global error handler
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const cliErrorHandler = defineErrorInterceptor((error, reply) => {
|
|
108
|
+
console.error(`Error: ${error.message}`)
|
|
109
|
+
reply('')
|
|
110
|
+
}, TInterceptorPriority.CATCH_ERROR)
|
|
111
|
+
|
|
112
|
+
const app = new CliApp()
|
|
113
|
+
app.applyGlobalInterceptors(cliErrorHandler)
|
|
114
|
+
app.controllers(AppController)
|
|
115
|
+
app.useHelp({ name: 'my-cli' })
|
|
116
|
+
app.start()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Pattern: Timing interceptor
|
|
120
|
+
|
|
121
|
+
Class-based with `FOR_EVENT` scope (fresh instance per command):
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { Interceptor, Before, After, TInterceptorPriority } from 'moost'
|
|
125
|
+
|
|
126
|
+
@Interceptor(TInterceptorPriority.BEFORE_ALL, 'FOR_EVENT')
|
|
127
|
+
class TimingInterceptor {
|
|
128
|
+
private start = 0
|
|
129
|
+
|
|
130
|
+
@Before()
|
|
131
|
+
recordStart() { this.start = performance.now() }
|
|
132
|
+
|
|
133
|
+
@After()
|
|
134
|
+
logDuration() {
|
|
135
|
+
const ms = (performance.now() - this.start).toFixed(1)
|
|
136
|
+
console.log(`Completed in ${ms}ms`)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Applying interceptors
|
|
142
|
+
|
|
143
|
+
| Scope | How |
|
|
144
|
+
|-------|-----|
|
|
145
|
+
| Single command | `@Intercept(fn)` on the method |
|
|
146
|
+
| All commands in a controller | `@Intercept(fn)` on the class |
|
|
147
|
+
| Every command in the app | `app.applyGlobalInterceptors(fn)` |
|
|
148
|
+
|
|
149
|
+
## Best Practices
|
|
150
|
+
|
|
151
|
+
- Use `GUARD` priority for permission/env checks that should block execution
|
|
152
|
+
- Use `CATCH_ERROR` for terminal-friendly error formatting
|
|
153
|
+
- Apply error handlers globally so every command benefits
|
|
154
|
+
- Use `FOR_EVENT` scope for class-based interceptors that track per-command state (like timing)
|
|
155
|
+
|
|
156
|
+
## Gotchas
|
|
157
|
+
|
|
158
|
+
- Interceptors run in priority order (lower numbers first), not registration order
|
|
159
|
+
- `reply(value)` in a before-interceptor skips the handler entirely — the value becomes the response
|
|
160
|
+
- The help interceptor runs at `BEFORE_ALL` — it runs before guards
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Options & arguments — @moostjs/event-cli
|
|
2
|
+
|
|
3
|
+
> CLI flags, boolean options, optional parameters, descriptions, sample values, and global options.
|
|
4
|
+
|
|
5
|
+
## Concepts
|
|
6
|
+
|
|
7
|
+
CLI commands accept two kinds of input:
|
|
8
|
+
- **Positional arguments** — extracted from `:param` segments in the command path via `@Param()`
|
|
9
|
+
- **Option flags** — bound to `--flag`/`-f` style switches via `@CliOption()`
|
|
10
|
+
|
|
11
|
+
Additional decorators control documentation and behavior: `@Description()`, `@Optional()`, `@Value()`, and `@CliGlobalOption()`.
|
|
12
|
+
|
|
13
|
+
## API Reference
|
|
14
|
+
|
|
15
|
+
### `@CliOption(...keys: string[])`
|
|
16
|
+
|
|
17
|
+
Parameter decorator. Binds the parameter to one or more CLI flags. Long names (2+ chars) become `--flag`, single chars become `-f`.
|
|
18
|
+
|
|
19
|
+
Under the hood, this calls `useCliOption(keys[0])` from `@wooksjs/event-cli` via a `@Resolve()` pipe.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { Cli, CliOption, Controller, Description, Param } from '@moostjs/event-cli'
|
|
23
|
+
|
|
24
|
+
@Controller()
|
|
25
|
+
export class DeployController {
|
|
26
|
+
@Cli('deploy/:env')
|
|
27
|
+
deploy(
|
|
28
|
+
@Param('env') env: string,
|
|
29
|
+
|
|
30
|
+
@Description('Project name')
|
|
31
|
+
@CliOption('project', 'p')
|
|
32
|
+
project: string,
|
|
33
|
+
|
|
34
|
+
@Description('Enable verbose logging')
|
|
35
|
+
@CliOption('verbose', 'v')
|
|
36
|
+
verbose: boolean,
|
|
37
|
+
) {
|
|
38
|
+
if (verbose) console.log(`Project: ${project}, env: ${env}`)
|
|
39
|
+
return `Deploying ${project} to ${env}`
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
my-cli deploy production --project my-app --verbose
|
|
46
|
+
my-cli deploy production -p my-app -v # same thing
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `@CliGlobalOption(option: { keys: string[]; description?: string; value?: string })`
|
|
50
|
+
|
|
51
|
+
Class decorator. Declares an option that appears in help output for every command in the controller.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { Cli, CliGlobalOption, Controller } from '@moostjs/event-cli'
|
|
55
|
+
|
|
56
|
+
@Controller('build')
|
|
57
|
+
@CliGlobalOption({
|
|
58
|
+
keys: ['verbose', 'v'],
|
|
59
|
+
description: 'Enable verbose logging',
|
|
60
|
+
})
|
|
61
|
+
export class BuildController {
|
|
62
|
+
@Cli('dev')
|
|
63
|
+
buildDev() { return 'Building for dev...' }
|
|
64
|
+
|
|
65
|
+
@Cli('prod')
|
|
66
|
+
buildProd() { return 'Building for prod...' }
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `@Description(text: string)`
|
|
71
|
+
|
|
72
|
+
Parameter or method decorator (re-exported from `moost`). Documents the parameter or command for help output.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
@Description('Deploy the application to a target environment')
|
|
76
|
+
@Cli('deploy/:env')
|
|
77
|
+
deploy(
|
|
78
|
+
@Description('Target environment (production, staging, dev)')
|
|
79
|
+
@Param('env')
|
|
80
|
+
env: string,
|
|
81
|
+
) {
|
|
82
|
+
return `Deploying to ${env}...`
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `@Optional()`
|
|
87
|
+
|
|
88
|
+
Parameter decorator (re-exported from `moost`). Marks a parameter as not required. Integrates with the help system.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
@Cli('build')
|
|
92
|
+
build(
|
|
93
|
+
@Description('Output directory')
|
|
94
|
+
@CliOption('out', 'o')
|
|
95
|
+
@Optional()
|
|
96
|
+
outDir: string,
|
|
97
|
+
) {
|
|
98
|
+
return `Output: ${outDir ?? './dist'}`
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `@Value(sample: string)`
|
|
103
|
+
|
|
104
|
+
Parameter decorator (from `moost`). Shows a placeholder in help output. Does NOT set a default value.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { Value } from 'moost'
|
|
108
|
+
|
|
109
|
+
@Cli('test/:config')
|
|
110
|
+
test(
|
|
111
|
+
@Description('Target environment')
|
|
112
|
+
@CliOption('target', 't')
|
|
113
|
+
@Value('<staging>')
|
|
114
|
+
target: string,
|
|
115
|
+
) {
|
|
116
|
+
return `Testing in ${target}`
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
In help: `--target <staging>`.
|
|
121
|
+
|
|
122
|
+
## Common Patterns
|
|
123
|
+
|
|
124
|
+
### Pattern: Boolean flags
|
|
125
|
+
|
|
126
|
+
When a parameter has type `boolean`, Moost automatically registers it as a boolean flag (no value expected — presence means `true`):
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
@Cli('build')
|
|
130
|
+
build(
|
|
131
|
+
@CliOption('watch', 'w') watch: boolean,
|
|
132
|
+
@CliOption('minify', 'm') minify: boolean,
|
|
133
|
+
) {
|
|
134
|
+
return `watch=${watch}, minify=${minify}`
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
my-cli build --watch --minify # watch=true, minify=true
|
|
140
|
+
my-cli build -wm # combined short flags
|
|
141
|
+
my-cli build # watch=undefined, minify=undefined
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Pattern: Global options via CliApp
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
new CliApp()
|
|
148
|
+
.controllers(AppController)
|
|
149
|
+
.useHelp({ name: 'my-cli' })
|
|
150
|
+
.useOptions([
|
|
151
|
+
{ keys: ['help'], description: 'Display instructions for the command.' },
|
|
152
|
+
{ keys: ['verbose', 'v'], description: 'Enable verbose output.' },
|
|
153
|
+
])
|
|
154
|
+
.start()
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Decorator summary
|
|
158
|
+
|
|
159
|
+
| Decorator | Applies to | Purpose |
|
|
160
|
+
|-----------|-----------|---------|
|
|
161
|
+
| `@Param('name')` | parameter | Extract positional argument from `:name` in path |
|
|
162
|
+
| `@CliOption('key', 'k')` | parameter | Bind to `--key` / `-k` flag |
|
|
163
|
+
| `@CliGlobalOption({...})` | class | Global option shown in all commands' help |
|
|
164
|
+
| `@Description('...')` | parameter, method | Document for help output |
|
|
165
|
+
| `@Optional()` | parameter | Mark as not required |
|
|
166
|
+
| `@Value('...')` | parameter | Show sample value in help |
|
|
167
|
+
|
|
168
|
+
## Best Practices
|
|
169
|
+
|
|
170
|
+
- Always add `@Description()` to options and arguments — it drives `--help` output
|
|
171
|
+
- Use short aliases (single char) for frequently-used flags: `@CliOption('verbose', 'v')`
|
|
172
|
+
- Type boolean flags as `boolean` so they don't expect a value argument
|
|
173
|
+
- Use `@Value()` for non-obvious option formats (e.g., `@Value('<host:port>')`)
|
|
174
|
+
|
|
175
|
+
## Gotchas
|
|
176
|
+
|
|
177
|
+
- `@Optional()` does not provide a default value — it only marks the parameter as optional. Use `??` in your code for defaults
|
|
178
|
+
- `@Value()` is purely cosmetic for help display — it does NOT set a default value
|
|
179
|
+
- Without `@Optional()`, a missing flag results in `undefined` (not an error)
|
|
180
|
+
- Boolean flags that are absent yield `undefined`, not `false`
|