@travetto/cli 7.0.0-rc.5 → 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 +5 -5
- package/package.json +3 -3
- package/src/registry/decorator.ts +43 -29
- package/src/trv.d.ts +6 -2
- package/src/types.ts +1 -1
- package/src/util.ts +6 -14
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
|
|
@@ -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 */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/cli",
|
|
3
|
-
"version": "7.0.0
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI infrastructure for Travetto framework",
|
|
6
6
|
"keywords": [
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"directory": "module/cli"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@travetto/schema": "^7.0.0
|
|
33
|
-
"@travetto/terminal": "^7.0.0
|
|
32
|
+
"@travetto/schema": "^7.0.0",
|
|
33
|
+
"@travetto/terminal": "^7.0.0"
|
|
34
34
|
},
|
|
35
35
|
"travetto": {
|
|
36
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,30 +56,37 @@ 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
|
|
@@ -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[] = [];
|
|
@@ -103,8 +102,8 @@ export class CliUtil {
|
|
|
103
102
|
/**
|
|
104
103
|
* Dispatch IPC payload
|
|
105
104
|
*/
|
|
106
|
-
static async
|
|
107
|
-
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) {
|
|
108
107
|
return false;
|
|
109
108
|
}
|
|
110
109
|
|
|
@@ -116,7 +115,7 @@ export class CliUtil {
|
|
|
116
115
|
|
|
117
116
|
const env: Record<string, string> = {};
|
|
118
117
|
const request = {
|
|
119
|
-
type: `@travetto/cli
|
|
118
|
+
type: `@travetto/cli:run`,
|
|
120
119
|
data: {
|
|
121
120
|
name: cmd._cfg!.name,
|
|
122
121
|
env,
|
|
@@ -133,13 +132,6 @@ export class CliUtil {
|
|
|
133
132
|
return sent.ok;
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
/**
|
|
137
|
-
* Debug if IPC available
|
|
138
|
-
*/
|
|
139
|
-
static async debugIfIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<boolean> {
|
|
140
|
-
return cmd.debugIpc === true && this.triggerIpc('run', cmd);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
135
|
/**
|
|
144
136
|
* Write data to channel and ensure its flushed before continuing
|
|
145
137
|
*/
|