@travetto/cli 3.0.0-rc.7 → 3.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 +2 -7
- package/package.json +5 -5
- package/src/command-manager.ts +2 -2
- package/src/command.ts +18 -13
- package/src/execute.ts +35 -16
- package/src/help.ts +5 -4
- package/src/module.ts +5 -5
- package/support/cli.exec.ts +2 -2
- package/support/cli.list.ts +1 -1
- package/support/cli.ts +3 -0
- package/support/main.cli.ts +0 -8
package/README.md
CHANGED
|
@@ -27,8 +27,6 @@ Options:
|
|
|
27
27
|
Commands:
|
|
28
28
|
echo [options] [args...]
|
|
29
29
|
help [command] display help for command
|
|
30
|
-
|
|
31
|
-
[s[r[u
|
|
32
30
|
```
|
|
33
31
|
|
|
34
32
|
This will show all the available options/choices that are exposed given the currently installed modules.
|
|
@@ -50,7 +48,7 @@ export class CliEchoCommand extends CliCommand {
|
|
|
50
48
|
name = 'echo';
|
|
51
49
|
|
|
52
50
|
getOptions() {
|
|
53
|
-
return { uppercase: this.boolOption({ desc: 'Upper case'
|
|
51
|
+
return { uppercase: this.boolOption({ desc: 'Upper case' }) };
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
getArgs() {
|
|
@@ -75,10 +73,8 @@ $ trv echo --help
|
|
|
75
73
|
Usage: echo [options] [args...]
|
|
76
74
|
|
|
77
75
|
Options:
|
|
78
|
-
-u, --uppercase Upper case
|
|
76
|
+
-u, --uppercase Upper case
|
|
79
77
|
-h, --help display help for command
|
|
80
|
-
|
|
81
|
-
[s[r[u
|
|
82
78
|
```
|
|
83
79
|
|
|
84
80
|
And actually using it:
|
|
@@ -88,5 +84,4 @@ And actually using it:
|
|
|
88
84
|
$ trv echo -u bOb rOb DRoP
|
|
89
85
|
|
|
90
86
|
[ 'BOB', 'ROB', 'DROP' ]
|
|
91
|
-
[s[r[u
|
|
92
87
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/cli",
|
|
3
|
-
"version": "3.0.0-rc.
|
|
3
|
+
"version": "3.0.0-rc.9",
|
|
4
4
|
"description": "CLI infrastructure for travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"directory": "module/cli"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@travetto/base": "^3.0.0-rc.
|
|
30
|
-
"@travetto/terminal": "^3.0.0-rc.
|
|
31
|
-
"@travetto/worker": "^3.0.0-rc.
|
|
32
|
-
"commander": "^
|
|
29
|
+
"@travetto/base": "^3.0.0-rc.8",
|
|
30
|
+
"@travetto/terminal": "^3.0.0-rc.6",
|
|
31
|
+
"@travetto/worker": "^3.0.0-rc.8",
|
|
32
|
+
"commander": "^10.0.0"
|
|
33
33
|
},
|
|
34
34
|
"travetto": {
|
|
35
35
|
"displayName": "Command Line Interface"
|
package/src/command-manager.ts
CHANGED
|
@@ -24,8 +24,8 @@ export class CliCommandManager {
|
|
|
24
24
|
*/
|
|
25
25
|
static getCommandMapping(): Map<string, string> {
|
|
26
26
|
const all = new Map<string, string>();
|
|
27
|
-
for (const { output } of RootIndex.findSupport({ filter: /\/cli[.]/, checkProfile: false })) {
|
|
28
|
-
all.set(output.replace(/^.*\/cli[.](.*?)[.][^.]+$/, (_, f) => f),
|
|
27
|
+
for (const { outputFile: output, import: imp } of RootIndex.findSupport({ filter: /\/cli[.]/, checkProfile: false })) {
|
|
28
|
+
all.set(output.replace(/^.*\/cli[.](.*?)[.][^.]+$/, (_, f) => f), imp);
|
|
29
29
|
}
|
|
30
30
|
return all;
|
|
31
31
|
}
|
package/src/command.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { appendFile, mkdir } from 'fs/promises';
|
|
2
|
-
import type
|
|
2
|
+
import type commander from 'commander';
|
|
3
3
|
|
|
4
4
|
import { path } from '@travetto/manifest';
|
|
5
5
|
import { ConsoleManager, DataUtil, defineGlobalEnv, GlobalEnvConfig, ShutdownManager } from '@travetto/base';
|
|
@@ -74,7 +74,7 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
|
|
|
74
74
|
/**
|
|
75
75
|
* Get args
|
|
76
76
|
*/
|
|
77
|
-
getArgs?(): string;
|
|
77
|
+
getArgs?(): string | undefined;
|
|
78
78
|
/**
|
|
79
79
|
* Initialization code for adding options
|
|
80
80
|
*/
|
|
@@ -135,8 +135,8 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
|
|
|
135
135
|
boolOption(cfg: OptionConfig<boolean>): OptionConfig<boolean> {
|
|
136
136
|
return {
|
|
137
137
|
type: Boolean,
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
combine: (val, curr): boolean =>
|
|
139
|
+
(val !== undefined ? DataUtil.coerceType(val, Boolean, false) : undefined) ?? curr,
|
|
140
140
|
completion: true,
|
|
141
141
|
...cfg
|
|
142
142
|
};
|
|
@@ -217,18 +217,23 @@ export abstract class CliCommand<V extends OptionMap = OptionMap> {
|
|
|
217
217
|
if (this.init) {
|
|
218
218
|
cmd = await this.init?.(cmd);
|
|
219
219
|
}
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
const args = this.getArgs?.();
|
|
221
|
+
if (args) {
|
|
222
|
+
cmd = cmd.arguments(args);
|
|
222
223
|
}
|
|
223
224
|
for (const cfg of await this.finalizeOptions()) {
|
|
224
|
-
|
|
225
|
-
if (cfg.type
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
const pre = cfg.short ? `-${cfg.short}, ` : '';
|
|
226
|
+
if (cfg.type === Boolean) {
|
|
227
|
+
if (cfg.def) {
|
|
228
|
+
cmd.option(`${pre}--no-${cfg.name}`, `Disables: ${cfg.desc}`);
|
|
229
|
+
} else {
|
|
230
|
+
cmd.option(`${pre}--${cfg.name}`, cfg.desc);
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
const key = `${pre}--${cfg.name} <${cfg.name}>`;
|
|
229
234
|
// @ts-expect-error
|
|
230
|
-
cmd.option(key, cfg.desc, cfg.combine, cfg.def)
|
|
231
|
-
|
|
235
|
+
cmd = cmd.option(key, cfg.desc, cfg.combine ?? ((cur, acc): unknown => cur), cfg.def);
|
|
236
|
+
}
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
cmd = cmd.action(this.runAction.bind(this));
|
package/src/execute.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
1
2
|
import { program as commander } from 'commander';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import { PackageUtil, path, RootIndex } from '@travetto/manifest';
|
|
4
5
|
import { GlobalTerminal } from '@travetto/terminal';
|
|
5
|
-
import {
|
|
6
|
+
import { ShutdownManager } from '@travetto/base';
|
|
6
7
|
|
|
7
8
|
import { CliCommandManager } from './command-manager';
|
|
8
9
|
import { HelpUtil } from './help';
|
|
@@ -15,9 +16,7 @@ export class ExecutionManager {
|
|
|
15
16
|
/**
|
|
16
17
|
* Run command
|
|
17
18
|
*/
|
|
18
|
-
static async runCommand(args: string[]): Promise<void> {
|
|
19
|
-
const cmd = args[2];
|
|
20
|
-
|
|
19
|
+
static async runCommand(cmd: string, args: string[]): Promise<void> {
|
|
21
20
|
let command;
|
|
22
21
|
|
|
23
22
|
try {
|
|
@@ -32,7 +31,7 @@ export class ExecutionManager {
|
|
|
32
31
|
if (args.includes('-h') || args.includes('--help')) {
|
|
33
32
|
return command.showHelp();
|
|
34
33
|
} else {
|
|
35
|
-
await commander.parseAsync(args);
|
|
34
|
+
await commander.parseAsync([process.argv[0], process.argv[1], cmd, ...args]);
|
|
36
35
|
}
|
|
37
36
|
} catch (err) {
|
|
38
37
|
if (!(err instanceof Error)) {
|
|
@@ -44,27 +43,47 @@ export class ExecutionManager {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Run file expecting a main method
|
|
48
|
+
*/
|
|
49
|
+
static async runMain(file: string, args: string[]): Promise<void> {
|
|
50
|
+
try {
|
|
51
|
+
// If referenced file exists
|
|
52
|
+
if (await (fs.stat(path.resolve(file)).then(() => true, () => false))) {
|
|
53
|
+
file = path.join(RootIndex.manifest.mainModule, file);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const imp = RootIndex.getFromImport(file)?.import;
|
|
57
|
+
if (!imp) {
|
|
58
|
+
throw new Error(`Unknown file: ${file}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const mod = await import(imp);
|
|
62
|
+
await ShutdownManager.exitWithResponse(await mod.main(...args));
|
|
63
|
+
} catch (err) {
|
|
64
|
+
await ShutdownManager.exitWithResponse(err, true);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
47
68
|
/**
|
|
48
69
|
* Execute the command line
|
|
49
70
|
* @param args
|
|
50
71
|
*/
|
|
51
|
-
static async run(
|
|
72
|
+
static async run(argv: string[]): Promise<void> {
|
|
73
|
+
const { init } = await import('@travetto/base/support/init.js');
|
|
74
|
+
await init();
|
|
75
|
+
|
|
52
76
|
const width = GlobalTerminal.width;
|
|
53
77
|
commander
|
|
54
78
|
.version(PackageUtil.getFrameworkVersion())
|
|
55
79
|
.configureOutput({ getOutHelpWidth: () => width, getErrHelpWidth: () => width });
|
|
56
80
|
|
|
57
|
-
const cmd =
|
|
58
|
-
|
|
81
|
+
const [, , cmd, ...args] = argv;
|
|
59
82
|
if (cmd === 'main') {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
mainFile = path.join(RootIndex.manifest.mainModule, mainFile);
|
|
63
|
-
mainFile = RootIndex.resolveFileImport(mainFile);
|
|
64
|
-
}
|
|
65
|
-
await runMain((await import(mainFile)).main, process.argv.slice(4));
|
|
83
|
+
const [file, ...rest] = args;
|
|
84
|
+
await this.runMain(file, rest);
|
|
66
85
|
} else if (cmd && !cmd.startsWith('-')) {
|
|
67
|
-
await this.runCommand(args);
|
|
86
|
+
await this.runCommand(cmd, args);
|
|
68
87
|
} else {
|
|
69
88
|
// Load all commands
|
|
70
89
|
await CliCommandManager.loadAllCommands(x => x.setup(commander));
|
package/src/help.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type commander from 'commander';
|
|
2
2
|
|
|
3
3
|
import { cliTpl } from './color';
|
|
4
4
|
|
|
5
5
|
const TYPE_PATTERN = /(\[[^\]]+\])/g;
|
|
6
|
+
const REQ_TYPE_PATTERN = /(<[^>]+>)/g;
|
|
6
7
|
const TITLE_PATTERN = /^(\S[^:]+:)/gim;
|
|
7
8
|
|
|
8
9
|
const OPTIONS_PATTERN = new RegExp([
|
|
@@ -32,7 +33,7 @@ const COMMANDS_PATTERN = new RegExp([
|
|
|
32
33
|
'(?<space>[ ]+)',
|
|
33
34
|
'(?<name>\\S+)',
|
|
34
35
|
'(?<optionsSpace>[ ]+)?',
|
|
35
|
-
'(?<options
|
|
36
|
+
'(?<options>(?:\\[|<).*(?:\\]|>))?',
|
|
36
37
|
'((?<descriptionSpace>[ ]+)(?<description>[a-z][^\\n\\[]+))?',
|
|
37
38
|
'(?:[ ]+)?',
|
|
38
39
|
'$',
|
|
@@ -50,7 +51,7 @@ const USAGE_PATTERN = new RegExp([
|
|
|
50
51
|
'(?<space>[ ]+)?',
|
|
51
52
|
'(?<name>[^\\[ ]+)?',
|
|
52
53
|
'(?<nameSpace>[ ]+)?',
|
|
53
|
-
'(?<options
|
|
54
|
+
'(?<options>(?:\\[|<).*(?:\\]|>))?',
|
|
54
55
|
'(?:[ ]+)?',
|
|
55
56
|
'$',
|
|
56
57
|
].join(''), 'gim');
|
|
@@ -135,7 +136,7 @@ export class HelpUtil {
|
|
|
135
136
|
space,
|
|
136
137
|
cliTpl`${{ param: name }}`,
|
|
137
138
|
optionsSpace,
|
|
138
|
-
options?.replace(TYPE_PATTERN, input => cliTpl`${{ input }}`),
|
|
139
|
+
options?.replace(TYPE_PATTERN, input => cliTpl`${{ input }}`).replace(REQ_TYPE_PATTERN, type => cliTpl`${{ type }}`),
|
|
139
140
|
descriptionSpace,
|
|
140
141
|
cliTpl`${{ description }}`
|
|
141
142
|
]
|
package/src/module.ts
CHANGED
|
@@ -38,13 +38,13 @@ export class CliModuleUtil {
|
|
|
38
38
|
stdoutTerm: Terminal,
|
|
39
39
|
stderrTerm: Terminal
|
|
40
40
|
): ExecutionOptions {
|
|
41
|
-
const folder = mod.
|
|
41
|
+
const folder = mod.sourceFolder;
|
|
42
42
|
const opts: ExecutionOptions = {
|
|
43
43
|
stdio: ['ignore', 'pipe', 'pipe', 'ignore'],
|
|
44
44
|
outputMode: 'text',
|
|
45
45
|
catchAsResult: true,
|
|
46
46
|
cwd: folder,
|
|
47
|
-
env: { TRV_MANIFEST: '' },
|
|
47
|
+
env: { TRV_MANIFEST: '', TRV_MODULE: mod.name },
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
if (config.showStdout) {
|
|
@@ -62,7 +62,7 @@ export class CliModuleUtil {
|
|
|
62
62
|
* @returns
|
|
63
63
|
*/
|
|
64
64
|
static #buildPrefixes(mods: IndexedModule[]): Record<string, string> {
|
|
65
|
-
const folders = mods.map(x => x.
|
|
65
|
+
const folders = mods.map(x => x.sourceFolder);
|
|
66
66
|
const maxWidth = Math.max(...folders.map(x => x.length));
|
|
67
67
|
return Object.fromEntries(folders.map((x, i) => [x, colorize(x.padStart(maxWidth, ' ').padEnd(maxWidth + 1), i)]));
|
|
68
68
|
}
|
|
@@ -102,14 +102,14 @@ export class CliModuleUtil {
|
|
|
102
102
|
return (mode === 'changed' ?
|
|
103
103
|
await this.findChangedModulesRecursive() :
|
|
104
104
|
[...RootIndex.getModuleList('all')].map(x => RootIndex.getModule(x)!)
|
|
105
|
-
).filter(x => x.
|
|
105
|
+
).filter(x => x.sourcePath !== RootIndex.manifest.workspacePath);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Synchronize all workspace modules to have the correct versions from the current packages
|
|
110
110
|
*/
|
|
111
111
|
static async synchronizeModuleVersions(): Promise<void> {
|
|
112
|
-
await PackageUtil.syncVersions((await this.findModules('all')).map(x => x.
|
|
112
|
+
await PackageUtil.syncVersions((await this.findModules('all')).map(x => x.sourcePath));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
package/support/cli.exec.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class RepoExecCommand extends CliCommand<Options> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
getArgs(): string {
|
|
33
|
-
return '
|
|
33
|
+
return '<command> [...args]';
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
envInit(): GlobalEnvConfig {
|
|
@@ -43,7 +43,7 @@ export class RepoExecCommand extends CliCommand<Options> {
|
|
|
43
43
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
44
44
|
(mod, opts) => ExecUtil.spawn(this.args[0], this.args.slice(1), opts),
|
|
45
45
|
{
|
|
46
|
-
progressMessage: mod => `Running '${this.args.join(' ')}' [%idx/%total] ${mod?.
|
|
46
|
+
progressMessage: mod => `Running '${this.args.join(' ')}' [%idx/%total] ${mod?.sourceFolder ?? ''}`,
|
|
47
47
|
showStdout: this.cmd.showStdout,
|
|
48
48
|
prefixOutput: this.cmd.prefixOutput,
|
|
49
49
|
workerCount: this.cmd.workers,
|
package/support/cli.list.ts
CHANGED
|
@@ -29,7 +29,7 @@ export class RepoListCommand extends CliCommand<Options> {
|
|
|
29
29
|
async action(...args: unknown[]): Promise<void> {
|
|
30
30
|
const mods = await CliModuleUtil.findModules(this.cmd.changed ? 'changed' : 'all');
|
|
31
31
|
if (!this.cmd.graph) {
|
|
32
|
-
for (const mod of mods.map(x => x.
|
|
32
|
+
for (const mod of mods.map(x => x.sourceFolder).sort()) {
|
|
33
33
|
console.log!(mod);
|
|
34
34
|
}
|
|
35
35
|
} else {
|
package/support/cli.ts
ADDED