@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.
Files changed (165) hide show
  1. package/.github/workflows/release-bun-library.yml +1 -0
  2. package/README/core-commands.md +40 -0
  3. package/README/core-service-providers.md +198 -0
  4. package/README/development.md +60 -0
  5. package/README/implementation-details.md +474 -0
  6. package/README/key-concepts.md +751 -0
  7. package/README.md +12 -1413
  8. package/bun.lock +20 -18
  9. package/index.ts +98 -1
  10. package/package.json +8 -7
  11. package/src/api/BaseCLIFeatureOptions.ts +10 -0
  12. package/src/api/CLIConfig.ts +5 -0
  13. package/src/api/RunResult.ts +16 -0
  14. package/src/api/argument/Argument.ts +40 -1
  15. package/src/api/argument/ArgumentValueTypes.ts +1 -1
  16. package/src/api/command/SubCommand.ts +1 -1
  17. package/src/api/service/ServiceProvider.ts +3 -3
  18. package/src/api/service/core/ArgumentPrompterService.ts +10 -0
  19. package/src/api/service/core/AsciiBannerGeneratorService.ts +44 -7
  20. package/src/api/service/core/CompletionService.ts +36 -0
  21. package/src/api/service/core/DataDumpGeneratorService.ts +27 -0
  22. package/src/api/service/core/ImagePrinterService.ts +26 -0
  23. package/src/api/service/core/KeyValueService.ts +22 -5
  24. package/src/api/service/core/PrinterService.ts +127 -1
  25. package/src/api/service/core/PrompterService.ts +49 -0
  26. package/src/api/service/core/SecretService.ts +27 -0
  27. package/src/api/service/core/ShutdownService.ts +17 -1
  28. package/src/api/service/core/Table.ts +85 -0
  29. package/src/api/service/core/TableGeneratorService.ts +38 -0
  30. package/src/api/service/core/TreePrinterService.ts +11 -0
  31. package/src/cli/BaseCLI.ts +116 -44
  32. package/src/cli/DefaultRuntimeCLI.ts +10 -18
  33. package/src/command/CompletionCommand.ts +179 -0
  34. package/src/command/MultiCommandCliHelpCommand.ts +20 -32
  35. package/src/command/SingleCommandCliHelpCommand.ts +10 -1
  36. package/src/launcher.ts +16 -58
  37. package/src/runtime/command/CommandValidator.ts +70 -6
  38. package/src/runtime/runner.ts +112 -31
  39. package/src/runtime/scanner.ts +18 -15
  40. package/src/runtime/values/argumentValueValidation.ts +93 -10
  41. package/src/runtime/values/globalCommandValuePopulation.ts +1 -1
  42. package/src/runtime/values/subCommandValuePopulation.ts +9 -8
  43. package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +34 -0
  44. package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +330 -0
  45. package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +1 -1
  46. package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +254 -17
  47. package/src/service/banner/BannerServiceProvider.ts +2 -2
  48. package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +85 -0
  49. package/src/service/chiselAsciiBannerGenerator/chisel.flf.json +3 -0
  50. package/src/service/completion/CompletionServiceProvider.ts +212 -0
  51. package/src/service/completion/DefaultCompletionService.ts +364 -0
  52. package/src/service/completion/shell/ShellHandler.ts +16 -0
  53. package/src/service/completion/shell/bash.ts +47 -0
  54. package/src/service/completion/shell/fish.ts +43 -0
  55. package/src/service/completion/shell/powershell.ts +66 -0
  56. package/src/service/completion/shell/zsh.ts +50 -0
  57. package/src/service/configuration/ConfigurationServiceProvider.ts +138 -42
  58. package/src/service/configuration/DefaultKeyValueService.ts +53 -7
  59. package/src/service/configuration/DefaultSecretService.ts +85 -0
  60. package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +41 -0
  61. package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +80 -0
  62. package/src/service/imagePrinter/DefaultImagePrinterService.ts +23 -0
  63. package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +32 -0
  64. package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +1 -1
  65. package/src/service/printer/DefaultPrinterService.ts +147 -27
  66. package/src/service/printer/PrinterServiceProvider.ts +7 -7
  67. package/src/service/printer/command/LogLevelCommand.ts +2 -1
  68. package/src/service/printer/command/NoHyperlinksCommand.ts +40 -0
  69. package/src/service/printer/terminal/Progress.ts +21 -4
  70. package/src/service/printer/terminal/Spinner.ts +32 -8
  71. package/src/service/printer/terminal/Theme.ts +1 -1
  72. package/src/service/prompter/DefaultPrompterService.ts +87 -0
  73. package/src/service/prompter/PrompterServiceProvider.ts +36 -0
  74. package/src/service/prompter/command/NoPromptCommand.ts +40 -0
  75. package/src/service/prompter/prompt/PromptContext.ts +47 -0
  76. package/src/service/prompter/prompt/promptAcknowledge.ts +28 -0
  77. package/src/service/prompter/prompt/promptMultiSelect.ts +99 -0
  78. package/src/service/prompter/prompt/promptOpenUrl.ts +97 -0
  79. package/src/service/prompter/prompt/promptSingleSelect.ts +102 -0
  80. package/src/service/prompter/prompt/promptText.ts +107 -0
  81. package/src/service/prompter/prompt/promptToggle.ts +28 -0
  82. package/src/service/shutdown/DefaultShutdownService.ts +13 -0
  83. package/src/service/shutdown/ShutdownServiceProvider.ts +28 -9
  84. package/src/service/shutdown/ShutdownState.ts +5 -0
  85. package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +1 -1
  86. package/src/service/tableGenerator/DefaultTableGeneratorService.ts +415 -0
  87. package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +43 -0
  88. package/src/service/treePrinter/DefaultTreePrinterService.ts +49 -0
  89. package/src/service/treePrinter/TreePrinterServiceProvider.ts +40 -0
  90. package/src/terminal/Ansi.ts +27 -0
  91. package/src/terminal/ImageRenderer.ts +199 -0
  92. package/src/terminal/KeyReader.ts +23 -0
  93. package/src/terminal/PngDecoder.ts +143 -0
  94. package/src/{service/printer/terminal → terminal}/Styler.ts +3 -0
  95. package/src/{service/printer/terminal → terminal}/Terminal.ts +1 -0
  96. package/src/terminal/TtyKeyReader.ts +83 -0
  97. package/src/terminal/TtyStyler.ts +78 -0
  98. package/src/{service/printer/terminal → terminal}/TtyTerminal.ts +9 -1
  99. package/src/terminal/supportsHyperlinks.ts +110 -0
  100. package/src/util/configHelper.ts +2 -2
  101. package/src/util/envVarHelper.ts +2 -2
  102. package/src/util/helpHelper.ts +139 -123
  103. package/src/util/logger.ts +16 -14
  104. package/src/util/runnerHelper.ts +41 -0
  105. package/tests/cli/BaseCLI.test.ts +50 -54
  106. package/tests/command/CompletionCommand.test.ts +68 -0
  107. package/tests/command/UsageCommand.test.ts +3 -2
  108. package/tests/command/VersionCommand.test.ts +3 -2
  109. package/tests/fixtures/Context.ts +9 -2
  110. package/tests/fixtures/util.ts +1 -1
  111. package/tests/runtime/command/CommandValidator.test.ts +103 -0
  112. package/tests/runtime/parser.test.ts +9 -7
  113. package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +3 -3
  114. package/tests/runtime/runner.test.ts +36 -0
  115. package/tests/runtime/values/argumentValueValidation.test.ts +215 -1
  116. package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +47 -0
  117. package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +754 -0
  118. package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +5 -4
  119. package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +163 -3
  120. package/tests/service/asciiBannerGenerator/__snapshots__/DefaultAsciiBannerGeneratorService.test.ts.snap +1 -1
  121. package/tests/service/banner/BannerServiceProvider.test.ts +8 -4
  122. package/tests/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.test.ts +52 -0
  123. package/tests/service/completion/CompletionServiceProvider.test.ts +404 -0
  124. package/tests/service/completion/DefaultCompletionService.test.ts +278 -0
  125. package/tests/service/completion/shell/bash.test.ts +73 -0
  126. package/tests/service/completion/shell/fish.test.ts +62 -0
  127. package/tests/service/completion/shell/powershell.test.ts +59 -0
  128. package/tests/service/completion/shell/zsh.test.ts +60 -0
  129. package/tests/service/configuration/ConfigurationServiceProvider.test.ts +24 -12
  130. package/tests/service/configuration/DefaultKeyValueService.test.ts +118 -16
  131. package/tests/service/configuration/DefaultSecretService.test.ts +148 -0
  132. package/tests/service/configuration/command/ConfigCommand.test.ts +29 -0
  133. package/tests/service/configuration/command/DumpConfigCommand.test.ts +60 -0
  134. package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +57 -0
  135. package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +217 -0
  136. package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +96 -0
  137. package/tests/service/imagePrinter/ImagePrinterServiceProvider.test.ts +17 -0
  138. package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +2 -2
  139. package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +5 -4
  140. package/tests/service/printer/DefaultPrinterService.test.ts +233 -2
  141. package/tests/service/printer/PrinterServiceProvider.test.ts +6 -5
  142. package/tests/service/printer/command/DarkModeCommand.test.ts +83 -0
  143. package/tests/service/printer/command/LogLevelCommand.test.ts +8 -6
  144. package/tests/service/printer/command/NoColorCommand.test.ts +83 -0
  145. package/tests/service/printer/command/NoHyperlinksCommand.test.ts +89 -0
  146. package/tests/service/printer/terminal/Progress.test.ts +64 -4
  147. package/tests/service/printer/terminal/Spinner.test.ts +44 -3
  148. package/tests/service/prompter/DefaultPrompterService.test.ts +615 -0
  149. package/tests/service/prompter/PrompterServiceProvider.test.ts +47 -0
  150. package/tests/service/prompter/command/NoPromptCommand.test.ts +58 -0
  151. package/tests/service/shutdown/ShutdownServiceProvider.test.ts +4 -2
  152. package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +3 -2
  153. package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +5 -4
  154. package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +363 -0
  155. package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +47 -0
  156. package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +144 -0
  157. package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +55 -0
  158. package/tests/terminal/ImageRenderer.test.ts +161 -0
  159. package/tests/terminal/PngDecoder.test.ts +223 -0
  160. package/tests/terminal/supportsHyperlinks.test.ts +149 -0
  161. package/tests/util/configHelper.test.ts +4 -4
  162. package/tests/util/logger.test.ts +23 -1
  163. package/tsconfig.json +31 -0
  164. package/src/service/printer/terminal/Ansi.ts +0 -10
  165. 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
- * Default implementation of {@link AsciiBannerGeneratorService} which has a font definition
8
- * for the FIGlet "standard" font already registered.
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
- async generate(message: string, fontName: string): Promise<string> {
32
- const name = fontName.toLowerCase();
33
- if (!this.getRegisteredFonts().includes(name)) {
34
- throw new Error(`Font name is not registered: ${name}`);
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
- const bannerText = await figlet.text(message, { font: name });
38
- const lines = bannerText.split("\n");
278
+ let allLines = subLines ? [...titleLines, ...subLines] : titleLines;
39
279
 
40
- // Remove any whitespace lines from the end
41
- while (
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" + lines.join("\n") + "\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 provide(_cliConfig: CLIConfig): Promise<ServiceInfo> {
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
+ }