@clankmates/cli 0.5.1 → 0.5.2
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/package.json +1 -1
- package/src/cli.ts +36 -4
- package/src/lib/help.ts +70 -25
- package/src/lib/output.ts +5 -1
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -50,7 +50,9 @@ export async function runCli(
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
if (command === "help") {
|
|
53
|
-
const helpText = renderHelp(parsed.positionals
|
|
53
|
+
const helpText = renderHelp(parsed.positionals, {
|
|
54
|
+
boldSectionTitles: shouldBoldHelpSections(io),
|
|
55
|
+
});
|
|
54
56
|
|
|
55
57
|
if (!helpText) {
|
|
56
58
|
throw new CliError(formatUnknownHelpTopic(parsed.positionals), 2);
|
|
@@ -61,12 +63,18 @@ export async function runCli(
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
if (!command) {
|
|
64
|
-
io.stdout(
|
|
66
|
+
io.stdout(
|
|
67
|
+
renderHelp([], {
|
|
68
|
+
boldSectionTitles: shouldBoldHelpSections(io),
|
|
69
|
+
})!,
|
|
70
|
+
);
|
|
65
71
|
return 0;
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
if (parsed.flags.help === true) {
|
|
69
|
-
const helpText = renderHelp([command, ...parsed.positionals]
|
|
75
|
+
const helpText = renderHelp([command, ...parsed.positionals], {
|
|
76
|
+
boldSectionTitles: shouldBoldHelpSections(io),
|
|
77
|
+
});
|
|
70
78
|
|
|
71
79
|
if (!helpText) {
|
|
72
80
|
throw new CliError(
|
|
@@ -80,7 +88,11 @@ export async function runCli(
|
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
if (resolvesToHelpGroup([command, ...parsed.positionals])) {
|
|
83
|
-
io.stdout(
|
|
91
|
+
io.stdout(
|
|
92
|
+
renderHelp([command, ...parsed.positionals], {
|
|
93
|
+
boldSectionTitles: shouldBoldHelpSections(io),
|
|
94
|
+
})!,
|
|
95
|
+
);
|
|
84
96
|
return 0;
|
|
85
97
|
}
|
|
86
98
|
|
|
@@ -103,6 +115,26 @@ export async function runCli(
|
|
|
103
115
|
}
|
|
104
116
|
}
|
|
105
117
|
|
|
118
|
+
function shouldBoldHelpSections(io: Io): boolean {
|
|
119
|
+
if (io.stdoutIsTTY !== true) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (process.env.NO_COLOR !== undefined) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (process.env.CLICOLOR === "0" || process.env.FORCE_COLOR === "0") {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (process.env.TERM === "dumb") {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
function formatUnknownHelpTopic(path: string[]): string {
|
|
107
139
|
const topic = path.join(" ");
|
|
108
140
|
return topic
|
package/src/lib/help.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { CLI_VERSION } from "./version";
|
|
2
2
|
|
|
3
3
|
const CLI_NAME = "clankm";
|
|
4
|
+
const ANSI_BOLD = "\u001b[1m";
|
|
5
|
+
const ANSI_RESET = "\u001b[0m";
|
|
6
|
+
|
|
7
|
+
interface HelpRenderOptions {
|
|
8
|
+
boldSectionTitles?: boolean;
|
|
9
|
+
}
|
|
4
10
|
|
|
5
11
|
interface HelpOption {
|
|
6
12
|
flag: string;
|
|
@@ -945,7 +951,7 @@ const HELP_ROOT = group(
|
|
|
945
951
|
),
|
|
946
952
|
],
|
|
947
953
|
{
|
|
948
|
-
description: "
|
|
954
|
+
description: "Work with clankmates.com from the command line.",
|
|
949
955
|
usage: [`${CLI_NAME} <command>`, `${CLI_NAME} help <command-path>`],
|
|
950
956
|
examples: [
|
|
951
957
|
`${CLI_NAME}`,
|
|
@@ -963,7 +969,10 @@ const HELP_ROOT = group(
|
|
|
963
969
|
},
|
|
964
970
|
);
|
|
965
971
|
|
|
966
|
-
export function renderHelp(
|
|
972
|
+
export function renderHelp(
|
|
973
|
+
path: string[],
|
|
974
|
+
options: HelpRenderOptions = {},
|
|
975
|
+
): string | undefined {
|
|
967
976
|
const resolved = resolveHelpNode(path);
|
|
968
977
|
|
|
969
978
|
if (!resolved) {
|
|
@@ -971,8 +980,8 @@ export function renderHelp(path: string[]): string | undefined {
|
|
|
971
980
|
}
|
|
972
981
|
|
|
973
982
|
return resolved.node.kind === "group"
|
|
974
|
-
? renderGroupHelp(resolved.node, resolved.path)
|
|
975
|
-
: renderCommandHelp(resolved.node, resolved.path);
|
|
983
|
+
? renderGroupHelp(resolved.node, resolved.path, options)
|
|
984
|
+
: renderCommandHelp(resolved.node, resolved.path, options);
|
|
976
985
|
}
|
|
977
986
|
|
|
978
987
|
export function resolvesToHelpGroup(path: string[]): boolean {
|
|
@@ -1010,7 +1019,11 @@ function matchesSegment(node: HelpNode, segment: string): boolean {
|
|
|
1010
1019
|
return node.name === segment || node.aliases?.includes(segment) === true;
|
|
1011
1020
|
}
|
|
1012
1021
|
|
|
1013
|
-
function renderGroupHelp(
|
|
1022
|
+
function renderGroupHelp(
|
|
1023
|
+
node: HelpGroup,
|
|
1024
|
+
path: string[],
|
|
1025
|
+
options: HelpRenderOptions,
|
|
1026
|
+
): string {
|
|
1014
1027
|
const title = path.length === 0 ? `${CLI_NAME} ${CLI_VERSION}` : `${CLI_NAME} ${path.join(" ")}`;
|
|
1015
1028
|
const sections: string[] = [title];
|
|
1016
1029
|
|
|
@@ -1021,26 +1034,32 @@ function renderGroupHelp(node: HelpGroup, path: string[]): string {
|
|
|
1021
1034
|
}
|
|
1022
1035
|
|
|
1023
1036
|
if (node.usage && node.usage.length > 0) {
|
|
1024
|
-
sections.push(renderUsageSection(node.usage));
|
|
1037
|
+
sections.push(renderUsageSection(node.usage, options));
|
|
1025
1038
|
}
|
|
1026
1039
|
|
|
1027
1040
|
if (node.aliases && node.aliases.length > 0) {
|
|
1028
|
-
sections.push(renderLineListSection("Aliases", node.aliases));
|
|
1041
|
+
sections.push(renderLineListSection("Aliases", node.aliases, false, options));
|
|
1029
1042
|
}
|
|
1030
1043
|
|
|
1031
1044
|
const childHeading = path.length === 0 ? "Commands" : "Subcommands";
|
|
1032
|
-
sections.push(renderEntrySection(childHeading, node.children));
|
|
1045
|
+
sections.push(renderEntrySection(childHeading, node.children, options));
|
|
1033
1046
|
|
|
1034
1047
|
if (node.options && node.options.length > 0) {
|
|
1035
|
-
sections.push(
|
|
1048
|
+
sections.push(
|
|
1049
|
+
renderOptionSection(
|
|
1050
|
+
path.length === 0 ? "Global Flags" : "Options",
|
|
1051
|
+
node.options,
|
|
1052
|
+
options,
|
|
1053
|
+
),
|
|
1054
|
+
);
|
|
1036
1055
|
}
|
|
1037
1056
|
|
|
1038
1057
|
if (node.examples && node.examples.length > 0) {
|
|
1039
|
-
sections.push(renderLineListSection("Examples", node.examples, true));
|
|
1058
|
+
sections.push(renderLineListSection("Examples", node.examples, true, options));
|
|
1040
1059
|
}
|
|
1041
1060
|
|
|
1042
1061
|
if (node.notes && node.notes.length > 0) {
|
|
1043
|
-
sections.push(renderLineListSection("Notes", node.notes));
|
|
1062
|
+
sections.push(renderLineListSection("Notes", node.notes, false, options));
|
|
1044
1063
|
}
|
|
1045
1064
|
|
|
1046
1065
|
if (path.length === 0) {
|
|
@@ -1052,43 +1071,56 @@ function renderGroupHelp(node: HelpGroup, path: string[]): string {
|
|
|
1052
1071
|
return sections.join("\n\n");
|
|
1053
1072
|
}
|
|
1054
1073
|
|
|
1055
|
-
function renderCommandHelp(
|
|
1074
|
+
function renderCommandHelp(
|
|
1075
|
+
node: HelpCommand,
|
|
1076
|
+
path: string[],
|
|
1077
|
+
options: HelpRenderOptions,
|
|
1078
|
+
): string {
|
|
1056
1079
|
const title = `${CLI_NAME} ${path.join(" ")}`;
|
|
1057
1080
|
const sections: string[] = [title, node.description ?? node.summary];
|
|
1058
1081
|
|
|
1059
1082
|
if (node.aliases && node.aliases.length > 0) {
|
|
1060
|
-
sections.push(renderLineListSection("Aliases", node.aliases));
|
|
1083
|
+
sections.push(renderLineListSection("Aliases", node.aliases, false, options));
|
|
1061
1084
|
}
|
|
1062
1085
|
|
|
1063
1086
|
if (node.usage && node.usage.length > 0) {
|
|
1064
|
-
sections.push(renderUsageSection(node.usage));
|
|
1087
|
+
sections.push(renderUsageSection(node.usage, options));
|
|
1065
1088
|
}
|
|
1066
1089
|
|
|
1067
1090
|
if (node.options && node.options.length > 0) {
|
|
1068
|
-
sections.push(renderOptionSection("Options", node.options));
|
|
1091
|
+
sections.push(renderOptionSection("Options", node.options, options));
|
|
1069
1092
|
}
|
|
1070
1093
|
|
|
1071
1094
|
if (node.examples && node.examples.length > 0) {
|
|
1072
|
-
sections.push(renderLineListSection("Examples", node.examples, true));
|
|
1095
|
+
sections.push(renderLineListSection("Examples", node.examples, true, options));
|
|
1073
1096
|
}
|
|
1074
1097
|
|
|
1075
1098
|
if (node.notes && node.notes.length > 0) {
|
|
1076
|
-
sections.push(renderLineListSection("Notes", node.notes));
|
|
1099
|
+
sections.push(renderLineListSection("Notes", node.notes, false, options));
|
|
1077
1100
|
}
|
|
1078
1101
|
|
|
1079
1102
|
return sections.join("\n\n");
|
|
1080
1103
|
}
|
|
1081
1104
|
|
|
1082
|
-
function renderUsageSection(
|
|
1083
|
-
|
|
1105
|
+
function renderUsageSection(
|
|
1106
|
+
usage: string[],
|
|
1107
|
+
options: HelpRenderOptions,
|
|
1108
|
+
): string {
|
|
1109
|
+
return [formatSectionTitle("USAGE", options), ...usage.map((line) => ` ${line}`)].join(
|
|
1110
|
+
"\n",
|
|
1111
|
+
);
|
|
1084
1112
|
}
|
|
1085
1113
|
|
|
1086
|
-
function renderEntrySection(
|
|
1087
|
-
|
|
1114
|
+
function renderEntrySection(
|
|
1115
|
+
title: string,
|
|
1116
|
+
entries: HelpNode[],
|
|
1117
|
+
options: HelpRenderOptions,
|
|
1118
|
+
): string {
|
|
1119
|
+
const labels = entries.map((entry) => `${formatEntryLabel(entry)}:`);
|
|
1088
1120
|
const width = labels.reduce((current, label) => Math.max(current, label.length), 0);
|
|
1089
1121
|
|
|
1090
1122
|
return [
|
|
1091
|
-
|
|
1123
|
+
formatSectionTitle(title, options),
|
|
1092
1124
|
...entries.map((entry, index) => {
|
|
1093
1125
|
const label = labels[index]!.padEnd(width, " ");
|
|
1094
1126
|
return ` ${label} ${entry.summary}`;
|
|
@@ -1096,11 +1128,15 @@ function renderEntrySection(title: string, entries: HelpNode[]): string {
|
|
|
1096
1128
|
].join("\n");
|
|
1097
1129
|
}
|
|
1098
1130
|
|
|
1099
|
-
function renderOptionSection(
|
|
1131
|
+
function renderOptionSection(
|
|
1132
|
+
title: string,
|
|
1133
|
+
options: HelpOption[],
|
|
1134
|
+
renderOptions: HelpRenderOptions,
|
|
1135
|
+
): string {
|
|
1100
1136
|
const width = options.reduce((current, entry) => Math.max(current, entry.flag.length), 0);
|
|
1101
1137
|
|
|
1102
1138
|
return [
|
|
1103
|
-
|
|
1139
|
+
formatSectionTitle(title, renderOptions),
|
|
1104
1140
|
...options.map((entry) => ` ${entry.flag.padEnd(width, " ")} ${entry.description}`),
|
|
1105
1141
|
].join("\n");
|
|
1106
1142
|
}
|
|
@@ -1109,9 +1145,10 @@ function renderLineListSection(
|
|
|
1109
1145
|
title: string,
|
|
1110
1146
|
lines: string[],
|
|
1111
1147
|
code = false,
|
|
1148
|
+
options: HelpRenderOptions,
|
|
1112
1149
|
): string {
|
|
1113
1150
|
return [
|
|
1114
|
-
|
|
1151
|
+
formatSectionTitle(title, options),
|
|
1115
1152
|
...lines.map((line) => ` ${code ? line : line}`),
|
|
1116
1153
|
].join("\n");
|
|
1117
1154
|
}
|
|
@@ -1121,3 +1158,11 @@ function formatEntryLabel(entry: HelpNode): string {
|
|
|
1121
1158
|
? `${entry.name}, ${entry.aliases.join(", ")}`
|
|
1122
1159
|
: entry.name;
|
|
1123
1160
|
}
|
|
1161
|
+
|
|
1162
|
+
function formatSectionTitle(
|
|
1163
|
+
title: string,
|
|
1164
|
+
options: HelpRenderOptions = {},
|
|
1165
|
+
): string {
|
|
1166
|
+
const heading = title.toUpperCase();
|
|
1167
|
+
return options.boldSectionTitles ? `${ANSI_BOLD}${heading}${ANSI_RESET}` : heading;
|
|
1168
|
+
}
|
package/src/lib/output.ts
CHANGED
|
@@ -3,12 +3,16 @@ import type { OutputMode } from "../types/api";
|
|
|
3
3
|
export interface Io {
|
|
4
4
|
stdout: (message: string) => void;
|
|
5
5
|
stderr: (message: string) => void;
|
|
6
|
+
stdoutIsTTY?: boolean;
|
|
7
|
+
stderrIsTTY?: boolean;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
export function defaultIo(): Io {
|
|
9
11
|
return {
|
|
10
12
|
stdout: (message) => process.stdout.write(`${message}\n`),
|
|
11
|
-
stderr: (message) => process.stderr.write(`${message}\n`)
|
|
13
|
+
stderr: (message) => process.stderr.write(`${message}\n`),
|
|
14
|
+
stdoutIsTTY: process.stdout.isTTY,
|
|
15
|
+
stderrIsTTY: process.stderr.isTTY,
|
|
12
16
|
};
|
|
13
17
|
}
|
|
14
18
|
|