@travetto/cli 3.4.0-rc.9 → 3.4.1
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/LICENSE +1 -1
- package/README.md +4 -4
- package/package.json +3 -3
- package/src/decorators.ts +2 -2
- package/src/execute.ts +3 -12
- package/src/help.ts +1 -1
- package/src/registry.ts +3 -3
- package/src/schema.ts +123 -97
- package/src/types.ts +2 -2
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -170,7 +170,7 @@ Options:
|
|
|
170
170
|
$ trv basic:arg 20
|
|
171
171
|
|
|
172
172
|
Execution failed:
|
|
173
|
-
* Argument
|
|
173
|
+
* Argument volume is bigger than (10)
|
|
174
174
|
|
|
175
175
|
Usage: basic:arg [options] [volume:number]
|
|
176
176
|
|
|
@@ -233,7 +233,7 @@ $ trv basic:arglist 10 5 3 9 8 1
|
|
|
233
233
|
$ trv basic:arglist 10 5 3 9 20 1
|
|
234
234
|
|
|
235
235
|
Execution failed:
|
|
236
|
-
* Argument [4] is bigger than (10)
|
|
236
|
+
* Argument volumes[4] is bigger than (10)
|
|
237
237
|
|
|
238
238
|
Usage: basic:arglist [options] <volumes...:number>
|
|
239
239
|
|
|
@@ -390,7 +390,7 @@ export interface CliCommandShape {
|
|
|
390
390
|
/**
|
|
391
391
|
* Setup environment before command runs
|
|
392
392
|
*/
|
|
393
|
-
envInit?(): OrProm<
|
|
393
|
+
envInit?(): OrProm<EnvInit>;
|
|
394
394
|
/**
|
|
395
395
|
* Extra help
|
|
396
396
|
*/
|
|
@@ -454,7 +454,7 @@ export class RunRestCommand {
|
|
|
454
454
|
}
|
|
455
455
|
```
|
|
456
456
|
|
|
457
|
-
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 [GlobalEnv](https://github.com/travetto/travetto/tree/main/module/base/src/global-env.ts#
|
|
457
|
+
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 [GlobalEnv](https://github.com/travetto/travetto/tree/main/module/base/src/global-env.ts#L9) flags defined in the [Base](https://github.com/travetto/travetto/tree/main/module/base#readme "Environment config and common utilities for travetto applications.") module.
|
|
458
458
|
|
|
459
459
|
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.
|
|
460
460
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/cli",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.1",
|
|
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": "^3.4.0
|
|
33
|
-
"@travetto/terminal": "^3.4.0
|
|
32
|
+
"@travetto/schema": "^3.4.0",
|
|
33
|
+
"@travetto/terminal": "^3.4.0"
|
|
34
34
|
},
|
|
35
35
|
"travetto": {
|
|
36
36
|
"displayName": "Command Line Interface"
|
package/src/decorators.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Class, ClassInstance, ConsoleManager, GlobalEnv,
|
|
1
|
+
import { Class, ClassInstance, ConsoleManager, GlobalEnv, defineEnv } from '@travetto/base';
|
|
2
2
|
import { RootIndex } from '@travetto/manifest';
|
|
3
3
|
import { SchemaRegistry } from '@travetto/schema';
|
|
4
4
|
|
|
@@ -26,7 +26,7 @@ export function CliCommand(cfg: CliCommandConfigOptions = {}) {
|
|
|
26
26
|
hidden: cfg.hidden,
|
|
27
27
|
preMain: async (cmd) => {
|
|
28
28
|
if (addEnv && 'env' in cmd && typeof cmd.env === 'string') {
|
|
29
|
-
|
|
29
|
+
defineEnv({ envName: cmd.env });
|
|
30
30
|
ConsoleManager.setDebug(GlobalEnv.debug, GlobalEnv.devMode);
|
|
31
31
|
}
|
|
32
32
|
}
|
package/src/execute.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GlobalTerminal } from '@travetto/terminal';
|
|
2
|
-
import { ConsoleManager,
|
|
2
|
+
import { ConsoleManager, defineEnv, ShutdownManager, GlobalEnv } from '@travetto/base';
|
|
3
3
|
|
|
4
4
|
import { HelpUtil } from './help';
|
|
5
5
|
import { CliCommandShape } from './types';
|
|
@@ -14,20 +14,11 @@ export class ExecutionManager {
|
|
|
14
14
|
|
|
15
15
|
static async #envInit(cmd: CliCommandShape): Promise<void> {
|
|
16
16
|
if (cmd.envInit) {
|
|
17
|
-
|
|
17
|
+
defineEnv(await cmd.envInit());
|
|
18
18
|
ConsoleManager.setDebug(GlobalEnv.debug, GlobalEnv.devMode);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
static async #bindAndValidateArgs(cmd: CliCommandShape, args: string[]): Promise<unknown[]> {
|
|
23
|
-
await cmd.initialize?.();
|
|
24
|
-
const remainingArgs = await CliCommandSchemaUtil.bindFlags(cmd, args);
|
|
25
|
-
const [known, unknown] = await CliCommandSchemaUtil.bindArgs(cmd, remainingArgs);
|
|
26
|
-
await cmd.finalize?.(unknown);
|
|
27
|
-
await CliCommandSchemaUtil.validate(cmd, known);
|
|
28
|
-
return known;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
22
|
/**
|
|
32
23
|
* Run help
|
|
33
24
|
*/
|
|
@@ -41,7 +32,7 @@ export class ExecutionManager {
|
|
|
41
32
|
* Run the given command object with the given arguments
|
|
42
33
|
*/
|
|
43
34
|
static async command(cmd: CliCommandShape, args: string[]): Promise<void> {
|
|
44
|
-
const known = await
|
|
35
|
+
const known = await CliCommandSchemaUtil.bindAndValidateArgs(cmd, args);
|
|
45
36
|
await this.#envInit(cmd);
|
|
46
37
|
const cfg = CliCommandRegistry.getConfig(cmd);
|
|
47
38
|
await cfg?.preMain?.(cmd);
|
package/src/help.ts
CHANGED
|
@@ -105,7 +105,7 @@ export class HelpUtil {
|
|
|
105
105
|
if (inst) {
|
|
106
106
|
const cfg = await CliCommandRegistry.getConfig(inst);
|
|
107
107
|
if (!cfg.hidden) {
|
|
108
|
-
const schema = await CliCommandSchemaUtil.getSchema(
|
|
108
|
+
const schema = await CliCommandSchemaUtil.getSchema(cfg.cls);
|
|
109
109
|
rows.push(cliTpl` ${{ param: cmd.padEnd(maxWidth, ' ') }} ${{ title: schema.title }}`);
|
|
110
110
|
}
|
|
111
111
|
}
|
package/src/registry.ts
CHANGED
|
@@ -29,7 +29,7 @@ class $CliCommandRegistry {
|
|
|
29
29
|
#commands = new Map<Class, CliCommandConfig>();
|
|
30
30
|
#fileMapping: Map<string, string>;
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
getByClass(cls: Class): CliCommandConfig | undefined {
|
|
33
33
|
return this.#commands.get(cls);
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -75,7 +75,7 @@ class $CliCommandRegistry {
|
|
|
75
75
|
* Get config for a given instance
|
|
76
76
|
*/
|
|
77
77
|
getConfig(cmd: CliCommandShape): CliCommandConfig {
|
|
78
|
-
return this
|
|
78
|
+
return this.getByClass(this.#getClass(cmd))!;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
@@ -97,7 +97,7 @@ class $CliCommandRegistry {
|
|
|
97
97
|
if (found) {
|
|
98
98
|
const values = Object.values<Class>(await import(found));
|
|
99
99
|
for (const v of values) {
|
|
100
|
-
const cfg = this
|
|
100
|
+
const cfg = this.getByClass(v);
|
|
101
101
|
if (cfg) {
|
|
102
102
|
const inst = new cfg.cls();
|
|
103
103
|
if (!inst.isActive || inst.isActive()) {
|
package/src/schema.ts
CHANGED
|
@@ -5,14 +5,34 @@ import { CliCommandRegistry } from './registry';
|
|
|
5
5
|
import { CliCommandInput, CliCommandSchema, CliCommandShape } from './types';
|
|
6
6
|
import { CliValidationResultError } from './error';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const VALID_FLAG = /^-{1,2}[a-z]/i;
|
|
9
|
+
const LONG_FLAG = /^--[a-z][^= ]+/i;
|
|
10
|
+
const LONG_FLAG_WITH_EQ = /^--[a-z][^= ]+=\S+/i;
|
|
11
|
+
const SHORT_FLAG = /^-[a-z]/i;
|
|
12
|
+
|
|
13
|
+
type ParsedInput =
|
|
14
|
+
{ type: 'unknown', input: string } |
|
|
15
|
+
{ type: 'arg', input: string, array?: boolean } |
|
|
16
|
+
{ type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
|
|
17
|
+
|
|
18
|
+
const isBoolFlag = (x?: CliCommandInput): boolean => x?.type === 'boolean' && !x.array;
|
|
19
|
+
|
|
20
|
+
const getInput = (cfg: { field?: CliCommandInput, rawText?: string, input: string, value?: string }): ParsedInput => {
|
|
21
|
+
const { field, input, rawText = input, value } = cfg;
|
|
22
|
+
if (!field) {
|
|
23
|
+
return { type: 'unknown', input: rawText };
|
|
24
|
+
} else if (!field.flagNames?.length) {
|
|
25
|
+
return { type: 'arg', input: field ? input : rawText ?? input, array: field.array };
|
|
12
26
|
} else {
|
|
13
|
-
return
|
|
27
|
+
return {
|
|
28
|
+
type: 'flag',
|
|
29
|
+
fieldName: field.name,
|
|
30
|
+
array: field.array,
|
|
31
|
+
input: field ? input : rawText ?? input,
|
|
32
|
+
value: value ?? (isBoolFlag(field) ? !input.startsWith('--no-') : undefined)
|
|
33
|
+
};
|
|
14
34
|
}
|
|
15
|
-
}
|
|
35
|
+
};
|
|
16
36
|
|
|
17
37
|
function fieldToInput(x: FieldConfig): CliCommandInput {
|
|
18
38
|
const type = x.type === Date ? 'date' :
|
|
@@ -34,12 +54,6 @@ function fieldToInput(x: FieldConfig): CliCommandInput {
|
|
|
34
54
|
});
|
|
35
55
|
}
|
|
36
56
|
|
|
37
|
-
const VALID_FLAG = /^-{1,2}[a-z]/i;
|
|
38
|
-
const LONG_FLAG = /^--[a-z]/i;
|
|
39
|
-
const SHORT_FLAG = /^-[a-z]/i;
|
|
40
|
-
|
|
41
|
-
const isBoolFlag = (x: CliCommandInput): boolean => x.type === 'boolean' && !x.array;
|
|
42
|
-
|
|
43
57
|
/**
|
|
44
58
|
* Allows binding describing/binding inputs for commands
|
|
45
59
|
*/
|
|
@@ -50,10 +64,9 @@ export class CliCommandSchemaUtil {
|
|
|
50
64
|
/**
|
|
51
65
|
* Get schema for a given command
|
|
52
66
|
*/
|
|
53
|
-
static async getSchema(
|
|
67
|
+
static async getSchema(src: Class | CliCommandShape): Promise<CliCommandSchema> {
|
|
54
68
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
55
|
-
const cls =
|
|
56
|
-
|
|
69
|
+
const cls = 'main' in src ? src.constructor as Class : src;
|
|
57
70
|
if (this.#schemas.has(cls)) {
|
|
58
71
|
return this.#schemas.get(cls)!;
|
|
59
72
|
}
|
|
@@ -110,7 +123,7 @@ export class CliCommandSchemaUtil {
|
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
const fullSchema = SchemaRegistry.get(cls);
|
|
113
|
-
const { cls: _cls, preMain: _preMain, ...meta } = CliCommandRegistry.
|
|
126
|
+
const { cls: _cls, preMain: _preMain, ...meta } = CliCommandRegistry.getByClass(cls)!;
|
|
114
127
|
const cfg: CliCommandSchema = {
|
|
115
128
|
...meta,
|
|
116
129
|
args: method,
|
|
@@ -123,111 +136,107 @@ export class CliCommandSchemaUtil {
|
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
/**
|
|
126
|
-
*
|
|
139
|
+
* Parse inputs to command
|
|
127
140
|
*/
|
|
128
|
-
static async
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
let i = 0;
|
|
136
|
-
|
|
137
|
-
for (const el of schema.args) {
|
|
138
|
-
// Siphon off unrecognized flags, in order
|
|
139
|
-
while (i < copy.length && VALID_FLAG.test(copy[i])) {
|
|
140
|
-
i += 1;
|
|
141
|
-
}
|
|
141
|
+
static async parse<T extends CliCommandShape>(cls: Class<T>, inputs: string[]): Promise<ParsedInput[]> {
|
|
142
|
+
const schema = await this.getSchema(cls);
|
|
143
|
+
const flagMap = new Map<string, CliCommandInput>(
|
|
144
|
+
schema.flags.flatMap(f => (f.flagNames ?? []).map(name => [name, f]))
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const out: ParsedInput[] = [];
|
|
142
148
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
// Load env vars to front
|
|
150
|
+
for (const field of schema.flags) {
|
|
151
|
+
for (const envName of field.envVars ?? []) {
|
|
152
|
+
if (envName in process.env) {
|
|
153
|
+
const value: string = process.env[envName]!;
|
|
154
|
+
if (field.array) {
|
|
155
|
+
out.push(...value.split(/\s*,\s*/g).map(v => getInput({ field, input: `env.${envName}`, value: v })));
|
|
156
|
+
} else {
|
|
157
|
+
out.push(getInput({ field, input: `env.${envName}`, value }));
|
|
151
158
|
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let argIdx = 0;
|
|
164
|
+
|
|
165
|
+
for (let i = 0; i < inputs.length; i += 1) {
|
|
166
|
+
const input = inputs[i];
|
|
167
|
+
|
|
168
|
+
if (input === '--') { // Raw separator
|
|
169
|
+
out.push(...inputs.slice(i + 1).map(x => getInput({ input: x })));
|
|
170
|
+
break;
|
|
171
|
+
} else if (LONG_FLAG_WITH_EQ.test(input)) {
|
|
172
|
+
const [k, ...v] = input.split('=');
|
|
173
|
+
const field = flagMap.get(k);
|
|
174
|
+
out.push(getInput({ field, rawText: input, input: k, value: v.join('=') }));
|
|
175
|
+
} else if (VALID_FLAG.test(input)) { // Flag
|
|
176
|
+
const field = flagMap.get(input);
|
|
177
|
+
const next = inputs[i + 1];
|
|
178
|
+
if ((next && (VALID_FLAG.test(next) || next === '--')) || isBoolFlag(field)) {
|
|
179
|
+
out.push(getInput({ field, input }));
|
|
180
|
+
} else {
|
|
181
|
+
out.push(getInput({ field, input, value: next }));
|
|
152
182
|
i += 1;
|
|
153
183
|
}
|
|
154
|
-
out.push(sub);
|
|
155
184
|
} else {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
185
|
+
const field = schema.args[argIdx];
|
|
186
|
+
out.push(getInput({ field, input }));
|
|
187
|
+
// Move argIdx along if not in a vararg situation
|
|
188
|
+
if (!field?.array) {
|
|
189
|
+
argIdx += 1;
|
|
190
|
+
}
|
|
159
191
|
}
|
|
160
192
|
}
|
|
161
193
|
|
|
162
|
-
|
|
163
|
-
return [
|
|
164
|
-
BindUtil.coerceMethodParams(cls, 'main', out, true),
|
|
165
|
-
final
|
|
166
|
-
];
|
|
194
|
+
return out;
|
|
167
195
|
}
|
|
168
196
|
|
|
169
197
|
/**
|
|
170
198
|
* Bind arguments to command
|
|
171
199
|
*/
|
|
172
|
-
static async bindFlags<T extends CliCommandShape>(cmd: T, args:
|
|
173
|
-
const schema = await this.getSchema(cmd);
|
|
174
|
-
|
|
175
|
-
const [base, extra] = split(args);
|
|
176
|
-
const copy = base.flatMap(k => (k.startsWith('--') && k.includes('=')) ? k.split('=') : [k]);
|
|
177
|
-
|
|
200
|
+
static async bindFlags<T extends CliCommandShape>(cmd: T, args: ParsedInput[]): Promise<void> {
|
|
178
201
|
const template: Partial<T> = {};
|
|
179
202
|
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
flagMap.set(name, flag);
|
|
184
|
-
}
|
|
185
|
-
for (const envName of flag.envVars ?? []) {
|
|
186
|
-
if (envName in process.env) {
|
|
187
|
-
let val: string | string[] = process.env[envName]!;
|
|
188
|
-
if (flag.array) {
|
|
189
|
-
val = val.split(/\s*,\s*/g);
|
|
190
|
-
}
|
|
203
|
+
for (const arg of args) {
|
|
204
|
+
switch (arg.type) {
|
|
205
|
+
case 'flag': {
|
|
191
206
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
192
|
-
|
|
207
|
+
const key = arg.fieldName as keyof T;
|
|
208
|
+
const value = arg.value!;
|
|
209
|
+
if (arg.array) {
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
211
|
+
((template[key] as unknown[]) ??= []).push(value);
|
|
212
|
+
} else {
|
|
213
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
214
|
+
template[key] = value as unknown as T[typeof key];
|
|
215
|
+
}
|
|
193
216
|
}
|
|
194
217
|
}
|
|
195
218
|
}
|
|
196
219
|
|
|
197
|
-
const out = [];
|
|
198
|
-
for (let i = 0; i < copy.length; i += 1) {
|
|
199
|
-
const arg = copy[i];
|
|
200
|
-
const next = copy[i + 1];
|
|
201
|
-
|
|
202
|
-
const input = flagMap.get(arg);
|
|
203
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
204
|
-
const key = input?.name as keyof T;
|
|
205
|
-
if (!input) {
|
|
206
|
-
out.push(arg);
|
|
207
|
-
} else if (isBoolFlag(input)) {
|
|
208
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
209
|
-
template[key] = !arg.startsWith('--no') as T[typeof key];
|
|
210
|
-
} else if (next === undefined || VALID_FLAG.test(next)) {
|
|
211
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
212
|
-
template[key] = null as T[typeof key];
|
|
213
|
-
} else if (input.array) {
|
|
214
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
215
|
-
const arr = template[key] ??= [] as T[typeof key];
|
|
216
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
217
|
-
(arr as unknown[]).push(next);
|
|
218
|
-
i += 1; // Skip next
|
|
219
|
-
} else {
|
|
220
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
221
|
-
template[key] = next as T[typeof key];
|
|
222
|
-
i += 1; // Skip next
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
220
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
227
221
|
const cls = cmd.constructor as Class<CliCommandShape>;
|
|
228
222
|
BindUtil.bindSchemaToObject(cls, cmd, template);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Produce the arguments into the final argument set
|
|
227
|
+
*/
|
|
228
|
+
static async bindArgs(cmd: CliCommandShape, args: ParsedInput[]): Promise<unknown[]> {
|
|
229
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
230
|
+
const cls = cmd.constructor as Class<CliCommandShape>;
|
|
231
|
+
const out = args.filter(x => x.type === 'arg').map(x => x.input);
|
|
232
|
+
return BindUtil.coerceMethodParams(cls, 'main', out, true);
|
|
233
|
+
}
|
|
229
234
|
|
|
230
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Get the unused arguments
|
|
237
|
+
*/
|
|
238
|
+
static getUnusedArgs(args: ParsedInput[]): string[] {
|
|
239
|
+
return args.filter(x => x.type === 'unknown').map(x => x.input);
|
|
231
240
|
}
|
|
232
241
|
|
|
233
242
|
/**
|
|
@@ -237,9 +246,11 @@ export class CliCommandSchemaUtil {
|
|
|
237
246
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
238
247
|
const cls = cmd.constructor as Class<CliCommandShape>;
|
|
239
248
|
|
|
249
|
+
const paramNames = SchemaRegistry.getMethodSchema(cls, 'main').map(x => x.name);
|
|
250
|
+
|
|
240
251
|
const validators = [
|
|
241
252
|
(): Promise<void> => SchemaValidator.validate(cls, cmd).then(() => { }),
|
|
242
|
-
(): Promise<void> => SchemaValidator.validateMethod(cls, 'main', args),
|
|
253
|
+
(): Promise<void> => SchemaValidator.validateMethod(cls, 'main', args, paramNames),
|
|
243
254
|
async (): Promise<void> => {
|
|
244
255
|
const res = await cmd.validate?.(...args);
|
|
245
256
|
if (res) {
|
|
@@ -263,4 +274,19 @@ export class CliCommandSchemaUtil {
|
|
|
263
274
|
}
|
|
264
275
|
return cmd;
|
|
265
276
|
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Bind and validate a command with a given set of arguments
|
|
280
|
+
*/
|
|
281
|
+
static async bindAndValidateArgs(cmd: CliCommandShape, args: string[]): Promise<unknown[]> {
|
|
282
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
283
|
+
const cls = cmd.constructor as Class;
|
|
284
|
+
await cmd.initialize?.();
|
|
285
|
+
const parsed = await this.parse(cls, args);
|
|
286
|
+
await this.bindFlags(cmd, parsed);
|
|
287
|
+
const known = await this.bindArgs(cmd, parsed);
|
|
288
|
+
await cmd.finalize?.(this.getUnusedArgs(parsed));
|
|
289
|
+
await this.validate(cmd, known);
|
|
290
|
+
return known;
|
|
291
|
+
}
|
|
266
292
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Closeable,
|
|
1
|
+
import { Closeable, EnvInit } from '@travetto/base';
|
|
2
2
|
|
|
3
3
|
type OrProm<T> = T | Promise<T>;
|
|
4
4
|
|
|
@@ -29,7 +29,7 @@ export interface CliCommandShape {
|
|
|
29
29
|
/**
|
|
30
30
|
* Setup environment before command runs
|
|
31
31
|
*/
|
|
32
|
-
envInit?(): OrProm<
|
|
32
|
+
envInit?(): OrProm<EnvInit>;
|
|
33
33
|
/**
|
|
34
34
|
* Extra help
|
|
35
35
|
*/
|