@travetto/cli 7.0.0-rc.4 → 7.0.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 +16 -16
- package/bin/trv.js +2 -5
- package/package.json +4 -3
- package/src/registry/decorator.ts +44 -30
- package/src/registry/registry-index.ts +0 -1
- package/src/trv.d.ts +6 -2
- package/src/types.ts +1 -1
- package/src/util.ts +6 -15
- package/support/cli.cli_schema.ts +0 -1
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ This module also has a tight integration with the [VSCode plugin](https://market
|
|
|
59
59
|
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:
|
|
60
60
|
* The file must be located in the `support/` folder, and have a name that matches `cli.*.ts`
|
|
61
61
|
* The file must be a class that has a main method
|
|
62
|
-
* The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
62
|
+
* The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) decorator
|
|
63
63
|
|
|
64
64
|
**Code: Basic Command**
|
|
65
65
|
```typescript
|
|
@@ -94,7 +94,7 @@ Examples of mappings:
|
|
|
94
94
|
The pattern is that underscores(_) translate to colons (:), and the `cli.` prefix, and `.ts` suffix are dropped.
|
|
95
95
|
|
|
96
96
|
## Binding Flags
|
|
97
|
-
[@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
97
|
+
[@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19) class. The fields of the class represent the flags that are available to the command.
|
|
98
98
|
|
|
99
99
|
**Code: Basic Command with Flag**
|
|
100
100
|
```typescript
|
|
@@ -131,7 +131,7 @@ $ trv basic:flag --loud
|
|
|
131
131
|
HELLO
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
134
|
+
The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) supports the following data types for flags:
|
|
135
135
|
* Boolean values
|
|
136
136
|
* Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L166), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L173), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L159), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L93) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L104) decorators help provide additional validation.
|
|
137
137
|
* String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L93), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L104), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L84) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L58) provide additional constraints
|
|
@@ -213,9 +213,9 @@ export class BasicCommand {
|
|
|
213
213
|
|
|
214
214
|
**Terminal: Basic Command**
|
|
215
215
|
```bash
|
|
216
|
-
$ trv basic:
|
|
216
|
+
$ trv basic:arg-list -h
|
|
217
217
|
|
|
218
|
-
Usage: basic:
|
|
218
|
+
Usage: basic:arg-list [options] <volumes...:number>
|
|
219
219
|
|
|
220
220
|
Options:
|
|
221
221
|
-r, --reverse
|
|
@@ -224,19 +224,19 @@ Options:
|
|
|
224
224
|
|
|
225
225
|
**Terminal: Basic Arg List**
|
|
226
226
|
```bash
|
|
227
|
-
$ trv basic:
|
|
227
|
+
$ trv basic:arg-list 10 5 3 9 8 1
|
|
228
228
|
|
|
229
229
|
1 3 5 8 9 10
|
|
230
230
|
```
|
|
231
231
|
|
|
232
232
|
**Terminal: Basic Arg List with Invalid Number**
|
|
233
233
|
```bash
|
|
234
|
-
$ trv basic:
|
|
234
|
+
$ trv basic:arg-list 10 5 3 9 20 1
|
|
235
235
|
|
|
236
236
|
Execution failed:
|
|
237
237
|
* Argument volumes[4] is greater than (10)
|
|
238
238
|
|
|
239
|
-
Usage: basic:
|
|
239
|
+
Usage: basic:arg-list [options] <volumes...:number>
|
|
240
240
|
|
|
241
241
|
Options:
|
|
242
242
|
-r, --reverse
|
|
@@ -245,7 +245,7 @@ Options:
|
|
|
245
245
|
|
|
246
246
|
**Terminal: Basic Arg List with Reverse**
|
|
247
247
|
```bash
|
|
248
|
-
$ trv basic:
|
|
248
|
+
$ trv basic:arg-list -r 10 5 3 9 8 1
|
|
249
249
|
|
|
250
250
|
10 9 8 5 3 1
|
|
251
251
|
```
|
|
@@ -390,7 +390,7 @@ npx trv call:db --host localhost --port 3306 --username app --password <custom>
|
|
|
390
390
|
```
|
|
391
391
|
|
|
392
392
|
## VSCode Integration
|
|
393
|
-
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. [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative support for creating Web Applications") does expose a cli target `web:http` that will show up, to help run/debug a web 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). This is achieved by setting the `runTarget` field on the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#
|
|
393
|
+
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. [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative support for creating Web Applications") does expose a cli target `web:http` that will show up, to help run/debug a web 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). This is achieved by setting the `runTarget` field on the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) decorator. This means the target will be visible within the editor tooling.
|
|
394
394
|
|
|
395
395
|
**Code: Simple Run Target**
|
|
396
396
|
```typescript
|
|
@@ -472,7 +472,7 @@ import type { WebHttpServer } from '../src/types.ts';
|
|
|
472
472
|
/**
|
|
473
473
|
* Run a web server
|
|
474
474
|
*/
|
|
475
|
-
@CliCommand({ runTarget: true, with: { debugIpc:
|
|
475
|
+
@CliCommand({ runTarget: true, with: { debugIpc: 'optional', restartOnChange: true, module: true, env: true } })
|
|
476
476
|
export class WebHttpCommand implements CliCommandShape {
|
|
477
477
|
|
|
478
478
|
/** Port to run on */
|
|
@@ -502,7 +502,7 @@ export class WebHttpCommand implements CliCommandShape {
|
|
|
502
502
|
}
|
|
503
503
|
```
|
|
504
504
|
|
|
505
|
-
As noted in the example above, `fields` is specified in this execution, with support for `module`, and `env`. These env flag is directly tied to the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime/src/context.ts#
|
|
505
|
+
As noted in the example above, `fields` is specified in this execution, with support for `module`, and `env`. These env flag is directly tied to the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime/src/context.ts#L12) `name` defined in the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime#readme "Runtime for travetto applications.") module.
|
|
506
506
|
|
|
507
507
|
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.
|
|
508
508
|
|
|
@@ -550,13 +550,13 @@ Options:
|
|
|
550
550
|
Available Services
|
|
551
551
|
--------------------
|
|
552
552
|
* dynamodb@3.1.0
|
|
553
|
-
* elasticsearch@9.2.
|
|
553
|
+
* elasticsearch@9.2.3
|
|
554
554
|
* firestore@latest
|
|
555
555
|
* mongodb@8.2
|
|
556
556
|
* mysql@9.5
|
|
557
557
|
* postgresql@18.1
|
|
558
558
|
* redis@8.4
|
|
559
|
-
* s3@4.
|
|
559
|
+
* s3@4.11.0
|
|
560
560
|
```
|
|
561
561
|
|
|
562
562
|
A sample of all services available to the entire framework:
|
|
@@ -568,13 +568,13 @@ $ trv service status
|
|
|
568
568
|
Service Version Status
|
|
569
569
|
-------------------------------------------------
|
|
570
570
|
dynamodb 3.1.0 Running 93af422e793a
|
|
571
|
-
elasticsearch 9.2.
|
|
571
|
+
elasticsearch 9.2.3 Running ed76ee063d13
|
|
572
572
|
firestore latest Running feec2e5e95b4
|
|
573
573
|
mongodb 8.2 Running 5513eba6734e
|
|
574
574
|
mysql 9.5 Running 307bc66d442a
|
|
575
575
|
postgresql 18.1 Running e78291e71040
|
|
576
576
|
redis 8.4 Running 77ba279b4e30
|
|
577
|
-
s3 4.
|
|
577
|
+
s3 4.11.0 Running fdacfc55b9e3
|
|
578
578
|
```
|
|
579
579
|
|
|
580
580
|
### Defining new Services
|
package/bin/trv.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
globalThis.__entry_point__ = __filename;
|
|
4
|
-
|
|
5
2
|
// @ts-check
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { load } from '@travetto/compiler/bin/entry.common.js';
|
|
4
|
+
load(operations => operations.exec('@travetto/cli/support/entry.trv.js'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/cli",
|
|
3
|
-
"version": "7.0.0
|
|
3
|
+
"version": "7.0.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "CLI infrastructure for Travetto framework",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"cli",
|
|
@@ -28,8 +29,8 @@
|
|
|
28
29
|
"directory": "module/cli"
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
31
|
-
"@travetto/schema": "^7.0.0
|
|
32
|
-
"@travetto/terminal": "^7.0.0
|
|
32
|
+
"@travetto/schema": "^7.0.0",
|
|
33
|
+
"@travetto/terminal": "^7.0.0"
|
|
33
34
|
},
|
|
34
35
|
"travetto": {
|
|
35
36
|
"displayName": "Command Line Interface",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Class, ClassInstance, Env, Runtime, RuntimeIndex, describeFunction, getClass } from '@travetto/runtime';
|
|
1
|
+
import { Class, ClassInstance, Env, Runtime, RuntimeIndex, TypedObject, castTo, describeFunction, getClass } from '@travetto/runtime';
|
|
2
2
|
import { SchemaFieldConfig, SchemaRegistryIndex, ValidationError } from '@travetto/schema';
|
|
3
3
|
|
|
4
4
|
import { CliCommandShape } from '../types.ts';
|
|
@@ -18,19 +18,23 @@ type CliCommandConfigOptions = {
|
|
|
18
18
|
/** Module to run for */
|
|
19
19
|
module?: boolean;
|
|
20
20
|
/** Should debug invocation trigger via ipc */
|
|
21
|
-
debugIpc?: boolean;
|
|
22
|
-
/** Should restart on
|
|
23
|
-
|
|
21
|
+
debugIpc?: boolean | 'optional';
|
|
22
|
+
/** Should restart on source change */
|
|
23
|
+
restartOnChange?: boolean | 'optional';
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
type WithConfig = Required<Exclude<CliCommandConfigOptions['with'], undefined>>;
|
|
28
|
+
type WithHandler<K extends keyof WithConfig> = (config?: WithConfig[K]) => ({
|
|
29
|
+
name: K;
|
|
29
30
|
field: Partial<SchemaFieldConfig>;
|
|
30
|
-
run
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
run?: (cmd: Cmd) => (Promise<unknown> | unknown);
|
|
32
|
+
} | undefined)
|
|
33
|
+
|
|
34
|
+
const FIELD_CONFIG: { [K in keyof WithConfig]: WithHandler<K> } = {
|
|
35
|
+
env: (config) => {
|
|
36
|
+
if (!config) return;
|
|
37
|
+
return {
|
|
34
38
|
name: 'env',
|
|
35
39
|
run: cmd => Env.TRV_ENV.set(cmd.env || Runtime.env),
|
|
36
40
|
field: {
|
|
@@ -39,10 +43,12 @@ const FIELD_CONFIG: {
|
|
|
39
43
|
description: 'Application environment',
|
|
40
44
|
required: { active: false },
|
|
41
45
|
},
|
|
42
|
-
}
|
|
43
|
-
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
module: (config) => {
|
|
49
|
+
if (!config) return;
|
|
50
|
+
return {
|
|
44
51
|
name: 'module',
|
|
45
|
-
run: (): void => { },
|
|
46
52
|
field: {
|
|
47
53
|
type: String,
|
|
48
54
|
aliases: ['-m', CliParseUtil.toEnvField(Env.TRV_MODULE.key)],
|
|
@@ -50,36 +56,43 @@ const FIELD_CONFIG: {
|
|
|
50
56
|
specifiers: ['module'],
|
|
51
57
|
required: { active: Runtime.monoRoot },
|
|
52
58
|
},
|
|
53
|
-
}
|
|
54
|
-
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
debugIpc: (config) => {
|
|
62
|
+
if (!config) return;
|
|
63
|
+
return {
|
|
55
64
|
name: 'debugIpc',
|
|
56
|
-
run: cmd => CliUtil.
|
|
65
|
+
run: cmd => CliUtil.runWithDebugIpc(cmd).then((executed) => executed && process.exit(0)),
|
|
57
66
|
field: {
|
|
58
67
|
type: Boolean,
|
|
59
|
-
aliases: ['-di'],
|
|
68
|
+
aliases: ['-di', CliParseUtil.toEnvField(Env.TRV_DEBUG_IPC.key)],
|
|
60
69
|
description: 'Should debug invocation trigger via ipc',
|
|
61
|
-
default:
|
|
70
|
+
default: config !== 'optional',
|
|
62
71
|
required: { active: false },
|
|
63
72
|
},
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
restartOnChange: (config) => {
|
|
76
|
+
if (!config) return;
|
|
77
|
+
return {
|
|
78
|
+
name: 'restartOnChange',
|
|
79
|
+
run: cmd => CliUtil.runWithRestartOnChange(cmd),
|
|
68
80
|
field: {
|
|
69
81
|
type: Boolean,
|
|
70
|
-
aliases: ['-
|
|
82
|
+
aliases: ['-rc', CliParseUtil.toEnvField(Env.TRV_RESTART_ON_CHANGE.key)],
|
|
71
83
|
description: 'Should the invocation automatically restart on source changes',
|
|
72
|
-
default: Runtime.envType === 'development',
|
|
84
|
+
default: config !== 'optional' && Runtime.envType === 'development',
|
|
73
85
|
required: { active: false },
|
|
74
86
|
},
|
|
75
|
-
}
|
|
76
|
-
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
};
|
|
77
90
|
|
|
78
91
|
/**
|
|
79
92
|
* Decorator to register a CLI command
|
|
80
93
|
*
|
|
81
94
|
* @augments `@travetto/schema:Schema`
|
|
82
|
-
* @example main
|
|
95
|
+
* @example method:main
|
|
83
96
|
* @kind decorator
|
|
84
97
|
*/
|
|
85
98
|
export function CliCommand(config: CliCommandConfigOptions = {}) {
|
|
@@ -91,13 +104,13 @@ export function CliCommand(config: CliCommandConfigOptions = {}) {
|
|
|
91
104
|
return;
|
|
92
105
|
}
|
|
93
106
|
|
|
94
|
-
const VALID_FIELDS = FIELD_CONFIG.
|
|
107
|
+
const VALID_FIELDS = TypedObject.keys(FIELD_CONFIG).map((name) => FIELD_CONFIG[name](castTo(config.with?.[name]))).filter(x => !!x);
|
|
95
108
|
|
|
96
109
|
CliCommandRegistryIndex.getForRegister(target).register({
|
|
97
110
|
runTarget: config.runTarget,
|
|
98
111
|
preMain: async (cmd: Cmd) => {
|
|
99
112
|
for (const field of VALID_FIELDS) {
|
|
100
|
-
await field.run(cmd);
|
|
113
|
+
await field.run?.(cmd);
|
|
101
114
|
}
|
|
102
115
|
}
|
|
103
116
|
});
|
|
@@ -105,7 +118,8 @@ export function CliCommand(config: CliCommandConfigOptions = {}) {
|
|
|
105
118
|
const commandModule = description.module;
|
|
106
119
|
|
|
107
120
|
for (const { name, field: { type, ...field } } of VALID_FIELDS) {
|
|
108
|
-
adapter.registerField(name,
|
|
121
|
+
adapter.registerField(name, { type }, field);
|
|
122
|
+
Object.defineProperty(target.prototype, name, { value: field.default, writable: true });
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
const runtimeModule = config.runtimeModule ?? (config.with?.module ? 'current' : undefined);
|
package/src/trv.d.ts
CHANGED
|
@@ -8,8 +8,12 @@ declare module '@travetto/runtime' {
|
|
|
8
8
|
*/
|
|
9
9
|
TRV_CLI_IPC: string;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Overrides behavior for allowing restart on changes
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
TRV_RESTART_ON_CHANGE: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Overrides behavior for triggering debug session via IPC
|
|
16
|
+
*/
|
|
17
|
+
TRV_DEBUG_IPC: boolean;
|
|
14
18
|
}
|
|
15
19
|
}
|
package/src/types.ts
CHANGED
package/src/util.ts
CHANGED
|
@@ -37,9 +37,8 @@ export class CliUtil {
|
|
|
37
37
|
/**
|
|
38
38
|
* Run a command as restartable, linking into self
|
|
39
39
|
*/
|
|
40
|
-
static async
|
|
41
|
-
|
|
42
|
-
if (Env.TRV_CAN_RESTART.isFalse || cmd.restartForDev !== true) {
|
|
40
|
+
static async runWithRestartOnChange<T extends CliCommandShapeFields & CliCommandShape>(cmd: T, config?: RunWithRestartOptions): Promise<boolean> {
|
|
41
|
+
if (cmd.restartOnChange !== true) {
|
|
43
42
|
process.on('message', event => isCodeRestart(event) && process.exit(event.code));
|
|
44
43
|
return false;
|
|
45
44
|
}
|
|
@@ -48,7 +47,7 @@ export class CliUtil {
|
|
|
48
47
|
let exhaustedRestarts = false;
|
|
49
48
|
let subProcess: ChildProcess | undefined;
|
|
50
49
|
|
|
51
|
-
const env = { ...process.env, ...Env.
|
|
50
|
+
const env = { ...process.env, ...Env.TRV_RESTART_ON_CHANGE.export(false) };
|
|
52
51
|
const maxRetries = config?.maxRetriesPerMinute ?? 5;
|
|
53
52
|
const relayInterrupt = config?.relayInterrupt ?? true;
|
|
54
53
|
const restarts: number[] = [];
|
|
@@ -92,7 +91,6 @@ export class CliUtil {
|
|
|
92
91
|
restarts.push(Date.now());
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
|
|
96
94
|
if (exhaustedRestarts) {
|
|
97
95
|
console.error(`Bailing, due to ${maxRetries} restarts in under 10s`);
|
|
98
96
|
}
|
|
@@ -104,8 +102,8 @@ export class CliUtil {
|
|
|
104
102
|
/**
|
|
105
103
|
* Dispatch IPC payload
|
|
106
104
|
*/
|
|
107
|
-
static async
|
|
108
|
-
if (!Env.TRV_CLI_IPC.isSet) {
|
|
105
|
+
static async runWithDebugIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<boolean> {
|
|
106
|
+
if (cmd.debugIpc !== true || !Env.TRV_CLI_IPC.isSet) {
|
|
109
107
|
return false;
|
|
110
108
|
}
|
|
111
109
|
|
|
@@ -117,7 +115,7 @@ export class CliUtil {
|
|
|
117
115
|
|
|
118
116
|
const env: Record<string, string> = {};
|
|
119
117
|
const request = {
|
|
120
|
-
type: `@travetto/cli
|
|
118
|
+
type: `@travetto/cli:run`,
|
|
121
119
|
data: {
|
|
122
120
|
name: cmd._cfg!.name,
|
|
123
121
|
env,
|
|
@@ -134,13 +132,6 @@ export class CliUtil {
|
|
|
134
132
|
return sent.ok;
|
|
135
133
|
}
|
|
136
134
|
|
|
137
|
-
/**
|
|
138
|
-
* Debug if IPC available
|
|
139
|
-
*/
|
|
140
|
-
static async debugIfIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<boolean> {
|
|
141
|
-
return cmd.debugIpc === true && this.triggerIpc('run', cmd);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
135
|
/**
|
|
145
136
|
* Write data to channel and ensure its flushed before continuing
|
|
146
137
|
*/
|