@visulima/cerebro 2.1.5 → 3.0.0-alpha.10
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/CHANGELOG.md +228 -0
- package/LICENSE.md +1810 -98
- package/README.md +28 -21
- package/dist/cli.d.ts +22 -0
- package/dist/commands/completion-command.js +204 -5
- package/dist/commands/help-command.js +200 -1
- package/dist/commands/readme-command.js +326 -32
- package/dist/commands/version-command.js +18 -1
- package/dist/default-env.d.ts +1 -1
- package/dist/index.js +7 -1
- package/dist/logger/create-pail-logger.js +34 -1
- package/dist/packem_chunks/has-new-version.js +264 -1
- package/dist/packem_shared/Cerebro-bgCm5Tb1.js +3444 -0
- package/dist/packem_shared/VERBOSITY_QUIET-Dp46zlLW.js +10 -0
- package/dist/packem_shared/VisulimaError-DA7QsCxH.js +34 -0
- package/dist/packem_shared/cerebro-error-GmJ3jN7Q.js +16 -0
- package/dist/packem_shared/index-CS31xKFe.js +264 -0
- package/dist/packem_shared/runtime-process-B6ZplyWn.js +187 -0
- package/dist/plugins/error-handler-plugin.js +648 -1
- package/dist/plugins/runtime-version-check-plugin.js +77 -1
- package/dist/plugins/update-notifier/update-notifier-plugin.js +517 -1
- package/dist/types/cli.d.ts +11 -0
- package/dist/types/command-line-usage.d.ts +1 -1
- package/dist/types/command.d.ts +10 -10
- package/dist/util/command-processing/option-processor.d.ts +8 -8
- package/dist/util/general/compile-cache.d.ts +41 -0
- package/dist/util/general/compile-cache.js +16 -0
- package/dist/util/general/heap-tuning.d.ts +81 -0
- package/dist/util/general/heap-tuning.js +91 -0
- package/dist/util/general/register-exception-handler.d.ts +1 -1
- package/dist/util/process-env-variables.d.ts +1 -1
- package/package.json +18 -9
- package/dist/packem_shared/Cerebro-CQZ9sj4S.js +0 -4
- package/dist/packem_shared/VERBOSITY_QUIET-XPultrIA.js +0 -1
- package/dist/packem_shared/VisulimaError--04oA1Oy.js +0 -76
- package/dist/packem_shared/cerebro-error-BnJTixb2.js +0 -1
- package/dist/packem_shared/help-command-CIRIXN03.js +0 -1
- package/dist/packem_shared/index-DQ3pvLQH.js +0 -6
- package/dist/packem_shared/isVisulimaError-jVZgumOU-C4fgdbWg.js +0 -1
- package/dist/packem_shared/renderError-ZMlMvw1N-eVUSdl6c.js +0 -24
- package/dist/packem_shared/runtime-process-G-n-wOub.js +0 -1
package/README.md
CHANGED
|
@@ -1,26 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
<h3>Visulima Cerebro</h3>
|
|
3
|
-
<p>
|
|
4
|
-
Cerebro is a delightful toolkit for building cross-runtime command-line interfaces (CLIs) for Node.js, Deno, and Bun, built on top of
|
|
1
|
+
<!-- START_PACKAGE_OG_IMAGE_PLACEHOLDER -->
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
[@visulima/colorize](https://github.com/visulima/visulima/tree/main/packages/colorize),
|
|
8
|
-
[@visulima/command-line-args](https://github.com/visulima/visulima/tree/main/packages/command-line-args),
|
|
9
|
-
[@visulima/tabular](https://github.com/visulima/visulima/tree/main/packages/tabular) and
|
|
10
|
-
[fastest-levenshtein](https://github.com/ka-weihe/fastest-levenshtein)
|
|
3
|
+
<a href="https://www.anolilab.com/open-source" align="center">
|
|
11
4
|
|
|
12
|
-
<
|
|
5
|
+
<img src="__assets__/package-og.svg" alt="cerebro" />
|
|
13
6
|
|
|
14
|
-
|
|
7
|
+
</a>
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
<h3 align="center">A delightful toolkit for building cross-runtime CLIs for Node.js, Deno, and Bun.</h3>
|
|
10
|
+
|
|
11
|
+
<!-- END_PACKAGE_OG_IMAGE_PLACEHOLDER -->
|
|
18
12
|
|
|
19
13
|
<br />
|
|
20
14
|
|
|
21
15
|
<div align="center">
|
|
22
16
|
|
|
23
|
-
[![typescript-image]
|
|
17
|
+
[![typescript-image][typescript-badge]][typescript-url]
|
|
18
|
+
[![mit licence][license-badge]][license]
|
|
19
|
+
[![npm downloads][npm-downloads-badge]][npm-downloads]
|
|
20
|
+
[![Chat][chat-badge]][chat]
|
|
21
|
+
[![PRs Welcome][prs-welcome-badge]][prs-welcome]
|
|
24
22
|
|
|
25
23
|
</div>
|
|
26
24
|
|
|
@@ -428,14 +426,23 @@ If you would like to help take a look at the [list of issues](https://github.com
|
|
|
428
426
|
- [commander.js](https://github.com/tj/commander.js) - node.js command-line interfaces made easy
|
|
429
427
|
- [yargs](https://www.npmjs.com/package/yargs) - yargs the modern, pirate-themed successor to optimist.
|
|
430
428
|
|
|
429
|
+
## Made with ❤️ at Anolilab
|
|
430
|
+
|
|
431
|
+
This is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Anolilab](https://www.anolilab.com/open-source) is a Development and AI Studio. Contact us at [hello@anolilab.com](mailto:hello@anolilab.com) if you need any help with these technologies or just want to say hi!
|
|
432
|
+
|
|
431
433
|
## License
|
|
432
434
|
|
|
433
|
-
The visulima package is open-sourced software licensed under the [MIT][license
|
|
435
|
+
The visulima package is open-sourced software licensed under the [MIT][license]
|
|
434
436
|
|
|
435
|
-
|
|
437
|
+
<!-- badges -->
|
|
436
438
|
|
|
437
|
-
[
|
|
438
|
-
[license
|
|
439
|
-
[
|
|
440
|
-
[npm-
|
|
441
|
-
[
|
|
439
|
+
[license-badge]: https://img.shields.io/npm/l/@visulima/cerebro?style=for-the-badge
|
|
440
|
+
[license]: https://github.com/visulima/visulima/blob/main/LICENSE
|
|
441
|
+
[npm-downloads-badge]: https://img.shields.io/npm/dm/@visulima/cerebro?style=for-the-badge
|
|
442
|
+
[npm-downloads]: https://www.npmjs.com/package/@visulima/cerebro
|
|
443
|
+
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
|
|
444
|
+
[prs-welcome]: https://github.com/visulima/visulima/blob/main/.github/CONTRIBUTING.md
|
|
445
|
+
[chat-badge]: https://img.shields.io/discord/932323359193186354.svg?style=for-the-badge
|
|
446
|
+
[chat]: https://discord.gg/TtFJY8xkFK
|
|
447
|
+
[typescript-badge]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
|
|
448
|
+
[typescript-url]: https://www.typescriptlang.org/
|
package/dist/cli.d.ts
CHANGED
|
@@ -89,6 +89,28 @@ export declare class Cli<T extends Console = Console> implements ICli<T> {
|
|
|
89
89
|
* ```
|
|
90
90
|
*/
|
|
91
91
|
addCommand<OD extends OptionDefinition<unknown> = OptionDefinition<unknown>>(command: ICommand<OD, T>): this;
|
|
92
|
+
/**
|
|
93
|
+
* Adds a global option available to all commands.
|
|
94
|
+
*
|
|
95
|
+
* Global options are parsed alongside command-specific options and displayed
|
|
96
|
+
* in the help output under the "Global Options" section.
|
|
97
|
+
* @param option The option definition
|
|
98
|
+
* @returns The CLI instance for method chaining
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* cli.addGlobalOption({
|
|
102
|
+
* name: 'cwd',
|
|
103
|
+
* type: String,
|
|
104
|
+
* description: 'Override working directory',
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
addGlobalOption<V = unknown>(option: OptionDefinition<V>): this;
|
|
109
|
+
/**
|
|
110
|
+
* Gets all global options (built-in + custom).
|
|
111
|
+
* @returns Array of all global option definitions
|
|
112
|
+
*/
|
|
113
|
+
getGlobalOptions(): OptionDefinition<unknown>[];
|
|
92
114
|
/**
|
|
93
115
|
* Adds a plugin to extend the CLI functionality.
|
|
94
116
|
*
|
|
@@ -1,5 +1,204 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import tab from '@bomb.sh/tab';
|
|
2
|
+
import { C as CerebroError } from '../packem_shared/cerebro-error-GmJ3jN7Q.js';
|
|
3
|
+
|
|
4
|
+
class CompletionError extends CerebroError {
|
|
5
|
+
troubleshooting;
|
|
6
|
+
constructor(message, code, troubleshooting = []) {
|
|
7
|
+
super(message, code, { troubleshooting });
|
|
8
|
+
this.name = "CompletionError";
|
|
9
|
+
this.troubleshooting = troubleshooting;
|
|
10
|
+
if (troubleshooting.length > 0) {
|
|
11
|
+
this.hint = troubleshooting.join("\n");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const validShells = ["bash", "zsh", "fish", "powershell"];
|
|
17
|
+
const validRuntimes = ["node", "bun", "deno"];
|
|
18
|
+
const hasDeno = (global) => "Deno" in global;
|
|
19
|
+
const hasBun = (global) => "Bun" in global;
|
|
20
|
+
const detectRuntime = () => {
|
|
21
|
+
if (hasDeno(globalThis)) {
|
|
22
|
+
return "deno";
|
|
23
|
+
}
|
|
24
|
+
if (hasBun(globalThis)) {
|
|
25
|
+
return "bun";
|
|
26
|
+
}
|
|
27
|
+
return "node";
|
|
28
|
+
};
|
|
29
|
+
const detectShell = (toolboxEnv) => {
|
|
30
|
+
const starshipShell = toolboxEnv?.starshipShell;
|
|
31
|
+
const shell = starshipShell ?? toolboxEnv?.shell;
|
|
32
|
+
if (shell) {
|
|
33
|
+
const shellPath = shell.toLowerCase();
|
|
34
|
+
if (shellPath.includes("zsh")) {
|
|
35
|
+
return "zsh";
|
|
36
|
+
}
|
|
37
|
+
if (shellPath.includes("bash")) {
|
|
38
|
+
return "bash";
|
|
39
|
+
}
|
|
40
|
+
if (shellPath.includes("fish")) {
|
|
41
|
+
return "fish";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const psModulePath = toolboxEnv?.psModulePath;
|
|
45
|
+
const prompt = toolboxEnv?.prompt;
|
|
46
|
+
if (psModulePath || prompt?.includes("PS")) {
|
|
47
|
+
return "powershell";
|
|
48
|
+
}
|
|
49
|
+
const comSpec = toolboxEnv?.comSpec;
|
|
50
|
+
if (comSpec?.toLowerCase().includes("cmd.exe")) {
|
|
51
|
+
return "bash";
|
|
52
|
+
}
|
|
53
|
+
return void 0;
|
|
54
|
+
};
|
|
55
|
+
const tabInstance = tab;
|
|
56
|
+
const registerCommandOptions = (cmd, options) => {
|
|
57
|
+
for (const option of options) {
|
|
58
|
+
if (option.hidden) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (option.name) {
|
|
62
|
+
cmd.option(option.name, option.description ?? "");
|
|
63
|
+
}
|
|
64
|
+
if (option.alias) {
|
|
65
|
+
cmd.option(option.alias, option.description ?? "");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const registerCommands = (tabInstance2, commands) => {
|
|
70
|
+
for (const [commandName, command] of commands) {
|
|
71
|
+
if (command.name !== commandName || command.hidden) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const cmd = tabInstance2.command(command.name, command.description ?? "");
|
|
75
|
+
if (command.options) {
|
|
76
|
+
registerCommandOptions(cmd, command.options);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const validateShell = (shell) => {
|
|
81
|
+
if (!validShells.includes(shell)) {
|
|
82
|
+
throw new CompletionError(`Invalid shell type: ${shell}`, "INVALID_SHELL", [
|
|
83
|
+
`Valid shells are: ${validShells.join(", ")}`,
|
|
84
|
+
"Shell will be auto-detected if not specified"
|
|
85
|
+
]);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const validateRuntime = (runtime) => {
|
|
89
|
+
if (runtime && !validRuntimes.includes(runtime)) {
|
|
90
|
+
throw new CompletionError(`Invalid runtime: ${runtime}`, "INVALID_RUNTIME", [
|
|
91
|
+
`Valid runtimes are: ${validRuntimes.join(", ")}`,
|
|
92
|
+
"Runtime will be auto-detected if not specified"
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const printUsageInstructions = (logger, cliName) => {
|
|
97
|
+
logger.error("Could not detect current shell");
|
|
98
|
+
const usageInfo = [
|
|
99
|
+
`Usage: ${cliName} completion --shell=<bash|zsh|fish|powershell> [--runtime=<node|bun|deno>]`,
|
|
100
|
+
"",
|
|
101
|
+
"Examples:",
|
|
102
|
+
` # Install completions for zsh:`,
|
|
103
|
+
` ${cliName} completion --shell=zsh > ~/.${cliName}-completion.zsh`,
|
|
104
|
+
` echo 'source ~/.${cliName}-completion.zsh' >> ~/.zshrc`,
|
|
105
|
+
"",
|
|
106
|
+
` # Install completions for bash with custom runtime:`,
|
|
107
|
+
` ${cliName} completion --shell=bash --runtime=bun > ~/.${cliName}-completion.bash`,
|
|
108
|
+
` echo 'source ~/.${cliName}-completion.bash' >> ~/.bashrc`,
|
|
109
|
+
"",
|
|
110
|
+
` # Install completions for fish:`,
|
|
111
|
+
` ${cliName} completion --shell=fish > ~/.config/fish/completions/${cliName}.fish`
|
|
112
|
+
].join("\n");
|
|
113
|
+
logger.info(usageInfo);
|
|
114
|
+
};
|
|
115
|
+
const completionCommand = {
|
|
116
|
+
description: "Generate shell completion scripts",
|
|
117
|
+
env: [
|
|
118
|
+
{
|
|
119
|
+
description: "Shell path (Unix-like systems). Used for shell detection.",
|
|
120
|
+
name: "SHELL",
|
|
121
|
+
type: String
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
description: "Starship shell configuration. Takes precedence over SHELL for detection.",
|
|
125
|
+
name: "STARSHIP_SHELL",
|
|
126
|
+
type: String
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
description: "PowerShell module path (Windows). Used for PowerShell detection.",
|
|
130
|
+
name: "PSModulePath",
|
|
131
|
+
type: String
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
description: "Command prompt variable (Windows). Used for PowerShell detection.",
|
|
135
|
+
name: "PROMPT",
|
|
136
|
+
type: String
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
description: "Command processor (Windows). Used for Windows Command Prompt detection.",
|
|
140
|
+
name: "ComSpec",
|
|
141
|
+
type: String
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
145
|
+
execute: async ({ env: toolboxEnv, logger, options, runtime }) => {
|
|
146
|
+
const cliName = runtime.getCliName();
|
|
147
|
+
const shell = options.shell ?? detectShell(toolboxEnv);
|
|
148
|
+
if (!shell) {
|
|
149
|
+
printUsageInstructions(logger, cliName);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
validateShell(shell);
|
|
154
|
+
validateRuntime(options.runtime);
|
|
155
|
+
registerCommands(tabInstance, runtime.getCommands());
|
|
156
|
+
const jsRuntime = options.runtime ?? detectRuntime();
|
|
157
|
+
const scriptPath = `${jsRuntime} ${cliName}`;
|
|
158
|
+
tabInstance.setup(cliName, scriptPath, shell);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (error instanceof CompletionError) {
|
|
161
|
+
const errorMessages = [`Failed to generate completion script: ${error.message}`, `Error code: ${error.code}`];
|
|
162
|
+
if (error.troubleshooting.length > 0) {
|
|
163
|
+
errorMessages.push("", "Troubleshooting:", ...error.troubleshooting.map((tip) => ` • ${tip}`));
|
|
164
|
+
}
|
|
165
|
+
logger.error(errorMessages.join("\n"));
|
|
166
|
+
throw error;
|
|
167
|
+
} else {
|
|
168
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
169
|
+
const errorMessages = [
|
|
170
|
+
"Failed to generate completion script",
|
|
171
|
+
`Error: ${errorMessage}`,
|
|
172
|
+
"",
|
|
173
|
+
"Troubleshooting:",
|
|
174
|
+
" • Ensure @bomb.sh/tab is installed: pnpm add @bomb.sh/tab",
|
|
175
|
+
` • Verify shell is supported: ${validShells.join(", ")}`,
|
|
176
|
+
` • Verify runtime is supported: ${validRuntimes.join(", ")}`,
|
|
177
|
+
" • Check that your CLI name is correct"
|
|
178
|
+
];
|
|
179
|
+
logger.error(errorMessages.join("\n"));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
name: "completion",
|
|
184
|
+
options: [
|
|
185
|
+
{
|
|
186
|
+
defaultOption: true,
|
|
187
|
+
defaultValue: detectShell(),
|
|
188
|
+
description: "Shell type (bash, zsh, fish, powershell). Defaults to current shell if detected.",
|
|
189
|
+
name: "shell",
|
|
190
|
+
type: String,
|
|
191
|
+
typeLabel: "{underline shell}"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
defaultOption: true,
|
|
195
|
+
defaultValue: detectRuntime(),
|
|
196
|
+
description: "JavaScript runtime (node, bun, deno). Defaults to current runtime if detected.",
|
|
197
|
+
name: "runtime",
|
|
198
|
+
type: String,
|
|
199
|
+
typeLabel: "{underline runtime}"
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export { completionCommand as default };
|
|
@@ -1 +1,200 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { inverse, cyan, green, yellow } from '@visulima/colorize';
|
|
2
|
+
import { t as templateFormat, c as commandLineUsage } from '../packem_shared/index-CS31xKFe.js';
|
|
3
|
+
|
|
4
|
+
const defaultEnv = [
|
|
5
|
+
{
|
|
6
|
+
defaultValue: "32",
|
|
7
|
+
description: "Controls the verbosity level of output. Valid values: '16' (quiet), '32' (normal), '64' (verbose), '128' (debug)",
|
|
8
|
+
name: "CEREBRO_OUTPUT_LEVEL",
|
|
9
|
+
type: String
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
description: "Sets the minimum required Node.js version. Overrides the default minimum version check",
|
|
13
|
+
name: "CEREBRO_MIN_NODE_VERSION",
|
|
14
|
+
type: Number
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
defaultValue: false,
|
|
18
|
+
description: "When set, disables the update notifier check",
|
|
19
|
+
name: "NO_UPDATE_NOTIFIER",
|
|
20
|
+
type: Boolean
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
description: "Standard Node.js environment variable. When set to 'test', disables update notifier",
|
|
24
|
+
name: "NODE_ENV",
|
|
25
|
+
type: String
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
defaultValue: false,
|
|
29
|
+
description: "When set, enables debug output (same as --debug flag)",
|
|
30
|
+
name: "DEBUG",
|
|
31
|
+
type: Boolean
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
description: "Sets the terminal width for table rendering. Useful for testing and consistent output",
|
|
35
|
+
name: "CEREBRO_TERMINAL_WIDTH",
|
|
36
|
+
type: Number
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const EMPTY_GROUP_KEY = "__Other";
|
|
41
|
+
const upperFirstChar = (string_) => string_.charAt(0).toUpperCase() + string_.slice(1);
|
|
42
|
+
const printGeneralHelp = (logger, runtime, commands, groupOption) => {
|
|
43
|
+
logger.debug("no command given, printing general help...");
|
|
44
|
+
let filteredCommands = [...new Set(commands.values())].filter((command) => !command.hidden);
|
|
45
|
+
if (groupOption) {
|
|
46
|
+
filteredCommands = filteredCommands.filter((command) => command.group === groupOption);
|
|
47
|
+
}
|
|
48
|
+
const groupedCommands = filteredCommands.reduce((accumulator, command) => {
|
|
49
|
+
const group = command.group ?? EMPTY_GROUP_KEY;
|
|
50
|
+
accumulator[group] ??= [];
|
|
51
|
+
accumulator[group].push(command);
|
|
52
|
+
return accumulator;
|
|
53
|
+
}, {});
|
|
54
|
+
const buildCommandList = (commandList) => commandList.map((command) => {
|
|
55
|
+
let aliases = "";
|
|
56
|
+
if (typeof command.alias === "string") {
|
|
57
|
+
aliases = command.alias;
|
|
58
|
+
} else if (Array.isArray(command.alias)) {
|
|
59
|
+
aliases = command.alias.join(", ");
|
|
60
|
+
}
|
|
61
|
+
if (aliases !== "") {
|
|
62
|
+
aliases = ` [${aliases}]`;
|
|
63
|
+
}
|
|
64
|
+
let commandDisplay = command.name;
|
|
65
|
+
if (command.commandPath && command.commandPath.length > 0) {
|
|
66
|
+
commandDisplay = `${command.commandPath.join(" ")} ${command.name}`;
|
|
67
|
+
}
|
|
68
|
+
return [`${green(commandDisplay)}${aliases}`, command.description ?? ""];
|
|
69
|
+
});
|
|
70
|
+
(logger.raw ?? logger.log)(
|
|
71
|
+
commandLineUsage(
|
|
72
|
+
[
|
|
73
|
+
{
|
|
74
|
+
content: `${cyan(runtime.getCliName())} ${green("<command>")} [positional arguments] ${yellow("[options]")}`,
|
|
75
|
+
header: inverse.cyan(" Usage ")
|
|
76
|
+
},
|
|
77
|
+
...Object.keys(groupedCommands).map((key) => {
|
|
78
|
+
const groupOptionName = groupOption ? ` ${upperFirstChar(groupOption)}` : "";
|
|
79
|
+
return {
|
|
80
|
+
content: buildCommandList(groupedCommands[key]),
|
|
81
|
+
header: key === EMPTY_GROUP_KEY || groupOption ? inverse.green(` Available${groupOptionName} Commands `) : ` ${inverse.green(` ${upperFirstChar(key)} `)}`
|
|
82
|
+
};
|
|
83
|
+
}),
|
|
84
|
+
commands.has("help") ? {
|
|
85
|
+
header: inverse.yellow(" Command Options "),
|
|
86
|
+
optionList: commands.get("help").options?.filter((option) => !option.hidden)
|
|
87
|
+
} : void 0,
|
|
88
|
+
{ header: inverse.yellow(" Global Options "), optionList: runtime.getGlobalOptions() },
|
|
89
|
+
{
|
|
90
|
+
content: defaultEnv.filter((envVariable) => !envVariable.hidden).map((envVariable) => [envVariable.name, envVariable.description ?? ""]),
|
|
91
|
+
header: inverse.magenta(" Environment Variables ")
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
content: `Run "${cyan(runtime.getCliName())} ${green("help <command>")}" or "${cyan(runtime.getCliName())} ${green("<command>")} ${yellow("--help")}" for help with a specific command.`,
|
|
95
|
+
raw: true
|
|
96
|
+
}
|
|
97
|
+
].filter(Boolean)
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
const printCommandHelp = (logger, runtime, commands, name) => {
|
|
102
|
+
let command = commands.get(name);
|
|
103
|
+
if (!command) {
|
|
104
|
+
for (const cmd of commands.values()) {
|
|
105
|
+
const fullPath = cmd.commandPath ? [...cmd.commandPath, cmd.name] : [cmd.name];
|
|
106
|
+
if (fullPath.at(-1) === name || fullPath.join(" ") === name) {
|
|
107
|
+
command = cmd;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!command) {
|
|
113
|
+
logger.error(`Command "${name}" not found`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const usageGroups = [];
|
|
117
|
+
const fullCommandPath = command.commandPath ? [...command.commandPath, command.name] : [command.name];
|
|
118
|
+
const commandDisplay = fullCommandPath.join(" ");
|
|
119
|
+
usageGroups.push({
|
|
120
|
+
content: `${cyan(runtime.getCliName())} ${green(commandDisplay)}${command.argument ? " [positional arguments]" : ""}${command.options ? " [options]" : ""}`,
|
|
121
|
+
header: inverse.cyan(" Usage ")
|
|
122
|
+
});
|
|
123
|
+
if (command.description) {
|
|
124
|
+
usageGroups.push({ content: command.description, header: inverse.green(" Description ") });
|
|
125
|
+
}
|
|
126
|
+
if (command.argument) {
|
|
127
|
+
usageGroups.push({ header: "Command Positional Arguments", isArgument: true, optionList: [command.argument] });
|
|
128
|
+
}
|
|
129
|
+
if (Array.isArray(command.options) && command.options.length > 0) {
|
|
130
|
+
usageGroups.push({
|
|
131
|
+
header: inverse.yellow(" Command Options "),
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
133
|
+
optionList: command.options.filter((option) => !option.hidden)
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
usageGroups.push({ header: inverse.yellow(" Global Options "), optionList: runtime.getGlobalOptions() });
|
|
137
|
+
if (Array.isArray(command.env) && command.env.length > 0) {
|
|
138
|
+
const visibleEnvVariables = command.env.filter((envVariable) => !envVariable.hidden);
|
|
139
|
+
if (visibleEnvVariables.length > 0) {
|
|
140
|
+
usageGroups.push({
|
|
141
|
+
content: visibleEnvVariables.map((envVariable) => [envVariable.name, envVariable.description ?? ""]),
|
|
142
|
+
header: inverse.magenta(" Environment Variables ")
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (command.alias !== void 0 && command.alias.length > 0) {
|
|
147
|
+
let alias = command.alias;
|
|
148
|
+
if (typeof command.alias === "string") {
|
|
149
|
+
alias = [command.alias];
|
|
150
|
+
}
|
|
151
|
+
usageGroups.splice(1, 0, {
|
|
152
|
+
content: alias,
|
|
153
|
+
header: "Alias(es)"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (Array.isArray(command.examples) && command.examples.length > 0) {
|
|
157
|
+
usageGroups.push({
|
|
158
|
+
content: command.examples,
|
|
159
|
+
header: "Examples"
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
(logger.raw ?? logger.log)(commandLineUsage(usageGroups));
|
|
163
|
+
};
|
|
164
|
+
class HelpCommand {
|
|
165
|
+
name = "help";
|
|
166
|
+
options = [
|
|
167
|
+
{
|
|
168
|
+
description: "Display only the specified group",
|
|
169
|
+
name: "group",
|
|
170
|
+
type: String
|
|
171
|
+
}
|
|
172
|
+
];
|
|
173
|
+
commands;
|
|
174
|
+
constructor(commands) {
|
|
175
|
+
this.commands = commands;
|
|
176
|
+
}
|
|
177
|
+
execute(toolbox) {
|
|
178
|
+
const { commandName, logger, options, runtime } = toolbox;
|
|
179
|
+
const { footer, header } = runtime.getCommandSection();
|
|
180
|
+
if (header) {
|
|
181
|
+
(logger.raw ?? logger.log)(templateFormat(header));
|
|
182
|
+
}
|
|
183
|
+
if (commandName === "help") {
|
|
184
|
+
printGeneralHelp(
|
|
185
|
+
logger,
|
|
186
|
+
runtime,
|
|
187
|
+
this.commands,
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- options may be undefined at runtime
|
|
189
|
+
typeof options?.group === "string" ? options.group : void 0
|
|
190
|
+
);
|
|
191
|
+
} else {
|
|
192
|
+
printCommandHelp(logger, runtime, this.commands, commandName);
|
|
193
|
+
}
|
|
194
|
+
if (footer) {
|
|
195
|
+
(logger.raw ?? logger.log)(templateFormat(footer));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export { HelpCommand as default };
|