@travetto/cli 5.0.0-rc.8 → 5.0.0-rc.9
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 -4
- package/package.json +3 -3
- package/src/decorators.ts +2 -4
- package/src/help.ts +7 -9
- package/src/parse.ts +1 -1
- package/src/registry.ts +7 -9
- package/src/schema.ts +8 -16
- package/src/types.ts +8 -7
package/README.md
CHANGED
|
@@ -132,9 +132,9 @@ HELLO
|
|
|
132
132
|
|
|
133
133
|
The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L85) supports the following data types for flags:
|
|
134
134
|
* Boolean values
|
|
135
|
-
* Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#
|
|
136
|
-
* String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#
|
|
137
|
-
* Date values. The [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#
|
|
135
|
+
* Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L171), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L177), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L165), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L106) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L116) decorators help provide additional validation.
|
|
136
|
+
* String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L106), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L116), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L98) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L77) provide additional constraints
|
|
137
|
+
* Date values. The [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L106) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L116) decorators help provide additional validation.
|
|
138
138
|
* String lists. Same as String, but allowing multiple values.
|
|
139
139
|
* Numeric lists. Same as Number, but allowing multiple values.
|
|
140
140
|
|
|
@@ -411,6 +411,7 @@ export class RunCommand {
|
|
|
411
411
|
**Code: Anatomy of a Command**
|
|
412
412
|
```typescript
|
|
413
413
|
export interface CliCommandShape<T extends unknown[] = unknown[]> {
|
|
414
|
+
|
|
414
415
|
/**
|
|
415
416
|
* Parsed state
|
|
416
417
|
*/
|
|
@@ -499,7 +500,7 @@ export class RunRestCommand implements CliCommandShape {
|
|
|
499
500
|
}
|
|
500
501
|
```
|
|
501
502
|
|
|
502
|
-
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/env.ts#
|
|
503
|
+
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/env.ts#L109) `name` defined in the [Base](https://github.com/travetto/travetto/tree/main/module/runtime#readme "Environment config and common utilities for travetto applications.") module.
|
|
503
504
|
|
|
504
505
|
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.
|
|
505
506
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/cli",
|
|
3
|
-
"version": "5.0.0-rc.
|
|
3
|
+
"version": "5.0.0-rc.9",
|
|
4
4
|
"description": "CLI infrastructure for Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"directory": "module/cli"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@travetto/schema": "^5.0.0-rc.
|
|
33
|
-
"@travetto/terminal": "^5.0.0-rc.
|
|
32
|
+
"@travetto/schema": "^5.0.0-rc.9",
|
|
33
|
+
"@travetto/terminal": "^5.0.0-rc.9"
|
|
34
34
|
},
|
|
35
35
|
"travetto": {
|
|
36
36
|
"displayName": "Command Line Interface",
|
package/src/decorators.ts
CHANGED
|
@@ -109,16 +109,14 @@ export function CliCommand(cfg: CliCommandConfigOptions = {}) {
|
|
|
109
109
|
const runtimeModule = cfg.runtimeModule ?? (cfg.with?.module ? 'current' : undefined);
|
|
110
110
|
|
|
111
111
|
if (runtimeModule) { // Validate module
|
|
112
|
-
(pendingCls.validators ??= []).push(async
|
|
113
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
114
|
-
const { module: mod } = item as CliCommandShapeFields;
|
|
112
|
+
(pendingCls.validators ??= []).push(async ({ module: mod }: Partial<CliCommandShapeFields>) => {
|
|
115
113
|
const runModule = (runtimeModule === 'command' ? commandModule : mod) || Runtime.main.name;
|
|
116
114
|
|
|
117
115
|
// If we need to run as a specific module
|
|
118
116
|
if (runModule !== Runtime.main.name) {
|
|
119
117
|
try {
|
|
120
118
|
RuntimeIndex.reinitForModule(runModule);
|
|
121
|
-
} catch
|
|
119
|
+
} catch {
|
|
122
120
|
return { source: 'flag', message: `${runModule} is an unknown module`, kind: 'custom', path: '.' };
|
|
123
121
|
}
|
|
124
122
|
}
|
package/src/help.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import util from 'node:util';
|
|
2
2
|
|
|
3
|
-
import { Primitive } from '@travetto/runtime';
|
|
3
|
+
import { castKey, castTo, Primitive } from '@travetto/runtime';
|
|
4
4
|
|
|
5
5
|
import { cliTpl } from './color';
|
|
6
6
|
import { CliCommandShape } from './types';
|
|
@@ -41,13 +41,11 @@ export class HelpUtil {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const params: string[] = [];
|
|
44
|
-
const
|
|
44
|
+
const descriptions: string[] = [];
|
|
45
45
|
|
|
46
46
|
for (const flag of flags) {
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
50
|
-
const flagVal = command[key] as unknown as Primitive;
|
|
47
|
+
const key = castKey<CliCommandShape>(flag.name);
|
|
48
|
+
const flagVal: Primitive = castTo(command[key]);
|
|
51
49
|
|
|
52
50
|
let aliases = flag.flagNames ?? [];
|
|
53
51
|
if (isBoolFlag(flag)) {
|
|
@@ -68,11 +66,11 @@ export class HelpUtil {
|
|
|
68
66
|
if (key !== 'help' && flagVal !== null && flagVal !== undefined && flagVal !== '') {
|
|
69
67
|
desc.push(cliTpl`(default: ${{ input: JSON.stringify(flagVal) }})`);
|
|
70
68
|
}
|
|
71
|
-
|
|
69
|
+
descriptions.push(desc.join(' '));
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
const paramWidths = params.map(x => util.stripVTControlCharacters(x).length);
|
|
75
|
-
const descWidths =
|
|
73
|
+
const descWidths = descriptions.map(x => util.stripVTControlCharacters(x).length);
|
|
76
74
|
|
|
77
75
|
const paramWidth = Math.max(...paramWidths);
|
|
78
76
|
const descWidth = Math.max(...descWidths);
|
|
@@ -87,7 +85,7 @@ export class HelpUtil {
|
|
|
87
85
|
'',
|
|
88
86
|
cliTpl`${{ title: 'Options:' }}`,
|
|
89
87
|
...params.map((_, i) =>
|
|
90
|
-
` ${params[i]}${' '.repeat((paramWidth - paramWidths[i]))} ${
|
|
88
|
+
` ${params[i]}${' '.repeat((paramWidth - paramWidths[i]))} ${descriptions[i].padEnd(descWidth)}${' '.repeat((descWidth - descWidths[i]))}`
|
|
91
89
|
),
|
|
92
90
|
'',
|
|
93
91
|
...helpText
|
package/src/parse.ts
CHANGED
|
@@ -191,7 +191,7 @@ export class CliParseUtil {
|
|
|
191
191
|
} else {
|
|
192
192
|
const field = schema.args[argIdx];
|
|
193
193
|
out.push(getInput({ field, input, index: argIdx }));
|
|
194
|
-
// Move argIdx along if not in a
|
|
194
|
+
// Move argIdx along if not in a var arg situation
|
|
195
195
|
if (!field?.array) {
|
|
196
196
|
argIdx += 1;
|
|
197
197
|
}
|
package/src/registry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Class,
|
|
1
|
+
import { asConstructable, Class, classConstruct, describeFunction, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
import { CliCommandConfig, CliCommandShape } from './types';
|
|
4
4
|
import { CliUnknownCommandError } from './error';
|
|
@@ -14,9 +14,8 @@ class $CliCommandRegistry {
|
|
|
14
14
|
return this.#commands.get(cls);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return cmd.constructor as Class;
|
|
17
|
+
getClass(cmd: CliCommandShape): Class<CliCommandShape> {
|
|
18
|
+
return asConstructable<CliCommandShape>(cmd).constructor;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
/**
|
|
@@ -40,11 +39,10 @@ class $CliCommandRegistry {
|
|
|
40
39
|
/**
|
|
41
40
|
* Registers a cli command
|
|
42
41
|
*/
|
|
43
|
-
registerClass(cls: Class
|
|
42
|
+
registerClass<T extends CliCommandShape>(cls: Class<T>, cfg: Partial<CliCommandConfig>): CliCommandConfig {
|
|
44
43
|
const meta = describeFunction(cls);
|
|
45
44
|
this.#commands.set(cls, {
|
|
46
|
-
|
|
47
|
-
cls: cls as ConcreteClass,
|
|
45
|
+
cls,
|
|
48
46
|
name: getName(meta.import),
|
|
49
47
|
commandModule: meta.module,
|
|
50
48
|
...cfg,
|
|
@@ -56,7 +54,7 @@ class $CliCommandRegistry {
|
|
|
56
54
|
* Get config for a given instance
|
|
57
55
|
*/
|
|
58
56
|
getConfig(cmd: CliCommandShape): CliCommandConfig {
|
|
59
|
-
return this.getByClass(this
|
|
57
|
+
return this.getByClass(this.getClass(cmd))!;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
/**
|
|
@@ -80,7 +78,7 @@ class $CliCommandRegistry {
|
|
|
80
78
|
for (const v of values) {
|
|
81
79
|
const cfg = this.getByClass(v);
|
|
82
80
|
if (cfg) {
|
|
83
|
-
const inst =
|
|
81
|
+
const inst = classConstruct(cfg.cls);
|
|
84
82
|
if (!inst.isActive || inst.isActive()) {
|
|
85
83
|
inst._cfg = this.getConfig(inst);
|
|
86
84
|
return inst;
|
package/src/schema.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Class } from '@travetto/runtime';
|
|
1
|
+
import { castKey, castTo, Class } from '@travetto/runtime';
|
|
2
2
|
import { BindUtil, FieldConfig, SchemaRegistry, SchemaValidator, ValidationResultError } from '@travetto/schema';
|
|
3
3
|
|
|
4
4
|
import { CliCommandRegistry } from './registry';
|
|
@@ -52,8 +52,7 @@ export class CliCommandSchemaUtil {
|
|
|
52
52
|
* Get schema for a given command
|
|
53
53
|
*/
|
|
54
54
|
static async getSchema(src: Class | CliCommandShape): Promise<CliCommandSchema> {
|
|
55
|
-
|
|
56
|
-
const cls = 'main' in src ? src.constructor as Class : src;
|
|
55
|
+
const cls = 'main' in src ? CliCommandRegistry.getClass(src) : src;
|
|
57
56
|
if (this.#schemas.has(cls)) {
|
|
58
57
|
return this.#schemas.get(cls)!;
|
|
59
58
|
}
|
|
@@ -127,22 +126,18 @@ export class CliCommandSchemaUtil {
|
|
|
127
126
|
for (const arg of state.all) {
|
|
128
127
|
switch (arg.type) {
|
|
129
128
|
case 'flag': {
|
|
130
|
-
|
|
131
|
-
const key = arg.fieldName as keyof T;
|
|
129
|
+
const key = castKey<T>(arg.fieldName);
|
|
132
130
|
const value = arg.value!;
|
|
133
131
|
if (arg.array) {
|
|
134
|
-
|
|
135
|
-
((template[key] as unknown[]) ??= []).push(value);
|
|
132
|
+
castTo<unknown[]>(template[key] ??= castTo([])).push(value);
|
|
136
133
|
} else {
|
|
137
|
-
|
|
138
|
-
template[key] = value as unknown as T[typeof key];
|
|
134
|
+
template[key] = castTo(value);
|
|
139
135
|
}
|
|
140
136
|
break;
|
|
141
137
|
}
|
|
142
138
|
case 'arg': {
|
|
143
139
|
if (arg.array) {
|
|
144
|
-
|
|
145
|
-
((bound[arg.index] ??= []) as unknown[]).push(arg.input);
|
|
140
|
+
castTo<unknown[]>(bound[arg.index] ??= []).push(arg.input);
|
|
146
141
|
} else {
|
|
147
142
|
bound[arg.index] = arg.input;
|
|
148
143
|
}
|
|
@@ -150,8 +145,7 @@ export class CliCommandSchemaUtil {
|
|
|
150
145
|
}
|
|
151
146
|
}
|
|
152
147
|
|
|
153
|
-
|
|
154
|
-
const cls = cmd.constructor as Class<CliCommandShape>;
|
|
148
|
+
const cls = CliCommandRegistry.getClass(cmd);
|
|
155
149
|
BindUtil.bindSchemaToObject(cls, cmd, template);
|
|
156
150
|
return BindUtil.coerceMethodParams(cls, 'main', bound);
|
|
157
151
|
}
|
|
@@ -160,9 +154,7 @@ export class CliCommandSchemaUtil {
|
|
|
160
154
|
* Validate command shape with the given arguments
|
|
161
155
|
*/
|
|
162
156
|
static async validate(cmd: CliCommandShape, args: unknown[]): Promise<typeof cmd> {
|
|
163
|
-
|
|
164
|
-
const cls = cmd.constructor as Class<CliCommandShape>;
|
|
165
|
-
|
|
157
|
+
const cls = CliCommandRegistry.getClass(cmd);
|
|
166
158
|
const paramNames = SchemaRegistry.getMethodSchema(cls, 'main').map(x => x.name);
|
|
167
159
|
|
|
168
160
|
const validators = [
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Class } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
type OrProm<T> = T | Promise<T>;
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ export type CliCommandConfig = {
|
|
|
19
19
|
name: string;
|
|
20
20
|
commandModule: string;
|
|
21
21
|
runTarget?: boolean;
|
|
22
|
-
cls:
|
|
22
|
+
cls: Class<CliCommandShape>;
|
|
23
23
|
hidden?: boolean;
|
|
24
24
|
preMain?: (cmd: CliCommandShape) => void | Promise<void>;
|
|
25
25
|
};
|
|
@@ -49,6 +49,7 @@ export type CliValidationError = {
|
|
|
49
49
|
* CLI Command Contract
|
|
50
50
|
*/
|
|
51
51
|
export interface CliCommandShape<T extends unknown[] = unknown[]> {
|
|
52
|
+
|
|
52
53
|
/**
|
|
53
54
|
* Parsed state
|
|
54
55
|
*/
|
|
@@ -116,7 +117,7 @@ export type CliCommandShapeFields = {
|
|
|
116
117
|
/**
|
|
117
118
|
* CLI Command argument/flag shape
|
|
118
119
|
*/
|
|
119
|
-
export type CliCommandInput = {
|
|
120
|
+
export type CliCommandInput<K extends string = string> = {
|
|
120
121
|
name: string;
|
|
121
122
|
description?: string;
|
|
122
123
|
type: 'string' | 'file' | 'number' | 'boolean' | 'date' | 'regex' | 'module';
|
|
@@ -125,19 +126,19 @@ export type CliCommandInput = {
|
|
|
125
126
|
required?: boolean;
|
|
126
127
|
array?: boolean;
|
|
127
128
|
default?: unknown;
|
|
128
|
-
flagNames?:
|
|
129
|
+
flagNames?: K[];
|
|
129
130
|
envVars?: string[];
|
|
130
131
|
};
|
|
131
132
|
|
|
132
133
|
/**
|
|
133
134
|
* CLI Command schema shape
|
|
134
135
|
*/
|
|
135
|
-
export
|
|
136
|
+
export interface CliCommandSchema<K extends string = string> {
|
|
136
137
|
name: string;
|
|
137
138
|
title: string;
|
|
138
139
|
commandModule: string;
|
|
139
140
|
runTarget?: boolean;
|
|
140
141
|
description?: string;
|
|
141
142
|
args: CliCommandInput[];
|
|
142
|
-
flags: CliCommandInput[];
|
|
143
|
-
}
|
|
143
|
+
flags: CliCommandInput<K>[];
|
|
144
|
+
}
|