@travetto/cli 3.0.2 → 3.1.0-rc.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.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
- <!-- Please modify https://github.com/travetto/travetto/tree/main/module/cli/DOC.ts and execute "npx trv doc" to rebuild -->
2
+ <!-- Please modify https://github.com/travetto/travetto/tree/main/module/cli/DOC.tsx and execute "npx trv doc" to rebuild -->
3
3
  # Command Line Interface
4
+
4
5
  ## CLI infrastructure for Travetto framework
5
6
 
6
7
  **Install: @travetto/cli**
@@ -12,11 +13,7 @@ npm install @travetto/cli
12
13
  yarn add @travetto/cli
13
14
  ```
14
15
 
15
- The cli is the primary structure for interacting with the external requirements of the framework. This can range from running tests, to running applications, to generating email templates. The main executable can be installed globally or locally. If installed globally and locally, it will defer to the local installation for execution.
16
-
17
- As is the custom, modules are able to register their own cli extensions as scripts, whose name starts with `cli.`. These scripts are then picked up at runtime and all available options are provided when viewing the help documentation. The following are all the supported cli operations and the various settings they allow.
18
-
19
- ## General
16
+ The cli module represents the primary entry point for execution within the framework. One of the main goals for this module is extensibility, as adding new entry points is meant to be trivial. The framework leverages this module for exposing all executable tools and entry points. To see a high level listing of all supported commands, invoke `trv --help`
20
17
 
21
18
  **Terminal: General Usage**
22
19
  ```bash
@@ -24,69 +21,392 @@ $ trv --help
24
21
 
25
22
  Usage: [options] [command]
26
23
 
24
+ Commands:
25
+ doc Command line support for generating module docs.
26
+ doc:angular Generate documentation into the angular webapp under related/travetto.github.io
27
+ doc:mapping Generate module mapping for @travetto/doc
28
+ email:compile CLI Entry point for running the email server
29
+ email:editor The email editor compilation service and output serving
30
+ exec Repo execution
31
+ lint Command line support for linting
32
+ lint:register Writes the lint configuration file
33
+ list Allows for listing of modules
34
+ model:export Exports model schemas
35
+ model:install Installing models
36
+ openapi:client CLI for generating the cli client
37
+ openapi:spec CLI for outputting the open api spec to a local file
38
+ pack Standard pack support
39
+ pack:docker Standard docker support for pack
40
+ pack:lambda Standard lambda support for pack
41
+ pack:zip Standard zip support for pack
42
+ repo:publish Publish all pending modules
43
+ repo:version Version all changed dependencies
44
+ run:double Doubles a number
45
+ run:rest Run a rest server as an application
46
+ scaffold Command to run scaffolding
47
+ service Allows for running services
48
+ test Launch test framework and execute tests
49
+ test:watch Invoke the test watcher
50
+ version-sync Enforces all packages to write out their versions and dependencies
51
+ ```
52
+
53
+ This listing is from the [Travetto](https://travetto.dev) monorepo, and represents the majority of tools that can be invoked from the command line.
54
+
55
+ This module also has a tight integration with the [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=arcsine.travetto-plugin), allowing the editing experience to benefit from the commands defined. The most commonly used commands will be the ones packaged with the framework, but its also very easy to create new commands. With the correct configuration, these commands will also be exposed within VSCode.
56
+
57
+ At it's heart, a cli command is the contract defined by what flags, and what arguments the command supports. Within the framework this requires three criteria to be met:
58
+ * The file must be located in the `support/` folder, and have a name that matches `cli.*.ts`
59
+ * The file must be a class that has a main method
60
+ * The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L20) decorator
61
+
62
+ **Code: Basic Command**
63
+ ```typescript
64
+ import { CliCommand } from '@travetto/cli';
65
+
66
+ @CliCommand()
67
+ export class BasicCommand {
68
+ main() {
69
+ console.log('Hello');
70
+ }
71
+ }
72
+ ```
73
+
74
+ **Terminal: Basic Command Help**
75
+ ```bash
76
+ $ trv basic -h
77
+
78
+ Usage: doc/cli.basic [options]
79
+
27
80
  Options:
28
- -V, --version output the version number
29
- -h, --help display help for command
81
+ -h, --help display help for command
82
+ ```
30
83
 
31
- Commands:
32
- echo [options] [args...]
33
- main <fileOrImport> [args...]
34
- help [command] display help for command
84
+ ## Command Naming
85
+ The file name `support/cli.<name>.ts` has a direct mapping to the cli command name. This hard mapping allows for the framework to be able to know which file to invoke without needing to load all command-related files.
86
+
87
+ Examples of mappings:
88
+ * `cli.test.ts` maps to `test`
89
+ * `cli.pack_docker.ts` maps to `pack:docker`
90
+ * `cli.email_template.ts` maps to `email:template`
91
+ The pattern is that underscores(_) translate to colons (:), and the `cli.` prefix, and `.ts` suffix are dropped.
92
+
93
+ ## Binding Flags
94
+ [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L20) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L20) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14) class. The fields of the class represent the flags that are available to the command.
95
+
96
+ **Code: Basic Command with Flag**
97
+ ```typescript
98
+ import { CliCommand } from '@travetto/cli';
99
+
100
+ @CliCommand()
101
+ export class BasicCommand {
102
+
103
+ loud?: boolean;
104
+
105
+ main() {
106
+ console.log(this.loud ? 'HELLO' : 'Hello');
107
+ }
108
+ }
35
109
  ```
36
110
 
37
- This will show all the available options/choices that are exposed given the currently installed modules.
111
+ **Terminal: Basic Command with Flag Help**
112
+ ```bash
113
+ $ trv basic:flag -h
114
+
115
+ Usage: doc/cli.basic:flag [options]
116
+
117
+ Options:
118
+ -l, --loud
119
+ -h, --help display help for command
120
+ ```
121
+
122
+ As you can see the command now has the support of a basic boolean flag to determine if the response should be loud or not. The default value here is undefined/false, and so is an opt-in experience.
123
+
124
+ **Terminal: Basic Command with Loud Flag**
125
+ ```bash
126
+ $ trv basic:flag --loud
127
+
128
+ HELLO
129
+ ```
38
130
 
39
- ## Extending
131
+ The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L20) supports the following data types for flags:
132
+ * Boolean values
133
+ * Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L179), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L185), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L173), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L114) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L124) decorators help provide additional validation.
134
+ * String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L114), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L124), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L106) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L85) provide additional constraints
135
+ * Date values. The [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L114) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L124) decorators help provide additional validation.
136
+ * String lists. Same as String, but allowing multiple values.
137
+ * Numeric lists. Same as Number, but allowing multiple values.
40
138
 
41
- Extending the `cli` is fairly straightforward. It is built upon [commander](https://www.npmjs.com/package/commander), with a model that is extensible:
139
+ ## Binding Arguments
140
+ The `main()` method is the entrypoint for the command, represents a series of parameters. Some will be required, some may be optional. The arguments support all types supported by the flags, and decorators can be provided using the decorators inline on parameters. Optional arguments in the method, will be optional at run time, and filled with the provided default values.
42
141
 
43
- **Code: Echo Command**
142
+ **Code: Basic Command with Arg**
44
143
  ```typescript
45
144
  import { CliCommand } from '@travetto/cli';
145
+ import { Max, Min } from '@travetto/schema';
46
146
 
47
- /**
48
- * `npx trv echo`
49
- *
50
- * Allows for cleaning of the cache dire
51
- */
52
- export class CliEchoCommand extends CliCommand {
53
- name = 'echo';
147
+ @CliCommand()
148
+ export class BasicCommand {
54
149
 
55
- getOptions() {
56
- return { uppercase: this.boolOption({ desc: 'Upper case' }) };
150
+ main(@Min(1) @Max(10) volume: number = 1) {
151
+ console.log(volume > 7 ? 'HELLO' : 'Hello');
57
152
  }
153
+ }
154
+ ```
155
+
156
+ **Terminal: Basic Command**
157
+ ```bash
158
+ $ trv basic:arg -h
159
+
160
+ Usage: doc/cli.basic:arg [options] [volume:number]
161
+
162
+ Options:
163
+ -h, --help display help for command
164
+ ```
165
+
166
+ **Terminal: Basic Command with Invalid Loud Arg**
167
+ ```bash
168
+ $ trv basic:arg 20
169
+
170
+ Execution failed:
171
+ * volume is bigger than (10). [1]
172
+
173
+ Usage: doc/cli.basic:arg [options] [volume:number]
174
+
175
+ Options:
176
+ -h, --help display help for command
177
+ ```
178
+
179
+ **Terminal: Basic Command with Loud Arg > 7**
180
+ ```bash
181
+ $ trv basic:arg 8
182
+
183
+ HELLO
184
+ ```
58
185
 
59
- getArgs() {
60
- return '[args...]';
186
+ **Terminal: Basic Command without Arg**
187
+ ```bash
188
+ $ trv basic:arg
189
+
190
+ Hello
191
+ ```
192
+
193
+ Additionally, if you provide a field as an array, it will collect all valid values (excludes flags, and any arguments past a `--`).
194
+
195
+ **Code: Basic Command with Arg List**
196
+ ```typescript
197
+ import { CliCommand } from '@travetto/cli';
198
+ import { Max, Min } from '@travetto/schema';
199
+
200
+ @CliCommand()
201
+ export class BasicCommand {
202
+
203
+ reverse?: boolean;
204
+
205
+ main(@Min(1) @Max(10) volumes: number[]) {
206
+ console.log(volumes.sort((a, b) => (a - b) * (this.reverse ? -1 : 1)).join(' '));
61
207
  }
208
+ }
209
+ ```
210
+
211
+ **Terminal: Basic Command**
212
+ ```bash
213
+ $ trv basic:arglist -h
214
+
215
+ Usage: doc/cli.basic:arglist [options] <volumes...:number>
216
+
217
+ Options:
218
+ -r, --reverse
219
+ -h, --help display help for command
220
+ ```
221
+
222
+ **Terminal: Basic Arg List**
223
+ ```bash
224
+ $ trv basic:arglist 10 5 3 9 8 1
62
225
 
63
- async action(args: string[]) {
64
- if (this.cmd.uppercase) {
65
- args = args.map(x => x.toUpperCase());
66
- }
67
- console.log!(args);
226
+ 1 3 5 8 9 10
227
+ ```
228
+
229
+ **Terminal: Basic Arg List with Invalid Number**
230
+ ```bash
231
+ $ trv basic:arglist 10 5 3 9 20 1
232
+
233
+ Execution failed:
234
+ * volumes[4] is bigger than (10). [1]
235
+
236
+ Usage: doc/cli.basic:arglist [options] <volumes...:number>
237
+
238
+ Options:
239
+ -r, --reverse
240
+ -h, --help display help for command
241
+ ```
242
+
243
+ **Terminal: Basic Arg List with Reverse**
244
+ ```bash
245
+ $ trv basic:arglist -r 10 5 3 9 8 1
246
+
247
+ 10 9 8 5 3 1
248
+ ```
249
+
250
+ ## Customization
251
+ By default, all fields are treated as flags and all parameters of `main()` are treated as arguments within the validation process. Like the standard [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14) behavior, we can leverage the metadata of the fields/parameters to help provide additional customization/context for the users of the commands.
252
+
253
+ **Code: Custom Command with Metadata**
254
+ ```typescript
255
+ import { CliCommand } from '@travetto/cli';
256
+ import { Max, Min } from '@travetto/schema';
257
+
258
+ /**
259
+ * Custom Argument Command
260
+ */
261
+ @CliCommand()
262
+ export class CustomCommand {
263
+
264
+ /**
265
+ * The message to send back to the user
266
+ * @alias -m
267
+ * @alias --message
268
+ */
269
+ text: string = 'hello';
270
+
271
+ main(@Min(1) @Max(10) volume: number = 1) {
272
+ console.log(volume > 7 ? this.text.toUpperCase() : this.text);
68
273
  }
69
274
  }
70
275
  ```
71
276
 
72
- With the corresponding output:
277
+ **Terminal: Custom Command Help**
278
+ ```bash
279
+ $ trv custom:arg -h
280
+
281
+ Usage: doc/cli.custom:arg [options] [volume:number]
282
+
283
+ Options:
284
+ -m, --message <string> The message to send back to the user (default: "hello")
285
+ -h, --help display help for command
286
+ ```
73
287
 
74
- **Terminal: Echo Command Help**
288
+ **Terminal: Custom Command Help with overridden Text**
75
289
  ```bash
76
- $ trv echo --help
290
+ $ trv custom:arg 10 -m cUsToM
291
+
292
+ CUSTOM
293
+ ```
294
+
295
+ **Terminal: Custom Command Help with default Text**
296
+ ```bash
297
+ $ trv custom:arg 6
298
+
299
+ hello
300
+ ```
301
+
302
+ ## Environment Variable Support
303
+ In addition to standard flag overriding (e.g. `/** @alias -m */`), the command execution also supports allowing environment variables to provide values (secondary to whatever is passed in on the command line).
304
+
305
+ **Code: Custom Command with Env Var**
306
+ ```typescript
307
+ import { CliCommand } from '@travetto/cli';
308
+ import { Max, Min } from '@travetto/schema';
77
309
 
78
- Usage: echo [options] [args...]
310
+ /**
311
+ * Custom Argument Command
312
+ */
313
+ @CliCommand()
314
+ export class CustomCommand {
315
+
316
+ /**
317
+ * The message to send back to the user
318
+ * @alias env.MESSAGE
319
+ */
320
+ text: string = 'hello';
321
+
322
+ main(@Min(1) @Max(10) volume: number = 1) {
323
+ console.log(volume > 7 ? this.text.toUpperCase() : this.text);
324
+ }
325
+ }
326
+ ```
327
+
328
+ **Terminal: Custom Command Help**
329
+ ```bash
330
+ $ trv custom:env-arg -h
331
+
332
+ Usage: doc/cli.custom:env-arg [options] [volume:number]
79
333
 
80
334
  Options:
81
- -u, --uppercase Upper case
82
- -h, --help display help for command
335
+ -t, --text <string> The message to send back to the user (default: "hello")
336
+ -h, --help display help for command
83
337
  ```
84
338
 
85
- And actually using it:
339
+ **Terminal: Custom Command Help with default Text**
340
+ ```bash
341
+ $ trv custom:env-arg 6
342
+
343
+ hello
344
+ ```
345
+
346
+ **Terminal: Custom Command Help with overridden Text**
347
+ ```bash
348
+ $ MESSAGE=CuStOm trv custom:env-arg 10
349
+
350
+ CUSTOM
351
+ ```
86
352
 
87
- **Terminal: Echo Command Run**
353
+ **Terminal: Custom Command Help with overridden Text**
88
354
  ```bash
89
- $ trv echo -u bOb rOb DRoP
355
+ $ MESSAGE=CuStOm trv custom:env-arg 7
356
+
357
+ CuStOm
358
+ ```
359
+
360
+ ## VSCode Integration
361
+ By default, cli commands do not expose themselves to the VSCode extension, as the majority of them are not intended for that sort of operation. [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") does expose a cli target `run:rest` that will show up, to help run/debug a rest application. Any command can mark itself as being a run target, and will be eligible for running from within the [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=arcsine.travetto-plugin).
362
+
363
+ **Code: Simple Run Target**
364
+ ```typescript
365
+ import { CliCommand } from '@travetto/cli';
366
+
367
+ /**
368
+ * Simple Run Target
369
+ */
370
+ @CliCommand({ runTarget: true })
371
+ export class RunCommand {
372
+
373
+ main(name: string) {
374
+ console.log(name);
375
+ }
376
+ }
377
+ ```
378
+
379
+ Also, any command name that starts with `run:` (i.e. `support/cli.run_*.ts`), will be opted-in to the run behavior unless explicitly disabled.
380
+
381
+ ## Advanced Usage
382
+ If the goal is to run a more complex application, which may include depending on [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."), we can take a look at [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.")'s target:
383
+
384
+ **Code: Simple Run Target**
385
+ ```typescript
386
+ import { DependencyRegistry } from '@travetto/di';
387
+ import { CliCommand } from '@travetto/cli';
388
+ import { ServerHandle } from '../src/types';
90
389
 
91
- [ 'BOB', 'ROB', 'DROP' ]
390
+ /**
391
+ * Run a rest server as an application
392
+ */
393
+ @CliCommand({ fields: ['module', 'env', 'profile'] })
394
+ export class RunRestCommand {
395
+
396
+ /** Port to run on */
397
+ port?: number;
398
+
399
+ envInit(): Record<string, string | number | boolean> {
400
+ return this.port ? { REST_PORT: `${this.port}` } : {};
401
+ }
402
+
403
+ async main(): Promise<ServerHandle> {
404
+ const { RestApplication } = await import('../src/application/rest.js');
405
+ return DependencyRegistry.runInstance(RestApplication);
406
+ }
407
+ }
92
408
  ```
409
+
410
+ As noted in the example above, `fields` is specified in this execution, with support for `module`, `env`, and `profile`. These env and profile flags are directly tied to the GlobalEnv flags defined in the [Base](https://github.com/travetto/travetto/tree/main/module/base#readme "Environment config and common utilities for travetto applications.") module.
411
+
412
+ The `module` field is slightly more complex, but is geared towards supporting commands within a monorepo context. This flag ensures that a module is specified if running from the root of the monorepo, and that the module provided is real, and can run the desired command. When running from an explicit module folder in the monorepo, the module flag is ignored.
package/__index__.ts CHANGED
@@ -1,7 +1,10 @@
1
- export * from './src/command';
2
- export * from './src/command-manager';
1
+ export * from './src/types';
2
+ export * from './src/decorators';
3
3
  export * from './src/execute';
4
+ export * from './src/schema';
5
+ export * from './src/registry';
4
6
  export * from './src/help';
5
7
  export * from './src/color';
6
8
  export * from './src/module';
7
9
  export * from './src/scm';
10
+ export * from './src/util';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "version": "3.0.2",
3
+ "version": "3.1.0-rc.0",
4
4
  "description": "CLI infrastructure for Travetto framework",
5
5
  "keywords": [
6
6
  "cli",
@@ -24,10 +24,9 @@
24
24
  "directory": "module/cli"
25
25
  },
26
26
  "dependencies": {
27
- "@travetto/base": "^3.0.2",
28
- "@travetto/terminal": "^3.0.2",
29
- "@travetto/worker": "^3.0.2",
30
- "commander": "^10.0.0"
27
+ "@travetto/schema": "^3.1.0-rc.0",
28
+ "@travetto/terminal": "^3.1.0-rc.0",
29
+ "@travetto/worker": "^3.1.0-rc.0"
31
30
  },
32
31
  "travetto": {
33
32
  "displayName": "Command Line Interface"
package/src/color.ts CHANGED
@@ -7,12 +7,12 @@ const tplFn = GlobalTerminal.templateFunction({
7
7
  path: 'teal',
8
8
  success: 'green',
9
9
  failure: 'red',
10
- param: 'yellow',
10
+ param: ['yellow', 'goldenrod'],
11
11
  type: 'cyan',
12
- description: 'white',
13
- title: 'brightWhite',
12
+ description: ['white', 'gray'],
13
+ title: ['brightWhite', 'black'],
14
14
  identifier: 'dodgerBlue',
15
- subtitle: 'lightGray',
15
+ subtitle: ['lightGray', 'darkGray'],
16
16
  subsubtitle: 'darkGray'
17
17
  });
18
18
 
@@ -0,0 +1,104 @@
1
+ import { Class, ClassInstance, ConcreteClass, ConsoleManager, defineGlobalEnv } from '@travetto/base';
2
+ import { RootIndex } from '@travetto/manifest';
3
+ import { SchemaRegistry } from '@travetto/schema';
4
+
5
+ import { CliCommandShape } from './types';
6
+ import { CliCommandRegistry } from './registry';
7
+ import { CliModuleUtil } from './module';
8
+ import { CliUtil } from './util';
9
+
10
+ type ExtraFields = 'module' | 'profile' | 'env';
11
+
12
+ const getName = (source: string): string => source.match(/cli.(.*)[.]tsx?$/)![1].replaceAll('_', ':');
13
+ const getMod = (cls: Class): string => RootIndex.getModuleFromSource(RootIndex.getFunctionMetadata(cls)!.source)!.name;
14
+
15
+ /**
16
+ * Decorator to register a CLI command
17
+ * @augments `@travetto/schema:Schema`
18
+ * @augments `@travetto/cli:CliCommand`
19
+ */
20
+ export function CliCommand(cfg: { fields?: ExtraFields[], runTarget?: boolean, hidden?: boolean } = {}) {
21
+ return function <T extends CliCommandShape>(target: Class<T>): void {
22
+ const meta = RootIndex.getFunctionMetadata(target);
23
+ if (!meta || meta.abstract) {
24
+ return;
25
+ }
26
+
27
+ const name = getName(meta.source);
28
+ const addEnv = cfg.fields?.includes('env');
29
+ const addProfile = cfg.fields?.includes('profile');
30
+ const addModule = cfg.fields?.includes('module');
31
+
32
+ CliCommandRegistry.registerClass({
33
+ module: getMod(target),
34
+ name,
35
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
36
+ cls: target as ConcreteClass<T>,
37
+ hidden: cfg.hidden,
38
+ runTarget: cfg.runTarget ?? name.startsWith('run:'),
39
+ preMain: (cmd: CliCommandShape & { env?: string, profile?: string[], module?: string }) => {
40
+ if (addEnv) { defineGlobalEnv({ envName: cmd.env }); }
41
+ if (addProfile) { defineGlobalEnv({ profiles: cmd.profile }); }
42
+ if (addEnv || addProfile) { ConsoleManager.setDebugFromEnv(); }
43
+ if (addModule && cmd.module && cmd.module !== RootIndex.mainModule.name) { // Mono-repo support
44
+ RootIndex.reinitForModule(cmd.module); // Reinit with specified module
45
+ }
46
+ }
47
+ });
48
+
49
+ const pendingCls = SchemaRegistry.getOrCreatePending(target);
50
+
51
+ if (addEnv) {
52
+ SchemaRegistry.registerPendingFieldConfig(target, 'env', String, {
53
+ aliases: ['e'],
54
+ description: 'Application environment',
55
+ required: { active: false }
56
+ });
57
+ }
58
+
59
+ if (addProfile) {
60
+ SchemaRegistry.registerPendingFieldConfig(target, 'profile', [String], {
61
+ aliases: ['p'],
62
+ description: 'Additional application profiles',
63
+ required: { active: false }
64
+ });
65
+ }
66
+
67
+ if (addModule) {
68
+ SchemaRegistry.registerPendingFieldConfig(target, 'module', String, {
69
+ aliases: ['m', 'env.TRV_MODULE'],
70
+ description: 'Module to run for',
71
+ required: { active: CliUtil.monoRoot }
72
+ });
73
+
74
+ // Register validator for module
75
+ (pendingCls.validators ??= []).push(item =>
76
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
77
+ CliModuleUtil.validateCommandModule(getMod(target), item as { module?: string })
78
+ );
79
+ }
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Decorator to register a CLI command flag
85
+ */
86
+ export function CliFlag(cfg: { name?: string, short?: string, desc?: string, file?: boolean, envVars?: string[] }) {
87
+ return function (target: ClassInstance, prop: string | symbol): void {
88
+ const aliases: string[] = [];
89
+ if (cfg.name) {
90
+ aliases.push(cfg.name.startsWith('-') ? cfg.name : `--${cfg.name}`);
91
+ }
92
+ if (cfg.short) {
93
+ aliases.push(cfg.short.startsWith('-') ? cfg.short : `-${cfg.short}`);
94
+ }
95
+ if (cfg.envVars) {
96
+ aliases.push(...cfg.envVars.map(v => `env.${v}`));
97
+ }
98
+ if (typeof prop === 'string') {
99
+ SchemaRegistry.registerPendingFieldFacet(target.constructor, prop, {
100
+ aliases, description: cfg.desc, specifier: cfg.file ? 'file' : undefined
101
+ });
102
+ }
103
+ };
104
+ }