@flowscripter/dynamic-cli-framework 1.1.5 → 1.2.0
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/.github/workflows/release-bun-library.yml +1 -0
- package/README/core-commands.md +40 -0
- package/README/core-service-providers.md +198 -0
- package/README/development.md +60 -0
- package/README/implementation-details.md +474 -0
- package/README/key-concepts.md +751 -0
- package/README.md +12 -1413
- package/bun.lock +20 -18
- package/index.ts +98 -1
- package/package.json +8 -7
- package/src/api/BaseCLIFeatureOptions.ts +10 -0
- package/src/api/CLIConfig.ts +5 -0
- package/src/api/RunResult.ts +16 -0
- package/src/api/argument/Argument.ts +40 -1
- package/src/api/argument/ArgumentValueTypes.ts +1 -1
- package/src/api/command/SubCommand.ts +1 -1
- package/src/api/service/ServiceProvider.ts +3 -3
- package/src/api/service/core/ArgumentPrompterService.ts +10 -0
- package/src/api/service/core/AsciiBannerGeneratorService.ts +44 -7
- package/src/api/service/core/CompletionService.ts +36 -0
- package/src/api/service/core/DataDumpGeneratorService.ts +27 -0
- package/src/api/service/core/ImagePrinterService.ts +26 -0
- package/src/api/service/core/KeyValueService.ts +22 -5
- package/src/api/service/core/PrinterService.ts +127 -1
- package/src/api/service/core/PrompterService.ts +49 -0
- package/src/api/service/core/SecretService.ts +27 -0
- package/src/api/service/core/ShutdownService.ts +17 -1
- package/src/api/service/core/Table.ts +85 -0
- package/src/api/service/core/TableGeneratorService.ts +38 -0
- package/src/api/service/core/TreePrinterService.ts +11 -0
- package/src/cli/BaseCLI.ts +116 -44
- package/src/cli/DefaultRuntimeCLI.ts +10 -18
- package/src/command/CompletionCommand.ts +179 -0
- package/src/command/MultiCommandCliHelpCommand.ts +20 -32
- package/src/command/SingleCommandCliHelpCommand.ts +10 -1
- package/src/launcher.ts +16 -58
- package/src/runtime/command/CommandValidator.ts +70 -6
- package/src/runtime/runner.ts +112 -31
- package/src/runtime/scanner.ts +18 -15
- package/src/runtime/values/argumentValueValidation.ts +93 -10
- package/src/runtime/values/globalCommandValuePopulation.ts +1 -1
- package/src/runtime/values/subCommandValuePopulation.ts +9 -8
- package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +34 -0
- package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +330 -0
- package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +1 -1
- package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +254 -17
- package/src/service/banner/BannerServiceProvider.ts +2 -2
- package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +85 -0
- package/src/service/chiselAsciiBannerGenerator/chisel.flf.json +3 -0
- package/src/service/completion/CompletionServiceProvider.ts +212 -0
- package/src/service/completion/DefaultCompletionService.ts +364 -0
- package/src/service/completion/shell/ShellHandler.ts +16 -0
- package/src/service/completion/shell/bash.ts +47 -0
- package/src/service/completion/shell/fish.ts +43 -0
- package/src/service/completion/shell/powershell.ts +66 -0
- package/src/service/completion/shell/zsh.ts +50 -0
- package/src/service/configuration/ConfigurationServiceProvider.ts +138 -42
- package/src/service/configuration/DefaultKeyValueService.ts +53 -7
- package/src/service/configuration/DefaultSecretService.ts +85 -0
- package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +41 -0
- package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +80 -0
- package/src/service/imagePrinter/DefaultImagePrinterService.ts +23 -0
- package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +32 -0
- package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +1 -1
- package/src/service/printer/DefaultPrinterService.ts +147 -27
- package/src/service/printer/PrinterServiceProvider.ts +7 -7
- package/src/service/printer/command/LogLevelCommand.ts +2 -1
- package/src/service/printer/command/NoHyperlinksCommand.ts +40 -0
- package/src/service/printer/terminal/Progress.ts +21 -4
- package/src/service/printer/terminal/Spinner.ts +32 -8
- package/src/service/printer/terminal/Theme.ts +1 -1
- package/src/service/prompter/DefaultPrompterService.ts +87 -0
- package/src/service/prompter/PrompterServiceProvider.ts +36 -0
- package/src/service/prompter/command/NoPromptCommand.ts +40 -0
- package/src/service/prompter/prompt/PromptContext.ts +47 -0
- package/src/service/prompter/prompt/promptAcknowledge.ts +28 -0
- package/src/service/prompter/prompt/promptMultiSelect.ts +99 -0
- package/src/service/prompter/prompt/promptOpenUrl.ts +97 -0
- package/src/service/prompter/prompt/promptSingleSelect.ts +102 -0
- package/src/service/prompter/prompt/promptText.ts +107 -0
- package/src/service/prompter/prompt/promptToggle.ts +28 -0
- package/src/service/shutdown/DefaultShutdownService.ts +13 -0
- package/src/service/shutdown/ShutdownServiceProvider.ts +28 -9
- package/src/service/shutdown/ShutdownState.ts +5 -0
- package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +1 -1
- package/src/service/tableGenerator/DefaultTableGeneratorService.ts +415 -0
- package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +43 -0
- package/src/service/treePrinter/DefaultTreePrinterService.ts +49 -0
- package/src/service/treePrinter/TreePrinterServiceProvider.ts +40 -0
- package/src/terminal/Ansi.ts +27 -0
- package/src/terminal/ImageRenderer.ts +199 -0
- package/src/terminal/KeyReader.ts +23 -0
- package/src/terminal/PngDecoder.ts +143 -0
- package/src/{service/printer/terminal → terminal}/Styler.ts +3 -0
- package/src/{service/printer/terminal → terminal}/Terminal.ts +1 -0
- package/src/terminal/TtyKeyReader.ts +83 -0
- package/src/terminal/TtyStyler.ts +78 -0
- package/src/{service/printer/terminal → terminal}/TtyTerminal.ts +9 -1
- package/src/terminal/supportsHyperlinks.ts +110 -0
- package/src/util/configHelper.ts +2 -2
- package/src/util/envVarHelper.ts +2 -2
- package/src/util/helpHelper.ts +139 -123
- package/src/util/logger.ts +16 -14
- package/src/util/runnerHelper.ts +41 -0
- package/tests/cli/BaseCLI.test.ts +50 -54
- package/tests/command/CompletionCommand.test.ts +68 -0
- package/tests/command/UsageCommand.test.ts +3 -2
- package/tests/command/VersionCommand.test.ts +3 -2
- package/tests/fixtures/Context.ts +9 -2
- package/tests/fixtures/util.ts +1 -1
- package/tests/runtime/command/CommandValidator.test.ts +103 -0
- package/tests/runtime/parser.test.ts +9 -7
- package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +3 -3
- package/tests/runtime/runner.test.ts +36 -0
- package/tests/runtime/values/argumentValueValidation.test.ts +215 -1
- package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +47 -0
- package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +754 -0
- package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +5 -4
- package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +163 -3
- package/tests/service/asciiBannerGenerator/__snapshots__/DefaultAsciiBannerGeneratorService.test.ts.snap +1 -1
- package/tests/service/banner/BannerServiceProvider.test.ts +8 -4
- package/tests/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.test.ts +52 -0
- package/tests/service/completion/CompletionServiceProvider.test.ts +404 -0
- package/tests/service/completion/DefaultCompletionService.test.ts +278 -0
- package/tests/service/completion/shell/bash.test.ts +73 -0
- package/tests/service/completion/shell/fish.test.ts +62 -0
- package/tests/service/completion/shell/powershell.test.ts +59 -0
- package/tests/service/completion/shell/zsh.test.ts +60 -0
- package/tests/service/configuration/ConfigurationServiceProvider.test.ts +24 -12
- package/tests/service/configuration/DefaultKeyValueService.test.ts +118 -16
- package/tests/service/configuration/DefaultSecretService.test.ts +148 -0
- package/tests/service/configuration/command/ConfigCommand.test.ts +29 -0
- package/tests/service/configuration/command/DumpConfigCommand.test.ts +60 -0
- package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +57 -0
- package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +217 -0
- package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +96 -0
- package/tests/service/imagePrinter/ImagePrinterServiceProvider.test.ts +17 -0
- package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +2 -2
- package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +5 -4
- package/tests/service/printer/DefaultPrinterService.test.ts +233 -2
- package/tests/service/printer/PrinterServiceProvider.test.ts +6 -5
- package/tests/service/printer/command/DarkModeCommand.test.ts +83 -0
- package/tests/service/printer/command/LogLevelCommand.test.ts +8 -6
- package/tests/service/printer/command/NoColorCommand.test.ts +83 -0
- package/tests/service/printer/command/NoHyperlinksCommand.test.ts +89 -0
- package/tests/service/printer/terminal/Progress.test.ts +64 -4
- package/tests/service/printer/terminal/Spinner.test.ts +44 -3
- package/tests/service/prompter/DefaultPrompterService.test.ts +615 -0
- package/tests/service/prompter/PrompterServiceProvider.test.ts +47 -0
- package/tests/service/prompter/command/NoPromptCommand.test.ts +58 -0
- package/tests/service/shutdown/ShutdownServiceProvider.test.ts +4 -2
- package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +3 -2
- package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +5 -4
- package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +363 -0
- package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +47 -0
- package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +144 -0
- package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +55 -0
- package/tests/terminal/ImageRenderer.test.ts +161 -0
- package/tests/terminal/PngDecoder.test.ts +223 -0
- package/tests/terminal/supportsHyperlinks.test.ts +149 -0
- package/tests/util/configHelper.test.ts +4 -4
- package/tests/util/logger.test.ts +23 -1
- package/tsconfig.json +31 -0
- package/src/service/printer/terminal/Ansi.ts +0 -10
- package/src/service/printer/terminal/TtyStyler.ts +0 -39
|
@@ -1,12 +1,94 @@
|
|
|
1
1
|
import type AsciiBannerGeneratorService from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
2
|
+
import type {
|
|
3
|
+
BannerGenerateOptions,
|
|
4
|
+
ColorEffect,
|
|
5
|
+
} from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
6
|
+
import {
|
|
7
|
+
BACKGROUND_COLOR_END,
|
|
8
|
+
backgroundColorStart,
|
|
9
|
+
FOREGROUND_COLOR_END,
|
|
10
|
+
foregroundColorStart,
|
|
11
|
+
} from "../../terminal/Ansi.ts";
|
|
2
12
|
import figlet from "figlet";
|
|
3
|
-
// FIGlet font is converted to a JSON string and embedded in a simple JSON file: `{ "font": "<figlet font definition>" }`
|
|
4
13
|
import standardFont from "./standard.flf.json" with { type: "json" };
|
|
5
14
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
|
|
15
|
+
function hslToRgb(h: number, s: number, l: number): [number, number, number] {
|
|
16
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
17
|
+
const x = c * (1 - Math.abs(((h * 6) % 2) - 1));
|
|
18
|
+
const m = l - c / 2;
|
|
19
|
+
let r = 0, g = 0, b = 0;
|
|
20
|
+
if (h < 1 / 6) {
|
|
21
|
+
r = c;
|
|
22
|
+
g = x;
|
|
23
|
+
b = 0;
|
|
24
|
+
} else if (h < 2 / 6) {
|
|
25
|
+
r = x;
|
|
26
|
+
g = c;
|
|
27
|
+
b = 0;
|
|
28
|
+
} else if (h < 3 / 6) {
|
|
29
|
+
r = 0;
|
|
30
|
+
g = c;
|
|
31
|
+
b = x;
|
|
32
|
+
} else if (h < 4 / 6) {
|
|
33
|
+
r = 0;
|
|
34
|
+
g = x;
|
|
35
|
+
b = c;
|
|
36
|
+
} else if (h < 5 / 6) {
|
|
37
|
+
r = x;
|
|
38
|
+
g = 0;
|
|
39
|
+
b = c;
|
|
40
|
+
} else {
|
|
41
|
+
r = c;
|
|
42
|
+
g = 0;
|
|
43
|
+
b = x;
|
|
44
|
+
}
|
|
45
|
+
return [
|
|
46
|
+
Math.round((r + m) * 255),
|
|
47
|
+
Math.round((g + m) * 255),
|
|
48
|
+
Math.round((b + m) * 255),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function parseHex(hex: string): [number, number, number] {
|
|
53
|
+
const v = parseInt(hex.slice(1), 16);
|
|
54
|
+
return [(v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function interpolateColors(
|
|
58
|
+
colorStops: [number, number, number][],
|
|
59
|
+
position: number,
|
|
60
|
+
total: number,
|
|
61
|
+
): [number, number, number] {
|
|
62
|
+
const first = colorStops[0];
|
|
63
|
+
if (total <= 1 || first === undefined) return first ?? [0, 0, 0];
|
|
64
|
+
const t = position / (total - 1);
|
|
65
|
+
const scaledT = t * (colorStops.length - 1);
|
|
66
|
+
const idx = Math.min(Math.floor(scaledT), colorStops.length - 2);
|
|
67
|
+
const localT = scaledT - idx;
|
|
68
|
+
const stop1 = colorStops[idx];
|
|
69
|
+
const stop2 = colorStops[idx + 1];
|
|
70
|
+
if (stop1 === undefined || stop2 === undefined) return first;
|
|
71
|
+
const [r1, g1, b1] = stop1;
|
|
72
|
+
const [r2, g2, b2] = stop2;
|
|
73
|
+
return [
|
|
74
|
+
Math.round(r1 + (r2 - r1) * localT),
|
|
75
|
+
Math.round(g1 + (g2 - g1) * localT),
|
|
76
|
+
Math.round(b1 + (b2 - b1) * localT),
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function rainbowColor(
|
|
81
|
+
freq: number,
|
|
82
|
+
spread: number,
|
|
83
|
+
seed: number,
|
|
84
|
+
x: number,
|
|
85
|
+
y: number,
|
|
86
|
+
): [number, number, number] {
|
|
87
|
+
const h = ((freq * (x / spread) + seed + y * freq / spread) % 1.0 + 1.0) %
|
|
88
|
+
1.0;
|
|
89
|
+
return hslToRgb(h, 1.0, 0.5);
|
|
90
|
+
}
|
|
91
|
+
|
|
10
92
|
export default class DefaultAsciiBannerGeneratorService
|
|
11
93
|
implements AsciiBannerGeneratorService {
|
|
12
94
|
#registeredFontNames: Array<string> = [];
|
|
@@ -28,22 +110,177 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
28
110
|
figlet.parseFont(fontName, fontDefinition);
|
|
29
111
|
}
|
|
30
112
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
113
|
+
protected applyForegroundEffect(
|
|
114
|
+
lines: string[],
|
|
115
|
+
effect: ColorEffect,
|
|
116
|
+
): string[] {
|
|
117
|
+
if (effect.type === "fixed") {
|
|
118
|
+
const [r, g, b] = parseHex(effect.color);
|
|
119
|
+
const code = foregroundColorStart(r, g, b);
|
|
120
|
+
return lines.map((line) =>
|
|
121
|
+
line.split("").map((ch) =>
|
|
122
|
+
ch === " " ? ch : code + ch + FOREGROUND_COLOR_END
|
|
123
|
+
).join(
|
|
124
|
+
"",
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (effect.type === "gradient") {
|
|
129
|
+
const colorStops = effect.colors.map(parseHex);
|
|
130
|
+
return lines.map((line, yi) => {
|
|
131
|
+
if (effect.direction === "vertical") {
|
|
132
|
+
const [r, g, b] = interpolateColors(
|
|
133
|
+
colorStops,
|
|
134
|
+
yi,
|
|
135
|
+
Math.max(lines.length, 1),
|
|
136
|
+
);
|
|
137
|
+
const code = foregroundColorStart(r, g, b);
|
|
138
|
+
return line.split("").map((ch) =>
|
|
139
|
+
ch === " " ? ch : code + ch + FOREGROUND_COLOR_END
|
|
140
|
+
).join("");
|
|
141
|
+
}
|
|
142
|
+
const nonSpaceCount = line.split("").filter((c) => c !== " ").length;
|
|
143
|
+
let charIdx = 0;
|
|
144
|
+
return line.split("").map((ch) => {
|
|
145
|
+
if (ch === " ") return ch;
|
|
146
|
+
const [r, g, b] = interpolateColors(
|
|
147
|
+
colorStops,
|
|
148
|
+
charIdx,
|
|
149
|
+
Math.max(nonSpaceCount, 1),
|
|
150
|
+
);
|
|
151
|
+
charIdx++;
|
|
152
|
+
return foregroundColorStart(r, g, b) + ch + FOREGROUND_COLOR_END;
|
|
153
|
+
}).join("");
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const freq = effect.frequency ?? 0.3;
|
|
157
|
+
const spread = effect.spread ?? 8.0;
|
|
158
|
+
const seed = effect.seed ?? Math.random();
|
|
159
|
+
return lines.map((line, yi) => {
|
|
160
|
+
if (effect.direction === "vertical") {
|
|
161
|
+
const [r, g, b] = rainbowColor(freq, spread, seed, 0, yi);
|
|
162
|
+
const code = foregroundColorStart(r, g, b);
|
|
163
|
+
return line.split("").map((ch) =>
|
|
164
|
+
ch === " " ? ch : code + ch + FOREGROUND_COLOR_END
|
|
165
|
+
).join("");
|
|
166
|
+
}
|
|
167
|
+
let charIdx = 0;
|
|
168
|
+
return line.split("").map((ch) => {
|
|
169
|
+
if (ch === " ") return ch;
|
|
170
|
+
const [r, g, b] = rainbowColor(freq, spread, seed, charIdx, yi);
|
|
171
|
+
charIdx++;
|
|
172
|
+
return foregroundColorStart(r, g, b) + ch + FOREGROUND_COLOR_END;
|
|
173
|
+
}).join("");
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
protected applyBackgroundEffect(
|
|
178
|
+
lines: string[],
|
|
179
|
+
effect: ColorEffect,
|
|
180
|
+
): string[] {
|
|
181
|
+
if (effect.type === "fixed") {
|
|
182
|
+
const [r, g, b] = parseHex(effect.color);
|
|
183
|
+
const code = backgroundColorStart(r, g, b);
|
|
184
|
+
return lines.map((line) => code + line + BACKGROUND_COLOR_END);
|
|
185
|
+
}
|
|
186
|
+
if (effect.type === "gradient") {
|
|
187
|
+
const colorStops = effect.colors.map(parseHex);
|
|
188
|
+
return lines.map((line, yi) => {
|
|
189
|
+
if (effect.direction === "vertical") {
|
|
190
|
+
const [r, g, b] = interpolateColors(
|
|
191
|
+
colorStops,
|
|
192
|
+
yi,
|
|
193
|
+
Math.max(lines.length, 1),
|
|
194
|
+
);
|
|
195
|
+
return backgroundColorStart(r, g, b) + line + BACKGROUND_COLOR_END;
|
|
196
|
+
}
|
|
197
|
+
const totalChars = Math.max(line.length, 1);
|
|
198
|
+
return line.split("").map((ch, xi) => {
|
|
199
|
+
const [r, g, b] = interpolateColors(colorStops, xi, totalChars);
|
|
200
|
+
return backgroundColorStart(r, g, b) + ch + BACKGROUND_COLOR_END;
|
|
201
|
+
}).join("");
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const freq = effect.frequency ?? 0.3;
|
|
205
|
+
const spread = effect.spread ?? 8.0;
|
|
206
|
+
const seed = effect.seed ?? Math.random();
|
|
207
|
+
return lines.map((line, yi) => {
|
|
208
|
+
if (effect.direction === "vertical") {
|
|
209
|
+
const [r, g, b] = rainbowColor(freq, spread, seed, 0, yi);
|
|
210
|
+
return backgroundColorStart(r, g, b) + line + BACKGROUND_COLOR_END;
|
|
211
|
+
}
|
|
212
|
+
return line.split("").map((ch, xi) => {
|
|
213
|
+
const [r, g, b] = rainbowColor(freq, spread, seed, xi, yi);
|
|
214
|
+
return backgroundColorStart(r, g, b) + ch + BACKGROUND_COLOR_END;
|
|
215
|
+
}).join("");
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async generate(
|
|
220
|
+
message: string,
|
|
221
|
+
options?: BannerGenerateOptions,
|
|
222
|
+
): Promise<string> {
|
|
223
|
+
const fontName = (options?.fontName ?? "standard").toLowerCase();
|
|
224
|
+
if (!this.getRegisteredFonts().includes(fontName)) {
|
|
225
|
+
throw new Error(`Font name is not registered: ${fontName}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const bannerText = await figlet.text(message, { font: fontName });
|
|
229
|
+
let titleLines = bannerText.split("\n");
|
|
230
|
+
|
|
231
|
+
while (titleLines.length > 0) {
|
|
232
|
+
const last = titleLines[titleLines.length - 1];
|
|
233
|
+
if (last === undefined || last.trim().length > 0) break;
|
|
234
|
+
titleLines.pop();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
let subMessageLine: string | undefined;
|
|
238
|
+
if (options?.subMessage) {
|
|
239
|
+
subMessageLine = options.subMessage
|
|
240
|
+
.toUpperCase()
|
|
241
|
+
.split("")
|
|
242
|
+
.map((c) => c === " " ? " " : c + " ")
|
|
243
|
+
.join("")
|
|
244
|
+
.trimEnd();
|
|
245
|
+
|
|
246
|
+
const bannerWidth = Math.max(...titleLines.map((l) => l.length));
|
|
247
|
+
const subWidth = subMessageLine.length;
|
|
248
|
+
|
|
249
|
+
if (bannerWidth >= subWidth) {
|
|
250
|
+
const pad = Math.floor((bannerWidth - subWidth) / 2);
|
|
251
|
+
subMessageLine = " ".repeat(pad) + subMessageLine;
|
|
252
|
+
} else {
|
|
253
|
+
const pad = Math.floor((subWidth - bannerWidth) / 2);
|
|
254
|
+
titleLines = titleLines.map((l) => " ".repeat(pad) + l);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const colorEffects = options?.colorEffects;
|
|
259
|
+
|
|
260
|
+
if (colorEffects?.messageForeground) {
|
|
261
|
+
titleLines = this.applyForegroundEffect(
|
|
262
|
+
titleLines,
|
|
263
|
+
colorEffects.messageForeground,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let subLines: string[] | undefined;
|
|
268
|
+
if (subMessageLine !== undefined) {
|
|
269
|
+
subLines = [subMessageLine];
|
|
270
|
+
if (colorEffects?.subMessageForeground) {
|
|
271
|
+
subLines = this.applyForegroundEffect(
|
|
272
|
+
subLines,
|
|
273
|
+
colorEffects.subMessageForeground,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
35
276
|
}
|
|
36
277
|
|
|
37
|
-
|
|
38
|
-
const lines = bannerText.split("\n");
|
|
278
|
+
let allLines = subLines ? [...titleLines, ...subLines] : titleLines;
|
|
39
279
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
(lines.length > 0) && (lines[lines.length - 1].trim().length === 0)
|
|
43
|
-
) {
|
|
44
|
-
lines.pop();
|
|
280
|
+
if (colorEffects?.background) {
|
|
281
|
+
allLines = this.applyBackgroundEffect(allLines, colorEffects.background);
|
|
45
282
|
}
|
|
46
283
|
|
|
47
|
-
return "\n" +
|
|
284
|
+
return "\n" + allLines.join("\n") + "\n";
|
|
48
285
|
}
|
|
49
286
|
}
|
|
@@ -46,7 +46,7 @@ export default class BannerServiceProvider implements ServiceProvider {
|
|
|
46
46
|
this.#configurationServiceProvider = configurationServiceProvider;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
public
|
|
49
|
+
public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
|
|
50
50
|
return Promise.resolve({
|
|
51
51
|
commands: [
|
|
52
52
|
new NoBannerCommand(this, this.servicePriority),
|
|
@@ -70,7 +70,7 @@ export default class BannerServiceProvider implements ServiceProvider {
|
|
|
70
70
|
const { cliConfig } = context;
|
|
71
71
|
const bannerText = await asciiBannerGeneratorService.generate(
|
|
72
72
|
cliConfig.name.toUpperCase(),
|
|
73
|
-
this.fontName,
|
|
73
|
+
{ fontName: this.fontName, subMessage: cliConfig.subMessage },
|
|
74
74
|
);
|
|
75
75
|
|
|
76
76
|
await printerService.info(printerService.blue(bannerText));
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type AsciiBannerGeneratorService from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
2
|
+
import type { BannerGenerateOptions } from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
3
|
+
import DefaultAsciiBannerGeneratorService from "../asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts";
|
|
4
|
+
import figlet from "figlet";
|
|
5
|
+
import chiselFont from "./chisel.flf.json" with { type: "json" };
|
|
6
|
+
|
|
7
|
+
export interface ChiselBannerColors {
|
|
8
|
+
highlightForeground?: number; // default 97
|
|
9
|
+
highlightBackground?: number; // default 107
|
|
10
|
+
lightForeground?: number; // default 37
|
|
11
|
+
lightBackground?: number; // default 47
|
|
12
|
+
shadowForeground?: number; // default 90
|
|
13
|
+
shadowBackground?: number; // default 100
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ChiselBannerGenerateOptions extends BannerGenerateOptions {
|
|
17
|
+
chiselColors?: ChiselBannerColors;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default class ChiselFontAsciiBannerGeneratorService
|
|
21
|
+
extends DefaultAsciiBannerGeneratorService
|
|
22
|
+
implements AsciiBannerGeneratorService {
|
|
23
|
+
private _ready = false;
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
this._ready = true;
|
|
28
|
+
figlet.parseFont("chisel", chiselFont.font);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override registerFont(_fontName: string, _fontDefinition: string): void {
|
|
32
|
+
if (this._ready) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"ChiselFontAsciiBannerGeneratorService supports only the built-in chisel font",
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override getRegisteredFonts(): ReadonlyArray<string> {
|
|
40
|
+
return ["chisel"];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override async generate(
|
|
44
|
+
message: string,
|
|
45
|
+
options?: ChiselBannerGenerateOptions,
|
|
46
|
+
): Promise<string> {
|
|
47
|
+
const chiselOptions: BannerGenerateOptions = {
|
|
48
|
+
...options,
|
|
49
|
+
fontName: "chisel",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let result = await super.generate(message, chiselOptions);
|
|
53
|
+
|
|
54
|
+
if (options?.chiselColors) {
|
|
55
|
+
const colors = options.chiselColors;
|
|
56
|
+
const colorMap: Record<string, number> = {};
|
|
57
|
+
if (colors.highlightForeground !== undefined) {
|
|
58
|
+
colorMap["97"] = colors.highlightForeground;
|
|
59
|
+
}
|
|
60
|
+
if (colors.highlightBackground !== undefined) {
|
|
61
|
+
colorMap["107"] = colors.highlightBackground;
|
|
62
|
+
}
|
|
63
|
+
if (colors.lightForeground !== undefined) {
|
|
64
|
+
colorMap["37"] = colors.lightForeground;
|
|
65
|
+
}
|
|
66
|
+
if (colors.lightBackground !== undefined) {
|
|
67
|
+
colorMap["47"] = colors.lightBackground;
|
|
68
|
+
}
|
|
69
|
+
if (colors.shadowForeground !== undefined) {
|
|
70
|
+
colorMap["90"] = colors.shadowForeground;
|
|
71
|
+
}
|
|
72
|
+
if (colors.shadowBackground !== undefined) {
|
|
73
|
+
colorMap["100"] = colors.shadowBackground;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
result = result.replace(
|
|
77
|
+
// deno-lint-ignore no-control-regex
|
|
78
|
+
/\x1b\[(\d+)m/g,
|
|
79
|
+
(_, n) => `\x1b[${colorMap[n] ?? n}m`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
}
|