@flowscripter/dynamic-cli-framework 1.2.2 → 1.3.1

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 (166) hide show
  1. package/README/core-service-providers.md +2 -2
  2. package/README/development.md +3 -6
  3. package/README/implementation-details.md +17 -17
  4. package/README/key-concepts.md +17 -17
  5. package/README.md +4 -4
  6. package/bun.lock +0 -2
  7. package/index.ts +22 -30
  8. package/package.json +19 -19
  9. package/src/api/argument/Argument.ts +1 -1
  10. package/src/api/argument/ArgumentValueTypes.ts +3 -10
  11. package/src/api/argument/ComplexOption.ts +5 -9
  12. package/src/api/command/GlobalCommand.ts +1 -4
  13. package/src/api/service/core/ArgumentPrompterService.ts +1 -3
  14. package/src/api/service/core/AsciiBannerGeneratorService.ts +1 -4
  15. package/src/api/service/core/CompletionService.ts +2 -6
  16. package/src/api/service/core/ImagePrinterService.ts +1 -2
  17. package/src/api/service/core/KeyValueService.ts +1 -2
  18. package/src/api/service/core/PrettyPrinterService.ts +1 -4
  19. package/src/api/service/core/PrinterService.ts +8 -9
  20. package/src/api/service/core/PrompterService.ts +4 -11
  21. package/src/api/service/core/ShutdownService.ts +1 -2
  22. package/src/api/service/core/SyntaxHighlighterService.ts +1 -5
  23. package/src/api/service/core/Table.ts +7 -25
  24. package/src/api/service/core/TreePrinterService.ts +1 -2
  25. package/src/cli/BaseCLI.ts +17 -47
  26. package/src/cli/DefaultRuntimeCLI.ts +1 -4
  27. package/src/command/CompletionCommand.ts +19 -45
  28. package/src/command/MultiCommandCliHelpCommand.ts +45 -92
  29. package/src/command/SingleCommandCliHelpCommand.ts +17 -28
  30. package/src/command/UsageCommand.ts +6 -12
  31. package/src/command/VersionCommand.ts +2 -6
  32. package/src/launcher.ts +4 -2
  33. package/src/runtime/DefaultContext.ts +2 -5
  34. package/src/runtime/argument/ArgumentTypeGuards.ts +1 -3
  35. package/src/runtime/command/CommandTypeGuards.ts +5 -14
  36. package/src/runtime/command/CommandValidator.ts +56 -118
  37. package/src/runtime/parser.ts +13 -17
  38. package/src/runtime/registry/CommandRegistry.ts +2 -7
  39. package/src/runtime/registry/DefaultCommandRegistry.ts +32 -84
  40. package/src/runtime/registry/DefaultServiceProviderRegistry.ts +3 -9
  41. package/src/runtime/runner.ts +103 -142
  42. package/src/runtime/scanner.ts +28 -46
  43. package/src/runtime/values/ValuePopulationResult.ts +1 -2
  44. package/src/runtime/values/argumentValueMerge.ts +16 -28
  45. package/src/runtime/values/argumentValueValidation.ts +21 -67
  46. package/src/runtime/values/globalCommandValuePopulation.ts +9 -18
  47. package/src/runtime/values/subCommandValuePopulation.ts +42 -65
  48. package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +3 -10
  49. package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +22 -59
  50. package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +5 -14
  51. package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +59 -77
  52. package/src/service/banner/BannerServiceProvider.ts +13 -35
  53. package/src/service/banner/command/NoBannerCommand.ts +2 -8
  54. package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +5 -10
  55. package/src/service/completion/CompletionServiceProvider.ts +20 -48
  56. package/src/service/completion/DefaultCompletionService.ts +17 -56
  57. package/src/service/completion/shell/ShellHandler.ts +1 -3
  58. package/src/service/completion/shell/fish.ts +1 -1
  59. package/src/service/completion/shell/powershell.ts +2 -12
  60. package/src/service/completion/shell/zsh.ts +1 -1
  61. package/src/service/configuration/ConfigurationServiceProvider.ts +40 -133
  62. package/src/service/configuration/DefaultKeyValueService.ts +6 -20
  63. package/src/service/configuration/DefaultSecretService.ts +10 -14
  64. package/src/service/configuration/command/ConfigCommand.ts +1 -4
  65. package/src/service/configuration/command/DumpConfigCommand.ts +9 -21
  66. package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +5 -14
  67. package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +5 -12
  68. package/src/service/imagePrinter/DefaultImagePrinterService.ts +1 -5
  69. package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +1 -4
  70. package/src/service/prettyPrinter/DefaultPrettyPrinterService.ts +4 -12
  71. package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +3 -10
  72. package/src/service/printer/DefaultPrinterService.ts +20 -83
  73. package/src/service/printer/PrinterServiceProvider.ts +3 -11
  74. package/src/service/printer/command/DarkModeCommand.ts +3 -10
  75. package/src/service/printer/command/LogLevelCommand.ts +7 -26
  76. package/src/service/printer/command/NoColorCommand.ts +3 -10
  77. package/src/service/printer/command/NoHyperlinksCommand.ts +3 -10
  78. package/src/service/printer/terminal/Progress.ts +99 -90
  79. package/src/service/printer/terminal/Spinner.ts +7 -26
  80. package/src/service/prompter/DefaultPrompterService.ts +2 -6
  81. package/src/service/prompter/PrompterServiceProvider.ts +3 -11
  82. package/src/service/prompter/command/NoPromptCommand.ts +3 -10
  83. package/src/service/prompter/prompt/PromptContext.ts +5 -18
  84. package/src/service/prompter/prompt/promptMultiSelect.ts +6 -21
  85. package/src/service/prompter/prompt/promptOpenUrl.ts +7 -22
  86. package/src/service/prompter/prompt/promptSingleSelect.ts +6 -23
  87. package/src/service/prompter/prompt/promptText.ts +10 -27
  88. package/src/service/prompter/prompt/promptToggle.ts +8 -8
  89. package/src/service/shutdown/ShutdownServiceProvider.ts +3 -10
  90. package/src/service/syntaxHighlighter/DefaultSyntaxHighlighterService.ts +13 -26
  91. package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +8 -21
  92. package/src/service/tableGenerator/DefaultTableGeneratorService.ts +44 -68
  93. package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +7 -16
  94. package/src/service/treePrinter/DefaultTreePrinterService.ts +2 -7
  95. package/src/service/treePrinter/TreePrinterServiceProvider.ts +4 -12
  96. package/src/terminal/ImageRenderer.ts +35 -54
  97. package/src/terminal/PngDecoder.ts +10 -19
  98. package/src/terminal/TtyStyler.ts +11 -9
  99. package/src/terminal/TtyTerminal.ts +2 -10
  100. package/src/terminal/supportsHyperlinks.ts +4 -10
  101. package/src/util/configHelper.ts +3 -10
  102. package/src/util/envVarHelper.ts +50 -88
  103. package/src/util/helpHelper.ts +123 -193
  104. package/src/util/logger.ts +12 -42
  105. package/src/util/runnerHelper.ts +20 -61
  106. package/tests/cli/BaseCLI.test.ts +23 -80
  107. package/tests/command/CompletionCommand.test.ts +1 -6
  108. package/tests/command/MultiCommandCliHelpCommand.test.ts +51 -205
  109. package/tests/command/SingleCommandCliHelpCommand.test.ts +21 -103
  110. package/tests/command/UsageCommand.test.ts +4 -10
  111. package/tests/fixtures/Command.ts +87 -68
  112. package/tests/fixtures/CommandRegistry.ts +1 -3
  113. package/tests/fixtures/Context.ts +3 -11
  114. package/tests/fixtures/ServiceProviderRegistry.ts +1 -1
  115. package/tests/fixtures/prettierPluginFoo.ts +1 -1
  116. package/tests/fixtures/util.ts +2 -8
  117. package/tests/runtime/argument/ArgumentTypeGuards.test.ts +1 -3
  118. package/tests/runtime/command/CommandValidator.test.ts +881 -604
  119. package/tests/runtime/parser.test.ts +222 -246
  120. package/tests/runtime/registry/DefaultCommandRegistry.test.ts +15 -37
  121. package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +2 -8
  122. package/tests/runtime/runner.test.ts +231 -281
  123. package/tests/runtime/scanner.test.ts +277 -475
  124. package/tests/runtime/values/argumentValueMerge.test.ts +133 -81
  125. package/tests/runtime/values/argumentValueValidation.test.ts +444 -588
  126. package/tests/runtime/values/globalCommandValuePopulation.test.ts +71 -253
  127. package/tests/runtime/values/subCommandValuePopulation.test.ts +1342 -1570
  128. package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +3 -12
  129. package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +36 -45
  130. package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +2 -8
  131. package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +40 -62
  132. package/tests/service/banner/BannerServiceProvider.test.ts +5 -18
  133. package/tests/service/banner/command/NoBannerCommand.test.ts +1 -4
  134. package/tests/service/completion/CompletionServiceProvider.test.ts +145 -214
  135. package/tests/service/completion/DefaultCompletionService.test.ts +17 -79
  136. package/tests/service/completion/shell/fish.test.ts +1 -3
  137. package/tests/service/configuration/ConfigurationServiceProvider.test.ts +26 -75
  138. package/tests/service/configuration/DefaultKeyValueService.test.ts +9 -21
  139. package/tests/service/configuration/DefaultSecretService.test.ts +7 -15
  140. package/tests/service/configuration/command/DumpConfigCommand.test.ts +4 -13
  141. package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +6 -12
  142. package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +1 -10
  143. package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +5 -70
  144. package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +4 -11
  145. package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +2 -6
  146. package/tests/service/printer/DefaultPrinterService.test.ts +57 -255
  147. package/tests/service/printer/PrinterServiceProvider.test.ts +2 -8
  148. package/tests/service/printer/command/DarkModeCommand.test.ts +4 -12
  149. package/tests/service/printer/command/LogLevelCommand.test.ts +4 -17
  150. package/tests/service/printer/command/NoColorCommand.test.ts +4 -12
  151. package/tests/service/printer/command/NoHyperlinksCommand.test.ts +7 -21
  152. package/tests/service/printer/terminal/Progress.test.ts +1 -3
  153. package/tests/service/printer/terminal/Spinner.test.ts +2 -8
  154. package/tests/service/prompter/DefaultPrompterService.test.ts +52 -69
  155. package/tests/service/prompter/PrompterServiceProvider.test.ts +2 -8
  156. package/tests/service/shutdown/ShutdownServiceProvider.test.ts +1 -3
  157. package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +13 -99
  158. package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +2 -7
  159. package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +12 -33
  160. package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +2 -2
  161. package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +4 -6
  162. package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +4 -8
  163. package/tests/terminal/ImageRenderer.test.ts +2 -11
  164. package/tests/terminal/PngDecoder.test.ts +2 -6
  165. package/tests/util/configHelper.test.ts +55 -137
  166. package/tests/util/envVarHelper.test.ts +46 -110
@@ -21,22 +21,16 @@ import type Positional from "../../api/argument/Positional.ts";
21
21
  import type ComplexOption from "../../api/argument/ComplexOption.ts";
22
22
  import type SubCommand from "../../api/command/SubCommand.ts";
23
23
  import type GlobalCommand from "../../api/command/GlobalCommand.ts";
24
- import {
25
- isGlobalCommand,
26
- isSubCommand,
27
- } from "../../runtime/command/CommandTypeGuards.ts";
24
+ import { isGlobalCommand, isSubCommand } from "../../runtime/command/CommandTypeGuards.ts";
28
25
 
29
- export default class DefaultArgumentPrompterService
30
- implements ArgumentPrompterService {
26
+ export default class DefaultArgumentPrompterService implements ArgumentPrompterService {
31
27
  readonly #prompterService: PrompterService;
32
28
 
33
29
  public constructor(prompterService: PrompterService) {
34
30
  this.#prompterService = prompterService;
35
31
  }
36
32
 
37
- async promptForMissingArguments(
38
- parseResult: ParseResult,
39
- ): Promise<ParseResult> {
33
+ async promptForMissingArguments(parseResult: ParseResult): Promise<ParseResult> {
40
34
  if (!this.#prompterService.promptEnabled) {
41
35
  return parseResult;
42
36
  }
@@ -69,9 +63,7 @@ export default class DefaultArgumentPrompterService
69
63
  return parseResult;
70
64
  }
71
65
 
72
- async #promptForGlobalCommand(
73
- parseResult: ParseResult,
74
- ): Promise<ParseResult> {
66
+ async #promptForGlobalCommand(parseResult: ParseResult): Promise<ParseResult> {
75
67
  const command = parseResult.command as GlobalCommand;
76
68
  if (!command.argument) {
77
69
  return parseResult;
@@ -97,48 +89,33 @@ export default class DefaultArgumentPrompterService
97
89
  };
98
90
  }
99
91
 
100
- async #promptForSubCommand(
101
- parseResult: ParseResult,
102
- ): Promise<ParseResult> {
92
+ async #promptForSubCommand(parseResult: ParseResult): Promise<ParseResult> {
103
93
  const command = parseResult.command as SubCommand;
104
- const existingValues = (parseResult.populatedArgumentValues ??
105
- {}) as PopulatedArgumentValues;
106
- const newValues: Record<
107
- string,
108
- PopulatedArgumentValues[string]
109
- > = { ...existingValues };
94
+ const existingValues = (parseResult.populatedArgumentValues ?? {}) as PopulatedArgumentValues;
95
+ const newValues: Record<string, PopulatedArgumentValues[string]> = {
96
+ ...existingValues,
97
+ };
110
98
  const remainingInvalid: InvalidArgument[] = [];
111
99
 
112
100
  for (const invalid of parseResult.invalidArguments) {
113
- if (
114
- invalid.reason !== InvalidArgumentReason.MISSING_VALUE ||
115
- !invalid.name
116
- ) {
101
+ if (invalid.reason !== InvalidArgumentReason.MISSING_VALUE || !invalid.name) {
117
102
  remainingInvalid.push(invalid);
118
103
  continue;
119
104
  }
120
105
 
121
- const arg = DefaultArgumentPrompterService.#findArgument(
122
- command,
123
- invalid.name,
124
- );
106
+ const arg = DefaultArgumentPrompterService.#findArgument(command, invalid.name);
125
107
  if (!arg) {
126
108
  remainingInvalid.push(invalid);
127
109
  continue;
128
110
  }
129
111
 
130
- if (
131
- "type" in arg &&
132
- (arg as ComplexOption).type === ComplexValueTypeName.COMPLEX
133
- ) {
112
+ if ("type" in arg && (arg as ComplexOption).type === ComplexValueTypeName.COMPLEX) {
134
113
  const complexValues = await this.#promptForComplexOption(
135
114
  invalid.name,
136
115
  arg as ComplexOption,
137
116
  );
138
117
  newValues[invalid.name] = complexValues;
139
- } else if (
140
- DefaultArgumentPrompterService.#isArrayArgument(arg)
141
- ) {
118
+ } else if (DefaultArgumentPrompterService.#isArrayArgument(arg)) {
142
119
  const arrayValues = await this.#promptForArrayArgument(
143
120
  invalid.name,
144
121
  arg as Option | Positional,
@@ -174,15 +151,11 @@ export default class DefaultArgumentPrompterService
174
151
  const values: Record<string, PopulatedArgumentValues[string]> = {};
175
152
 
176
153
  for (const prop of complexOption.properties) {
177
- if (
178
- "type" in prop &&
179
- (prop as ComplexOption).type === ComplexValueTypeName.COMPLEX
180
- ) {
181
- values[(prop as ComplexOption).name] = await this
182
- .#promptForComplexOption(
183
- `${name}.${(prop as ComplexOption).name}`,
184
- prop as ComplexOption,
185
- );
154
+ if ("type" in prop && (prop as ComplexOption).type === ComplexValueTypeName.COMPLEX) {
155
+ values[(prop as ComplexOption).name] = await this.#promptForComplexOption(
156
+ `${name}.${(prop as ComplexOption).name}`,
157
+ prop as ComplexOption,
158
+ );
186
159
  } else {
187
160
  const option = prop as Option;
188
161
  if (option.isOptional && option.defaultValue !== undefined) {
@@ -213,9 +186,7 @@ export default class DefaultArgumentPrompterService
213
186
  while (true) {
214
187
  const prompt = DefaultArgumentPrompterService.#argumentToPrompt(
215
188
  name,
216
- `${arg.description ?? name}${
217
- values.length > 0 ? ` [${values.length + 1}]` : ""
218
- }`,
189
+ `${arg.description ?? name}${values.length > 0 ? ` [${values.length + 1}]` : ""}`,
219
190
  arg as Argument,
220
191
  );
221
192
  const result = await this.#prompterService.prompt(prompt);
@@ -241,11 +212,7 @@ export default class DefaultArgumentPrompterService
241
212
  return values;
242
213
  }
243
214
 
244
- static #argumentToPrompt(
245
- name: string,
246
- description: string,
247
- arg: Argument,
248
- ): Prompt {
215
+ static #argumentToPrompt(name: string, description: string, arg: Argument): Prompt {
249
216
  if (arg.type === ArgumentValueTypeName.BOOLEAN) {
250
217
  return {
251
218
  name,
@@ -269,9 +236,7 @@ export default class DefaultArgumentPrompterService
269
236
  }
270
237
 
271
238
  const validationOption: PromptOption = {
272
- displayValue: arg.type === ArgumentValueTypeName.SECRET
273
- ? "__SECRET__"
274
- : name,
239
+ displayValue: arg.type === ArgumentValueTypeName.SECRET ? "__SECRET__" : name,
275
240
  returnedValue: "",
276
241
  min: arg.minValueInclusive,
277
242
  max: arg.maxValueInclusive,
@@ -316,9 +281,7 @@ export default class DefaultArgumentPrompterService
316
281
  return undefined;
317
282
  }
318
283
 
319
- static #isArrayArgument(
320
- arg: Option | Positional | ComplexOption,
321
- ): boolean {
284
+ static #isArrayArgument(arg: Option | Positional | ComplexOption): boolean {
322
285
  if ("isArray" in arg && (arg as Option).isArray) {
323
286
  return true;
324
287
  }
@@ -1,20 +1,14 @@
1
- import type {
2
- ServiceInfo,
3
- ServiceProvider,
4
- } from "../../api/service/ServiceProvider.ts";
1
+ import type { ServiceInfo, ServiceProvider } from "../../api/service/ServiceProvider.ts";
5
2
  import type Context from "../../api/Context.ts";
6
3
  import type AsciiBannerGeneratorService from "../../api/service/core/AsciiBannerGeneratorService.ts";
7
- import {
8
- ASCII_BANNER_GENERATOR_SERVICE_ID,
9
- } from "../../api/service/core/AsciiBannerGeneratorService.ts";
4
+ import { ASCII_BANNER_GENERATOR_SERVICE_ID } from "../../api/service/core/AsciiBannerGeneratorService.ts";
10
5
  import DefaultAsciiBannerGeneratorService from "./DefaultAsciiBannerGeneratorService.ts";
11
6
  import type CLIConfig from "../../api/CLIConfig.ts";
12
7
 
13
8
  /**
14
9
  * Provides an {@link AsciiBannerGeneratorService}.
15
10
  */
16
- export default class AsciiBannerGeneratorServiceProvider
17
- implements ServiceProvider {
11
+ export default class AsciiBannerGeneratorServiceProvider implements ServiceProvider {
18
12
  readonly serviceId: string = ASCII_BANNER_GENERATOR_SERVICE_ID;
19
13
  readonly servicePriority: number;
20
14
  readonly #asciiBannerGeneratorService: AsciiBannerGeneratorService;
@@ -24,12 +18,9 @@ export default class AsciiBannerGeneratorServiceProvider
24
18
  *
25
19
  * @param servicePriority the priority of the service.
26
20
  */
27
- public constructor(
28
- servicePriority: number,
29
- ) {
21
+ public constructor(servicePriority: number) {
30
22
  this.servicePriority = servicePriority;
31
- this.#asciiBannerGeneratorService =
32
- new DefaultAsciiBannerGeneratorService();
23
+ this.#asciiBannerGeneratorService = new DefaultAsciiBannerGeneratorService();
33
24
  }
34
25
 
35
26
  public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
@@ -16,7 +16,9 @@ function hslToRgb(h: number, s: number, l: number): [number, number, number] {
16
16
  const c = (1 - Math.abs(2 * l - 1)) * s;
17
17
  const x = c * (1 - Math.abs(((h * 6) % 2) - 1));
18
18
  const m = l - c / 2;
19
- let r = 0, g = 0, b = 0;
19
+ let r = 0,
20
+ g = 0,
21
+ b = 0;
20
22
  if (h < 1 / 6) {
21
23
  r = c;
22
24
  g = x;
@@ -42,16 +44,12 @@ function hslToRgb(h: number, s: number, l: number): [number, number, number] {
42
44
  g = 0;
43
45
  b = x;
44
46
  }
45
- return [
46
- Math.round((r + m) * 255),
47
- Math.round((g + m) * 255),
48
- Math.round((b + m) * 255),
49
- ];
47
+ return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];
50
48
  }
51
49
 
52
50
  function parseHex(hex: string): [number, number, number] {
53
51
  const v = parseInt(hex.slice(1), 16);
54
- return [(v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
52
+ return [(v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff];
55
53
  }
56
54
 
57
55
  function interpolateColors(
@@ -84,13 +82,11 @@ function rainbowColor(
84
82
  x: number,
85
83
  y: number,
86
84
  ): [number, number, number] {
87
- const h = ((freq * (x / spread) + seed + y * freq / spread) % 1.0 + 1.0) %
88
- 1.0;
85
+ const h = (((freq * (x / spread) + seed + (y * freq) / spread) % 1.0) + 1.0) % 1.0;
89
86
  return hslToRgb(h, 1.0, 0.5);
90
87
  }
91
88
 
92
- export default class DefaultAsciiBannerGeneratorService
93
- implements AsciiBannerGeneratorService {
89
+ export default class DefaultAsciiBannerGeneratorService implements AsciiBannerGeneratorService {
94
90
  #registeredFontNames: Array<string> = [];
95
91
 
96
92
  constructor() {
@@ -110,47 +106,39 @@ export default class DefaultAsciiBannerGeneratorService
110
106
  figlet.parseFont(fontName, fontDefinition);
111
107
  }
112
108
 
113
- protected applyForegroundEffect(
114
- lines: string[],
115
- effect: ColorEffect,
116
- ): string[] {
109
+ protected applyForegroundEffect(lines: string[], effect: ColorEffect): string[] {
117
110
  if (effect.type === "fixed") {
118
111
  const [r, g, b] = parseHex(effect.color);
119
112
  const code = foregroundColorStart(r, g, b);
120
113
  return lines.map((line) =>
121
- line.split("").map((ch) =>
122
- ch === " " ? ch : code + ch + FOREGROUND_COLOR_END
123
- ).join(
124
- "",
125
- )
114
+ line
115
+ .split("")
116
+ .map((ch) => (ch === " " ? ch : code + ch + FOREGROUND_COLOR_END))
117
+ .join(""),
126
118
  );
127
119
  }
128
120
  if (effect.type === "gradient") {
129
121
  const colorStops = effect.colors.map(parseHex);
130
122
  return lines.map((line, yi) => {
131
123
  if (effect.direction === "vertical") {
132
- const [r, g, b] = interpolateColors(
133
- colorStops,
134
- yi,
135
- Math.max(lines.length, 1),
136
- );
124
+ const [r, g, b] = interpolateColors(colorStops, yi, Math.max(lines.length, 1));
137
125
  const code = foregroundColorStart(r, g, b);
138
- return line.split("").map((ch) =>
139
- ch === " " ? ch : code + ch + FOREGROUND_COLOR_END
140
- ).join("");
126
+ return line
127
+ .split("")
128
+ .map((ch) => (ch === " " ? ch : code + ch + FOREGROUND_COLOR_END))
129
+ .join("");
141
130
  }
142
131
  const nonSpaceCount = line.split("").filter((c) => c !== " ").length;
143
132
  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("");
133
+ return line
134
+ .split("")
135
+ .map((ch) => {
136
+ if (ch === " ") return ch;
137
+ const [r, g, b] = interpolateColors(colorStops, charIdx, Math.max(nonSpaceCount, 1));
138
+ charIdx++;
139
+ return foregroundColorStart(r, g, b) + ch + FOREGROUND_COLOR_END;
140
+ })
141
+ .join("");
154
142
  });
155
143
  }
156
144
  const freq = effect.frequency ?? 0.3;
@@ -160,24 +148,25 @@ export default class DefaultAsciiBannerGeneratorService
160
148
  if (effect.direction === "vertical") {
161
149
  const [r, g, b] = rainbowColor(freq, spread, seed, 0, yi);
162
150
  const code = foregroundColorStart(r, g, b);
163
- return line.split("").map((ch) =>
164
- ch === " " ? ch : code + ch + FOREGROUND_COLOR_END
165
- ).join("");
151
+ return line
152
+ .split("")
153
+ .map((ch) => (ch === " " ? ch : code + ch + FOREGROUND_COLOR_END))
154
+ .join("");
166
155
  }
167
156
  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("");
157
+ return line
158
+ .split("")
159
+ .map((ch) => {
160
+ if (ch === " ") return ch;
161
+ const [r, g, b] = rainbowColor(freq, spread, seed, charIdx, yi);
162
+ charIdx++;
163
+ return foregroundColorStart(r, g, b) + ch + FOREGROUND_COLOR_END;
164
+ })
165
+ .join("");
174
166
  });
175
167
  }
176
168
 
177
- protected applyBackgroundEffect(
178
- lines: string[],
179
- effect: ColorEffect,
180
- ): string[] {
169
+ protected applyBackgroundEffect(lines: string[], effect: ColorEffect): string[] {
181
170
  if (effect.type === "fixed") {
182
171
  const [r, g, b] = parseHex(effect.color);
183
172
  const code = backgroundColorStart(r, g, b);
@@ -187,18 +176,17 @@ export default class DefaultAsciiBannerGeneratorService
187
176
  const colorStops = effect.colors.map(parseHex);
188
177
  return lines.map((line, yi) => {
189
178
  if (effect.direction === "vertical") {
190
- const [r, g, b] = interpolateColors(
191
- colorStops,
192
- yi,
193
- Math.max(lines.length, 1),
194
- );
179
+ const [r, g, b] = interpolateColors(colorStops, yi, Math.max(lines.length, 1));
195
180
  return backgroundColorStart(r, g, b) + line + BACKGROUND_COLOR_END;
196
181
  }
197
182
  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("");
183
+ return line
184
+ .split("")
185
+ .map((ch, xi) => {
186
+ const [r, g, b] = interpolateColors(colorStops, xi, totalChars);
187
+ return backgroundColorStart(r, g, b) + ch + BACKGROUND_COLOR_END;
188
+ })
189
+ .join("");
202
190
  });
203
191
  }
204
192
  const freq = effect.frequency ?? 0.3;
@@ -209,17 +197,17 @@ export default class DefaultAsciiBannerGeneratorService
209
197
  const [r, g, b] = rainbowColor(freq, spread, seed, 0, yi);
210
198
  return backgroundColorStart(r, g, b) + line + BACKGROUND_COLOR_END;
211
199
  }
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("");
200
+ return line
201
+ .split("")
202
+ .map((ch, xi) => {
203
+ const [r, g, b] = rainbowColor(freq, spread, seed, xi, yi);
204
+ return backgroundColorStart(r, g, b) + ch + BACKGROUND_COLOR_END;
205
+ })
206
+ .join("");
216
207
  });
217
208
  }
218
209
 
219
- async generate(
220
- message: string,
221
- options?: BannerGenerateOptions,
222
- ): Promise<string> {
210
+ async generate(message: string, options?: BannerGenerateOptions): Promise<string> {
223
211
  const fontName = (options?.fontName ?? "standard").toLowerCase();
224
212
  if (!this.getRegisteredFonts().includes(fontName)) {
225
213
  throw new Error(`Font name is not registered: ${fontName}`);
@@ -239,7 +227,7 @@ export default class DefaultAsciiBannerGeneratorService
239
227
  subMessageLine = options.subMessage
240
228
  .toUpperCase()
241
229
  .split("")
242
- .map((c) => c === " " ? " " : c + " ")
230
+ .map((c) => (c === " " ? " " : c + " "))
243
231
  .join("")
244
232
  .trimEnd();
245
233
 
@@ -258,20 +246,14 @@ export default class DefaultAsciiBannerGeneratorService
258
246
  const colorEffects = options?.colorEffects;
259
247
 
260
248
  if (colorEffects?.messageForeground) {
261
- titleLines = this.applyForegroundEffect(
262
- titleLines,
263
- colorEffects.messageForeground,
264
- );
249
+ titleLines = this.applyForegroundEffect(titleLines, colorEffects.messageForeground);
265
250
  }
266
251
 
267
252
  let subLines: string[] | undefined;
268
253
  if (subMessageLine !== undefined) {
269
254
  subLines = [subMessageLine];
270
255
  if (colorEffects?.subMessageForeground) {
271
- subLines = this.applyForegroundEffect(
272
- subLines,
273
- colorEffects.subMessageForeground,
274
- );
256
+ subLines = this.applyForegroundEffect(subLines, colorEffects.subMessageForeground);
275
257
  }
276
258
  }
277
259
 
@@ -1,19 +1,13 @@
1
1
  import type Context from "../../api/Context.ts";
2
- import type {
3
- ServiceInfo,
4
- ServiceProvider,
5
- } from "../../api/service/ServiceProvider.ts";
2
+ import type { ServiceInfo, ServiceProvider } from "../../api/service/ServiceProvider.ts";
6
3
  import NoBannerCommand from "./command/NoBannerCommand.ts";
7
4
  import type PrinterService from "../../api/service/core/PrinterService.ts";
8
5
  import { PRINTER_SERVICE_ID } from "../../api/service/core/PrinterService.ts";
9
6
  import type ConfigurationServiceProvider from "../configuration/ConfigurationServiceProvider.ts";
10
7
  import type AsciiBannerGeneratorService from "../../api/service/core/AsciiBannerGeneratorService.ts";
11
- import {
12
- ASCII_BANNER_GENERATOR_SERVICE_ID,
13
- } from "../../api/service/core/AsciiBannerGeneratorService.ts";
8
+ import { ASCII_BANNER_GENERATOR_SERVICE_ID } from "../../api/service/core/AsciiBannerGeneratorService.ts";
14
9
  import type CLIConfig from "../../api/CLIConfig.ts";
15
- export const BANNER_SERVICE_ID =
16
- "@flowscripter/dynamic-cli-framework/banner-service";
10
+ export const BANNER_SERVICE_ID = "@flowscripter/dynamic-cli-framework/banner-service";
17
11
 
18
12
  /**
19
13
  * Provides ascii banner functionality.
@@ -21,9 +15,7 @@ export const BANNER_SERVICE_ID =
21
15
  export default class BannerServiceProvider implements ServiceProvider {
22
16
  readonly serviceId: string = BANNER_SERVICE_ID;
23
17
  readonly servicePriority: number;
24
- readonly #configurationServiceProvider:
25
- | ConfigurationServiceProvider
26
- | undefined;
18
+ readonly #configurationServiceProvider: ConfigurationServiceProvider | undefined;
27
19
 
28
20
  /**
29
21
  * Whether or not to print the banner, defaults to true.
@@ -48,9 +40,7 @@ export default class BannerServiceProvider implements ServiceProvider {
48
40
 
49
41
  public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
50
42
  return Promise.resolve({
51
- commands: [
52
- new NoBannerCommand(this, this.servicePriority),
53
- ],
43
+ commands: [new NoBannerCommand(this, this.servicePriority)],
54
44
  });
55
45
  }
56
46
 
@@ -59,41 +49,29 @@ export default class BannerServiceProvider implements ServiceProvider {
59
49
  return Promise.resolve();
60
50
  }
61
51
 
62
- const printerService = context.getServiceById(
63
- PRINTER_SERVICE_ID,
64
- ) as PrinterService;
52
+ const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
65
53
 
66
54
  const asciiBannerGeneratorService = context.getServiceById(
67
55
  ASCII_BANNER_GENERATOR_SERVICE_ID,
68
56
  ) as AsciiBannerGeneratorService;
69
57
 
70
58
  const { cliConfig } = context;
71
- const bannerText = await asciiBannerGeneratorService.generate(
72
- cliConfig.name.toUpperCase(),
73
- { fontName: this.fontName, subMessage: cliConfig.subMessage },
74
- );
59
+ const bannerText = await asciiBannerGeneratorService.generate(cliConfig.name.toUpperCase(), {
60
+ fontName: this.fontName,
61
+ subMessage: cliConfig.subMessage,
62
+ });
75
63
 
76
64
  await printerService.info(printerService.blue(bannerText));
77
65
  if (cliConfig.description !== undefined) {
78
- await printerService.info(
79
- ` ${printerService.primary(cliConfig.description)}\n`,
80
- );
66
+ await printerService.info(` ${printerService.primary(cliConfig.description)}\n`);
81
67
  }
82
68
  if (cliConfig.version.length > 0) {
83
- await printerService.info(
84
- ` ${printerService.secondary("version: " + cliConfig.version)}\n`,
85
- );
69
+ await printerService.info(` ${printerService.secondary("version: " + cliConfig.version)}\n`);
86
70
  }
87
71
  if (this.#configurationServiceProvider) {
88
72
  const configLocation = this.#configurationServiceProvider.configLocation;
89
73
  if (configLocation && configLocation.length > 0) {
90
- await printerService.info(
91
- ` ${
92
- printerService.secondary(
93
- "config: " + configLocation,
94
- )
95
- }\n`,
96
- );
74
+ await printerService.info(` ${printerService.secondary("config: " + configLocation)}\n`);
97
75
  }
98
76
  }
99
77
  await printerService.info("\n");
@@ -23,18 +23,12 @@ export default class NoBannerCommand implements GlobalModifierCommand {
23
23
 
24
24
  readonly #bannerServiceProvider: BannerServiceProvider;
25
25
 
26
- public constructor(
27
- bannerServiceProvider: BannerServiceProvider,
28
- executePriority: number,
29
- ) {
26
+ public constructor(bannerServiceProvider: BannerServiceProvider, executePriority: number) {
30
27
  this.#bannerServiceProvider = bannerServiceProvider;
31
28
  this.executePriority = executePriority;
32
29
  }
33
30
 
34
- public execute(
35
- _context: Context,
36
- argumentValue: ArgumentSingleValueType,
37
- ): Promise<void> {
31
+ public execute(_context: Context, argumentValue: ArgumentSingleValueType): Promise<void> {
38
32
  this.#bannerServiceProvider.printBanner = !(argumentValue as boolean);
39
33
 
40
34
  return Promise.resolve();
@@ -19,7 +19,8 @@ export interface ChiselBannerGenerateOptions extends BannerGenerateOptions {
19
19
 
20
20
  export default class ChiselFontAsciiBannerGeneratorService
21
21
  extends DefaultAsciiBannerGeneratorService
22
- implements AsciiBannerGeneratorService {
22
+ implements AsciiBannerGeneratorService
23
+ {
23
24
  private _ready = false;
24
25
 
25
26
  constructor() {
@@ -40,10 +41,7 @@ export default class ChiselFontAsciiBannerGeneratorService
40
41
  return ["chisel"];
41
42
  }
42
43
 
43
- override async generate(
44
- message: string,
45
- options?: ChiselBannerGenerateOptions,
46
- ): Promise<string> {
44
+ override async generate(message: string, options?: ChiselBannerGenerateOptions): Promise<string> {
47
45
  const chiselOptions: BannerGenerateOptions = {
48
46
  ...options,
49
47
  fontName: "chisel",
@@ -73,11 +71,8 @@ export default class ChiselFontAsciiBannerGeneratorService
73
71
  colorMap["100"] = colors.shadowBackground;
74
72
  }
75
73
 
76
- result = result.replace(
77
- // deno-lint-ignore no-control-regex
78
- /\x1b\[(\d+)m/g,
79
- (_, n) => `\x1b[${colorMap[n] ?? n}m`,
80
- );
74
+ const ansiCodeRe = /\x1b\[(\d+)m/g; // oxlint-disable-line no-control-regex
75
+ result = result.replace(ansiCodeRe, (_, n) => `\x1b[${colorMap[n] ?? n}m`);
81
76
  }
82
77
 
83
78
  return result;