@clerc/plugin-help 1.0.0-beta.2 → 1.0.0-beta.20
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/dist/index.d.ts +113 -10
- package/dist/index.js +235 -54
- package/package.json +6 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,41 +1,143 @@
|
|
|
1
1
|
import { Plugin } from "@clerc/core";
|
|
2
2
|
|
|
3
3
|
//#region ../parser/src/types.d.ts
|
|
4
|
-
|
|
4
|
+
interface FlagDefaultValueFunction<T> {
|
|
5
|
+
(): T;
|
|
6
|
+
display?: string;
|
|
7
|
+
}
|
|
8
|
+
type FlagDefaultValue<T = unknown> = T | FlagDefaultValueFunction<T>;
|
|
5
9
|
/**
|
|
6
10
|
* Defines how a string input is converted to the target type T.
|
|
7
11
|
*
|
|
8
12
|
* @template T The target type.
|
|
9
13
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
interface TypeFunction<T = unknown> {
|
|
15
|
+
(value: string): T;
|
|
16
|
+
/**
|
|
17
|
+
* Optional display name for the type, useful in help output.
|
|
18
|
+
* If provided, this will be shown instead of the function name.
|
|
19
|
+
*/
|
|
20
|
+
display?: string;
|
|
21
|
+
}
|
|
22
|
+
type FlagType<T = unknown> = TypeFunction<T> | readonly [TypeFunction<T>];
|
|
12
23
|
//#endregion
|
|
13
24
|
//#region src/types.d.ts
|
|
14
25
|
interface Formatters {
|
|
15
26
|
formatFlagType: (type: FlagType) => string;
|
|
27
|
+
formatFlagDefault: <T>(value: FlagDefaultValue<T>) => string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A group definition as a tuple of [key, displayName].
|
|
31
|
+
* The key is used in help options to assign items to groups.
|
|
32
|
+
* The displayName is shown in the help output.
|
|
33
|
+
*/
|
|
34
|
+
type GroupDefinition = [key: string, name: string];
|
|
35
|
+
/**
|
|
36
|
+
* Options for defining groups in help output.
|
|
37
|
+
*/
|
|
38
|
+
interface GroupsOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Groups for commands.
|
|
41
|
+
* Each group is defined as `[key, name]`.
|
|
42
|
+
*/
|
|
43
|
+
commands?: GroupDefinition[];
|
|
44
|
+
/**
|
|
45
|
+
* Groups for command-specific flags.
|
|
46
|
+
* Each group is defined as `[key, name]`.
|
|
47
|
+
*/
|
|
48
|
+
flags?: GroupDefinition[];
|
|
49
|
+
/**
|
|
50
|
+
* Groups for global flags.
|
|
51
|
+
* Each group is defined as `[key, name]`.
|
|
52
|
+
*/
|
|
53
|
+
globalFlags?: GroupDefinition[];
|
|
16
54
|
}
|
|
17
55
|
//#endregion
|
|
18
56
|
//#region src/formatters.d.ts
|
|
19
57
|
declare const defaultFormatters: Formatters;
|
|
20
58
|
//#endregion
|
|
21
59
|
//#region src/index.d.ts
|
|
60
|
+
interface HelpOptions {
|
|
61
|
+
/**
|
|
62
|
+
* The group this item belongs to.
|
|
63
|
+
* The group must be defined in the `groups` option of `helpPlugin()`.
|
|
64
|
+
*/
|
|
65
|
+
group?: string;
|
|
66
|
+
}
|
|
67
|
+
interface CommandHelpOptions extends HelpOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Whether to show the command in help output.
|
|
70
|
+
*
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
show?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Notes to show in the help output.
|
|
76
|
+
*/
|
|
77
|
+
notes?: string[];
|
|
78
|
+
/**
|
|
79
|
+
* Examples to show in the help output.
|
|
80
|
+
* Each example is a tuple of `[command, description]`.
|
|
81
|
+
*/
|
|
82
|
+
examples?: [string, string][];
|
|
83
|
+
}
|
|
22
84
|
declare module "@clerc/core" {
|
|
23
85
|
interface CommandCustomOptions {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Help options for the command.
|
|
88
|
+
*/
|
|
89
|
+
help?: CommandHelpOptions;
|
|
90
|
+
}
|
|
91
|
+
interface FlagCustomOptions {
|
|
92
|
+
/**
|
|
93
|
+
* Help options for the flag.
|
|
94
|
+
*/
|
|
95
|
+
help?: HelpOptions;
|
|
29
96
|
}
|
|
30
97
|
}
|
|
31
98
|
interface HelpPluginOptions {
|
|
99
|
+
/**
|
|
100
|
+
* Whether to register the `help` command.
|
|
101
|
+
*
|
|
102
|
+
* @default true
|
|
103
|
+
*/
|
|
32
104
|
command?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Whether to register the `--help` global flag.
|
|
107
|
+
*
|
|
108
|
+
* @default true
|
|
109
|
+
*/
|
|
33
110
|
flag?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Whether to show help when no command is specified.
|
|
113
|
+
*
|
|
114
|
+
* @default true
|
|
115
|
+
*/
|
|
34
116
|
showHelpWhenNoCommandSpecified?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Notes to show in the help output.
|
|
119
|
+
*/
|
|
35
120
|
notes?: string[];
|
|
121
|
+
/**
|
|
122
|
+
* Examples to show in the help output.
|
|
123
|
+
* Each example is a tuple of `[command, description]`.
|
|
124
|
+
*/
|
|
36
125
|
examples?: [string, string][];
|
|
126
|
+
/**
|
|
127
|
+
* A banner to show before the help output.
|
|
128
|
+
*/
|
|
37
129
|
banner?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Custom formatters for rendering help.
|
|
132
|
+
*/
|
|
38
133
|
formatters?: Partial<Formatters>;
|
|
134
|
+
/**
|
|
135
|
+
* Group definitions for commands and flags.
|
|
136
|
+
* Groups allow organizing commands and flags into logical sections in help output.
|
|
137
|
+
* Each group is defined as `[key, name]` where `key` is the identifier used in help options
|
|
138
|
+
* and `name` is the display name shown in help output.
|
|
139
|
+
*/
|
|
140
|
+
groups?: GroupsOptions;
|
|
39
141
|
}
|
|
40
142
|
declare const helpPlugin: ({
|
|
41
143
|
command,
|
|
@@ -44,7 +146,8 @@ declare const helpPlugin: ({
|
|
|
44
146
|
notes,
|
|
45
147
|
examples,
|
|
46
148
|
banner,
|
|
47
|
-
formatters
|
|
149
|
+
formatters,
|
|
150
|
+
groups
|
|
48
151
|
}?: HelpPluginOptions) => Plugin;
|
|
49
152
|
//#endregion
|
|
50
|
-
export { HelpPluginOptions, defaultFormatters, helpPlugin };
|
|
153
|
+
export { CommandHelpOptions, type GroupDefinition, type GroupsOptions, HelpOptions, HelpPluginOptions, defaultFormatters, helpPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,55 +1,108 @@
|
|
|
1
|
-
import { definePlugin, resolveCommand } from "@clerc/core";
|
|
2
|
-
import { formatFlagName, formatVersion, isTruthy, objectIsEmpty, toArray } from "@clerc/utils";
|
|
1
|
+
import { NoSuchCommandError, definePlugin, normalizeFlagValue, resolveCommand } from "@clerc/core";
|
|
3
2
|
import stringWidth from "string-width";
|
|
4
3
|
import textTable from "text-table";
|
|
5
4
|
import * as yc from "yoctocolors";
|
|
6
5
|
|
|
6
|
+
//#region ../utils/src/index.ts
|
|
7
|
+
const toArray = (a) => Array.isArray(a) ? a : [a];
|
|
8
|
+
const kebabCase = (s) => s.replace(/([A-Z])/g, (_, c) => `-${c.toLowerCase()}`);
|
|
9
|
+
const formatFlagName = (n) => n.length <= 1 ? `-${n}` : `--${kebabCase(n)}`;
|
|
10
|
+
const formatVersion = (v) => v.length === 0 ? "" : v.startsWith("v") ? v : `v${v}`;
|
|
11
|
+
const isTruthy = Boolean;
|
|
12
|
+
const objectIsEmpty = (obj) => Object.keys(obj).length === 0;
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
7
15
|
//#region src/utils.ts
|
|
8
16
|
function formatFlagType(type) {
|
|
9
|
-
if (typeof type === "function") return type.name;
|
|
10
|
-
|
|
17
|
+
if (typeof type === "function") return type.display ?? type.name;
|
|
18
|
+
const innerType = type[0];
|
|
19
|
+
return `Array<${innerType.displayName ?? innerType.name}>`;
|
|
20
|
+
}
|
|
21
|
+
function formatFlagDefault(value) {
|
|
22
|
+
if (typeof value === "function" && "display" in value && value.display) return value.display;
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
function formatCommandName(name) {
|
|
26
|
+
if (name === "") return "(root)";
|
|
27
|
+
return name;
|
|
11
28
|
}
|
|
12
29
|
|
|
13
30
|
//#endregion
|
|
14
31
|
//#region src/formatters.ts
|
|
15
|
-
const defaultFormatters = {
|
|
32
|
+
const defaultFormatters = {
|
|
33
|
+
formatFlagType,
|
|
34
|
+
formatFlagDefault
|
|
35
|
+
};
|
|
16
36
|
|
|
17
37
|
//#endregion
|
|
18
38
|
//#region src/renderer.ts
|
|
39
|
+
const DEFAULT_GROUP_KEY = "default";
|
|
19
40
|
const table = (items) => textTable(items, { stringLength: stringWidth });
|
|
20
41
|
const splitTable = (items) => table(items).split("\n");
|
|
21
42
|
const DELIMITER = yc.yellow("-");
|
|
43
|
+
const INDENT = " ".repeat(2);
|
|
44
|
+
const withIndent = (str) => `${INDENT}${str}`;
|
|
45
|
+
function groupDefinitionsToMap(definitions) {
|
|
46
|
+
const map = /* @__PURE__ */ new Map();
|
|
47
|
+
if (definitions) for (const [key, name] of definitions) map.set(key, name);
|
|
48
|
+
return map;
|
|
49
|
+
}
|
|
50
|
+
function validateGroup(group, groupMap, itemType, itemName) {
|
|
51
|
+
if (group && group !== DEFAULT_GROUP_KEY && !groupMap.has(group)) throw new Error(`Unknown ${itemType} group "${group}" for "${itemName}". Available groups: ${[...groupMap.keys()].join(", ") || "(none)"}`);
|
|
52
|
+
}
|
|
22
53
|
var HelpRenderer = class {
|
|
23
|
-
|
|
54
|
+
_command;
|
|
55
|
+
get _commandGroups() {
|
|
56
|
+
return groupDefinitionsToMap(this._getGroups().commands);
|
|
57
|
+
}
|
|
58
|
+
get _flagGroups() {
|
|
59
|
+
return groupDefinitionsToMap(this._getGroups().flags);
|
|
60
|
+
}
|
|
61
|
+
get _globalFlagGroups() {
|
|
62
|
+
return groupDefinitionsToMap(this._getGroups().globalFlags);
|
|
63
|
+
}
|
|
64
|
+
constructor(_formatters, _cli, _globalFlags, _getGroups, _examples, _notes) {
|
|
24
65
|
this._formatters = _formatters;
|
|
25
66
|
this._cli = _cli;
|
|
26
67
|
this._globalFlags = _globalFlags;
|
|
27
|
-
this.
|
|
28
|
-
this._notes = _notes;
|
|
68
|
+
this._getGroups = _getGroups;
|
|
29
69
|
this._examples = _examples;
|
|
70
|
+
this._notes = _notes;
|
|
71
|
+
}
|
|
72
|
+
setCommand(command) {
|
|
73
|
+
if (command) {
|
|
74
|
+
this._command = command;
|
|
75
|
+
this._examples = command?.help?.examples;
|
|
76
|
+
this._notes = command?.help?.notes;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
renderSections(sections) {
|
|
80
|
+
return sections.filter(isTruthy).map((section) => {
|
|
81
|
+
const body = Array.isArray(section.body) ? section.body.filter((s) => s !== void 0).join("\n") : section.body;
|
|
82
|
+
if (!section.title) return body;
|
|
83
|
+
return `${yc.bold(section.title)}\n${body.split("\n").map(withIndent).join("\n")}`;
|
|
84
|
+
}).join("\n\n");
|
|
30
85
|
}
|
|
31
86
|
render() {
|
|
32
|
-
|
|
87
|
+
const sections = [
|
|
33
88
|
this.renderHeader(),
|
|
34
89
|
this.renderUsage(),
|
|
35
|
-
this.
|
|
36
|
-
this.renderGlobalFlags(),
|
|
90
|
+
this.renderParameters(),
|
|
37
91
|
this.renderCommandFlags(),
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}).join("\n\n");
|
|
92
|
+
this.renderGlobalFlags(),
|
|
93
|
+
this.renderCommands(),
|
|
94
|
+
this.renderExamples(),
|
|
95
|
+
this.renderNotes()
|
|
96
|
+
];
|
|
97
|
+
return this.renderSections(sections);
|
|
45
98
|
}
|
|
46
99
|
renderHeader() {
|
|
47
100
|
const { _name, _version, _description } = this._cli;
|
|
48
101
|
const command = this._command;
|
|
49
|
-
const description = command
|
|
102
|
+
const description = command ? command.description : _description;
|
|
50
103
|
const formattedCommandName = command?.name ? ` ${yc.cyan(command.name)}` : "";
|
|
51
104
|
const headerLine = command ? `${yc.green(_name)}${formattedCommandName}` : `${yc.green(_name)} ${yc.yellow(formatVersion(_version))}`;
|
|
52
|
-
const alias = command?.alias ? `Alias${toArray(command.alias).length > 1 ? "es" : ""}: ${toArray(command.alias).map((a) => yc.cyan(a)).join(", ")}` :
|
|
105
|
+
const alias = command?.alias ? `Alias${toArray(command.alias).length > 1 ? "es" : ""}: ${toArray(command.alias).map((a) => yc.cyan(a)).join(", ")}` : void 0;
|
|
53
106
|
return { body: [`${headerLine}${description ? ` ${DELIMITER} ${description}` : ""}`, alias] };
|
|
54
107
|
}
|
|
55
108
|
renderUsage() {
|
|
@@ -57,54 +110,153 @@ var HelpRenderer = class {
|
|
|
57
110
|
const command = this._command;
|
|
58
111
|
let usage = `$ ${_scriptName}`;
|
|
59
112
|
if (command) {
|
|
60
|
-
|
|
61
|
-
if (command.parameters) usage += ` ${command.parameters.join(" ")}`;
|
|
62
|
-
}
|
|
63
|
-
if (command?.flags && !objectIsEmpty(command.flags) || !objectIsEmpty(this._globalFlags)) usage += " [
|
|
113
|
+
if (command.name) usage += ` ${command.name}`;
|
|
114
|
+
if (command.parameters) usage += ` ${command.parameters.map((p) => typeof p === "string" ? p : p.key).join(" ")}`;
|
|
115
|
+
} else usage += this._cli._commands.has("") ? " [command]" : " <command>";
|
|
116
|
+
if (command?.flags && !objectIsEmpty(command.flags) || !objectIsEmpty(this._globalFlags)) usage += " [flags]";
|
|
64
117
|
return {
|
|
65
118
|
title: "Usage",
|
|
66
|
-
body: [usage]
|
|
119
|
+
body: [yc.magenta(usage)]
|
|
67
120
|
};
|
|
68
121
|
}
|
|
122
|
+
renderParameters() {
|
|
123
|
+
const command = this._command;
|
|
124
|
+
if (!command?.parameters || command.parameters.length === 0) return;
|
|
125
|
+
return {
|
|
126
|
+
title: "Parameters",
|
|
127
|
+
body: splitTable(command.parameters.map((parameter) => {
|
|
128
|
+
const key = typeof parameter === "string" ? parameter : parameter.key;
|
|
129
|
+
const type = typeof parameter === "string" ? void 0 : parameter.type;
|
|
130
|
+
const description = typeof parameter === "string" ? void 0 : parameter.description;
|
|
131
|
+
return [
|
|
132
|
+
yc.blue(key),
|
|
133
|
+
type?.display ? yc.gray(type.display) : void 0,
|
|
134
|
+
description
|
|
135
|
+
].filter(isTruthy);
|
|
136
|
+
}))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
getSubcommands(parentCommandName) {
|
|
140
|
+
const subcommands = /* @__PURE__ */ new Map();
|
|
141
|
+
if (parentCommandName === "") return subcommands;
|
|
142
|
+
const prefix = `${parentCommandName} `;
|
|
143
|
+
for (const [name, command] of this._cli._commands) if (name.startsWith(prefix)) {
|
|
144
|
+
const subcommandName = name.slice(prefix.length);
|
|
145
|
+
subcommands.set(subcommandName, command);
|
|
146
|
+
}
|
|
147
|
+
return subcommands;
|
|
148
|
+
}
|
|
149
|
+
buildGroupedCommandsBody(commandsToShow, prefix) {
|
|
150
|
+
const groupedCommands = /* @__PURE__ */ new Map();
|
|
151
|
+
const defaultCommands = [];
|
|
152
|
+
let rootCommand = [];
|
|
153
|
+
for (const command of commandsToShow.values()) {
|
|
154
|
+
if (command.__isAlias || command.help?.show === false) continue;
|
|
155
|
+
const group = command.help?.group;
|
|
156
|
+
validateGroup(group, this._commandGroups, "command", command.name);
|
|
157
|
+
const item = [`${yc.cyan(formatCommandName(command.name.slice(prefix.length)))}${command.alias ? ` (${toArray(command.alias).join(", ")})` : ""}`, command.description].filter(isTruthy);
|
|
158
|
+
if (command.name === "") rootCommand = item;
|
|
159
|
+
else if (group && group !== DEFAULT_GROUP_KEY) {
|
|
160
|
+
const groupItems = groupedCommands.get(group) ?? [];
|
|
161
|
+
groupItems.push(item);
|
|
162
|
+
groupedCommands.set(group, groupItems);
|
|
163
|
+
} else defaultCommands.push(item);
|
|
164
|
+
}
|
|
165
|
+
const body = [];
|
|
166
|
+
const defaultGroup = [];
|
|
167
|
+
if (rootCommand.length > 0) defaultGroup.push(rootCommand);
|
|
168
|
+
if (defaultCommands.length > 0) defaultGroup.push(...defaultCommands);
|
|
169
|
+
if (defaultGroup.length > 0) body.push(...splitTable(defaultGroup));
|
|
170
|
+
for (const [key, name] of this._commandGroups) {
|
|
171
|
+
const items = groupedCommands.get(key);
|
|
172
|
+
if (items && items.length > 0) {
|
|
173
|
+
if (body.length > 0) body.push("");
|
|
174
|
+
body.push(`${yc.dim(name)}`);
|
|
175
|
+
body.push(...splitTable(items).map(withIndent));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return body;
|
|
179
|
+
}
|
|
180
|
+
renderAvailableSubcommands(parentCommandName) {
|
|
181
|
+
const subcommands = this.getSubcommands(parentCommandName);
|
|
182
|
+
if (subcommands.size === 0) return "";
|
|
183
|
+
const prefix = `${parentCommandName} `;
|
|
184
|
+
const body = this.buildGroupedCommandsBody(subcommands, prefix);
|
|
185
|
+
if (body.length === 0) return "";
|
|
186
|
+
const sections = [{ body: `${yc.green(this._cli._name)} ${yc.cyan(parentCommandName)} not found` }, {
|
|
187
|
+
title: "Available Subcommands",
|
|
188
|
+
body
|
|
189
|
+
}];
|
|
190
|
+
return this.renderSections(sections);
|
|
191
|
+
}
|
|
69
192
|
renderCommands() {
|
|
70
193
|
const commands = this._cli._commands;
|
|
71
|
-
|
|
194
|
+
let commandsToShow;
|
|
195
|
+
let title = "Commands";
|
|
196
|
+
let prefix = "";
|
|
197
|
+
if (this._command) {
|
|
198
|
+
prefix = this._command.name ? `${this._command.name} ` : "";
|
|
199
|
+
title = "Subcommands";
|
|
200
|
+
commandsToShow = this.getSubcommands(this._command.name);
|
|
201
|
+
if (commandsToShow.size === 0) return;
|
|
202
|
+
} else commandsToShow = commands;
|
|
203
|
+
if (commandsToShow.size === 0) return;
|
|
204
|
+
const body = this.buildGroupedCommandsBody(commandsToShow, prefix);
|
|
72
205
|
return {
|
|
73
|
-
title
|
|
74
|
-
body
|
|
75
|
-
if (command.__isAlias || command.help?.showInHelp === false) return null;
|
|
76
|
-
return [`${yc.cyan(command.name)}${command.alias ? ` (${toArray(command.alias).join(", ")})` : ""}`, command.description];
|
|
77
|
-
}).filter(isTruthy))
|
|
206
|
+
title,
|
|
207
|
+
body
|
|
78
208
|
};
|
|
79
209
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
210
|
+
renderFlagItem(name, flag) {
|
|
211
|
+
flag = normalizeFlagValue(flag);
|
|
212
|
+
const flagName = formatFlagName(name);
|
|
213
|
+
const aliases = (Array.isArray(flag.alias) ? flag.alias : flag.alias ? [flag.alias] : []).map(formatFlagName).join(", ");
|
|
214
|
+
const type = this._formatters.formatFlagType(flag.type);
|
|
215
|
+
return [
|
|
216
|
+
yc.blue([flagName, aliases].filter(Boolean).join(", ")),
|
|
217
|
+
yc.gray(type),
|
|
218
|
+
flag.description,
|
|
219
|
+
flag.default !== void 0 && yc.gray(`[default: ${this._formatters.formatFlagDefault(flag.default)}]`)
|
|
220
|
+
].filter(isTruthy);
|
|
221
|
+
}
|
|
222
|
+
renderGroupedFlags(flags, groupMap, itemType) {
|
|
223
|
+
const groupedFlags = /* @__PURE__ */ new Map();
|
|
224
|
+
const defaultFlags = [];
|
|
225
|
+
for (const [name, flag] of Object.entries(flags)) {
|
|
226
|
+
const group = flag.help?.group;
|
|
227
|
+
validateGroup(group, groupMap, itemType, name);
|
|
228
|
+
const item = this.renderFlagItem(name, flag);
|
|
229
|
+
if (group && group !== DEFAULT_GROUP_KEY) {
|
|
230
|
+
const groupItems = groupedFlags.get(group) ?? [];
|
|
231
|
+
groupItems.push(item);
|
|
232
|
+
groupedFlags.set(group, groupItems);
|
|
233
|
+
} else defaultFlags.push(item);
|
|
234
|
+
}
|
|
235
|
+
const body = [];
|
|
236
|
+
if (defaultFlags.length > 0) body.push(...splitTable(defaultFlags));
|
|
237
|
+
for (const [key, name] of groupMap) {
|
|
238
|
+
const items = groupedFlags.get(key);
|
|
239
|
+
if (items && items.length > 0) {
|
|
240
|
+
if (body.length > 0) body.push("");
|
|
241
|
+
body.push(`${yc.dim(name)}`);
|
|
242
|
+
body.push(...splitTable(items).map(withIndent));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return body;
|
|
94
246
|
}
|
|
95
247
|
renderCommandFlags() {
|
|
96
248
|
const command = this._command;
|
|
97
249
|
if (!command?.flags || objectIsEmpty(command.flags)) return;
|
|
98
250
|
return {
|
|
99
251
|
title: "Flags",
|
|
100
|
-
body:
|
|
252
|
+
body: this.renderGroupedFlags(command.flags, this._flagGroups, "flag")
|
|
101
253
|
};
|
|
102
254
|
}
|
|
103
255
|
renderGlobalFlags() {
|
|
104
256
|
if (!this._globalFlags || objectIsEmpty(this._globalFlags)) return;
|
|
105
257
|
return {
|
|
106
258
|
title: "Global Flags",
|
|
107
|
-
body:
|
|
259
|
+
body: this.renderGroupedFlags(this._globalFlags, this._globalFlagGroups, "global flag")
|
|
108
260
|
};
|
|
109
261
|
}
|
|
110
262
|
renderNotes() {
|
|
@@ -129,9 +281,20 @@ var HelpRenderer = class {
|
|
|
129
281
|
}
|
|
130
282
|
};
|
|
131
283
|
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/store.ts
|
|
286
|
+
function addStoreApi(cli, { groups }) {
|
|
287
|
+
cli.store.help = { addGroup: (options) => {
|
|
288
|
+
if (options.commands) groups.commands = [...groups.commands ?? [], ...options.commands];
|
|
289
|
+
if (options.flags) groups.flags = [...groups.flags ?? [], ...options.flags];
|
|
290
|
+
if (options.globalFlags) groups.globalFlags = [...groups.globalFlags ?? [], ...options.globalFlags];
|
|
291
|
+
} };
|
|
292
|
+
}
|
|
293
|
+
|
|
132
294
|
//#endregion
|
|
133
295
|
//#region src/index.ts
|
|
134
|
-
const helpPlugin = ({ command = true, flag = true, showHelpWhenNoCommandSpecified = true, notes, examples, banner, formatters } = {}) => definePlugin({ setup: (cli) => {
|
|
296
|
+
const helpPlugin = ({ command = true, flag = true, showHelpWhenNoCommandSpecified = true, notes, examples, banner, formatters, groups = {} } = {}) => definePlugin({ setup: (cli) => {
|
|
297
|
+
addStoreApi(cli, { groups });
|
|
135
298
|
const mergedFormatters = {
|
|
136
299
|
...defaultFormatters,
|
|
137
300
|
...formatters
|
|
@@ -152,6 +315,15 @@ const helpPlugin = ({ command = true, flag = true, showHelpWhenNoCommandSpecifie
|
|
|
152
315
|
if (banner) console.log(banner);
|
|
153
316
|
console.log(s);
|
|
154
317
|
}
|
|
318
|
+
const renderer = new HelpRenderer(mergedFormatters, cli, cli._globalFlags, () => groups, effectiveExamples, effectiveNotes);
|
|
319
|
+
function tryPrintSubcommandsHelp(commandName) {
|
|
320
|
+
const subcommandsOutput = renderer.renderAvailableSubcommands(commandName);
|
|
321
|
+
if (subcommandsOutput) {
|
|
322
|
+
printHelp(subcommandsOutput);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
155
327
|
if (command) cli.command("help", "Show help", {
|
|
156
328
|
parameters: ["[command...]"],
|
|
157
329
|
help: {
|
|
@@ -164,11 +336,13 @@ const helpPlugin = ({ command = true, flag = true, showHelpWhenNoCommandSpecifie
|
|
|
164
336
|
if (commandName.length > 0) {
|
|
165
337
|
[command$1] = resolveCommand(cli._commands, commandName);
|
|
166
338
|
if (!command$1) {
|
|
167
|
-
|
|
168
|
-
return;
|
|
339
|
+
const parentCommandName = commandName.join(" ");
|
|
340
|
+
if (tryPrintSubcommandsHelp(parentCommandName)) return;
|
|
341
|
+
throw new NoSuchCommandError(parentCommandName);
|
|
169
342
|
}
|
|
170
343
|
}
|
|
171
|
-
|
|
344
|
+
renderer.setCommand(command$1);
|
|
345
|
+
printHelp(renderer.render());
|
|
172
346
|
});
|
|
173
347
|
if (flag) cli.globalFlag("help", "Show help", {
|
|
174
348
|
alias: "h",
|
|
@@ -176,10 +350,17 @@ const helpPlugin = ({ command = true, flag = true, showHelpWhenNoCommandSpecifie
|
|
|
176
350
|
default: false
|
|
177
351
|
});
|
|
178
352
|
cli.interceptor({
|
|
179
|
-
enforce: "
|
|
353
|
+
enforce: "post",
|
|
180
354
|
handler: async (ctx, next) => {
|
|
181
|
-
if (ctx.flags.help)
|
|
182
|
-
|
|
355
|
+
if (ctx.flags.help) {
|
|
356
|
+
const command$1 = ctx.command;
|
|
357
|
+
if (!command$1 && ctx.rawParsed.parameters.length > 0) {
|
|
358
|
+
if (tryPrintSubcommandsHelp(ctx.rawParsed.parameters.join(" "))) return;
|
|
359
|
+
await next();
|
|
360
|
+
}
|
|
361
|
+
renderer.setCommand(command$1);
|
|
362
|
+
printHelp(renderer.render());
|
|
363
|
+
} else if (showHelpWhenNoCommandSpecified && !ctx.command && ctx.rawParsed.parameters.length === 0) printHelp(renderer.render());
|
|
183
364
|
else await next();
|
|
184
365
|
}
|
|
185
366
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clerc/plugin-help",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.20",
|
|
4
4
|
"author": "Ray <i@mk1.io> (https://github.com/so1ve)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Clerc plugin help",
|
|
@@ -48,18 +48,15 @@
|
|
|
48
48
|
"@types/text-table": "^0.2.5",
|
|
49
49
|
"string-width": "^8.1.0",
|
|
50
50
|
"text-table": "^0.2.0",
|
|
51
|
-
"yoctocolors": "^2.1.2"
|
|
52
|
-
"@clerc/utils": "1.0.0-beta.2"
|
|
51
|
+
"yoctocolors": "^2.1.2"
|
|
53
52
|
},
|
|
54
53
|
"devDependencies": {
|
|
55
|
-
"
|
|
56
|
-
"@clerc/
|
|
54
|
+
"kons": "^0.7.1",
|
|
55
|
+
"@clerc/parser": "1.0.0-beta.20",
|
|
56
|
+
"@clerc/core": "1.0.0-beta.20",
|
|
57
|
+
"@clerc/utils": "1.0.0-beta.20"
|
|
57
58
|
},
|
|
58
59
|
"peerDependencies": {
|
|
59
60
|
"@clerc/core": "*"
|
|
60
|
-
},
|
|
61
|
-
"scripts": {
|
|
62
|
-
"build": "tsdown",
|
|
63
|
-
"watch": "tsdown --watch"
|
|
64
61
|
}
|
|
65
62
|
}
|