@moostjs/event-cli 0.5.32 → 0.6.0

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.
@@ -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`