@flowscripter/dynamic-cli-framework 1.1.6 → 1.2.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 (160) 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 +22 -18
  9. package/index.ts +97 -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 +24 -0
  15. package/src/api/service/ServiceProvider.ts +3 -3
  16. package/src/api/service/core/ArgumentPrompterService.ts +10 -0
  17. package/src/api/service/core/AsciiBannerGeneratorService.ts +44 -7
  18. package/src/api/service/core/CompletionService.ts +36 -0
  19. package/src/api/service/core/DataDumpGeneratorService.ts +27 -0
  20. package/src/api/service/core/ImagePrinterService.ts +26 -0
  21. package/src/api/service/core/KeyValueService.ts +22 -5
  22. package/src/api/service/core/PrinterService.ts +127 -1
  23. package/src/api/service/core/PrompterService.ts +49 -0
  24. package/src/api/service/core/SecretService.ts +27 -0
  25. package/src/api/service/core/ShutdownService.ts +17 -1
  26. package/src/api/service/core/Table.ts +85 -0
  27. package/src/api/service/core/TableGeneratorService.ts +38 -0
  28. package/src/api/service/core/TreePrinterService.ts +11 -0
  29. package/src/cli/BaseCLI.ts +116 -44
  30. package/src/cli/DefaultRuntimeCLI.ts +10 -18
  31. package/src/command/CompletionCommand.ts +179 -0
  32. package/src/command/MultiCommandCliHelpCommand.ts +18 -2
  33. package/src/command/SingleCommandCliHelpCommand.ts +10 -1
  34. package/src/launcher.ts +16 -58
  35. package/src/runtime/command/CommandValidator.ts +3 -3
  36. package/src/runtime/runner.ts +102 -30
  37. package/src/runtime/scanner.ts +18 -15
  38. package/src/runtime/values/argumentValueValidation.ts +49 -5
  39. package/src/runtime/values/globalCommandValuePopulation.ts +1 -1
  40. package/src/runtime/values/subCommandValuePopulation.ts +9 -8
  41. package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +34 -0
  42. package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +330 -0
  43. package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +1 -1
  44. package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +254 -17
  45. package/src/service/banner/BannerServiceProvider.ts +2 -2
  46. package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +85 -0
  47. package/src/service/chiselAsciiBannerGenerator/chisel.flf.json +3 -0
  48. package/src/service/completion/CompletionServiceProvider.ts +212 -0
  49. package/src/service/completion/DefaultCompletionService.ts +364 -0
  50. package/src/service/completion/shell/ShellHandler.ts +16 -0
  51. package/src/service/completion/shell/bash.ts +47 -0
  52. package/src/service/completion/shell/fish.ts +43 -0
  53. package/src/service/completion/shell/powershell.ts +66 -0
  54. package/src/service/completion/shell/zsh.ts +50 -0
  55. package/src/service/configuration/ConfigurationServiceProvider.ts +138 -42
  56. package/src/service/configuration/DefaultKeyValueService.ts +53 -7
  57. package/src/service/configuration/DefaultSecretService.ts +85 -0
  58. package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +41 -0
  59. package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +80 -0
  60. package/src/service/imagePrinter/DefaultImagePrinterService.ts +23 -0
  61. package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +32 -0
  62. package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +1 -1
  63. package/src/service/printer/DefaultPrinterService.ts +147 -27
  64. package/src/service/printer/PrinterServiceProvider.ts +7 -7
  65. package/src/service/printer/command/NoHyperlinksCommand.ts +40 -0
  66. package/src/service/printer/terminal/Progress.ts +21 -4
  67. package/src/service/printer/terminal/Spinner.ts +32 -8
  68. package/src/service/printer/terminal/Theme.ts +1 -1
  69. package/src/service/prompter/DefaultPrompterService.ts +87 -0
  70. package/src/service/prompter/PrompterServiceProvider.ts +36 -0
  71. package/src/service/prompter/command/NoPromptCommand.ts +40 -0
  72. package/src/service/prompter/prompt/PromptContext.ts +47 -0
  73. package/src/service/prompter/prompt/promptAcknowledge.ts +28 -0
  74. package/src/service/prompter/prompt/promptMultiSelect.ts +99 -0
  75. package/src/service/prompter/prompt/promptOpenUrl.ts +97 -0
  76. package/src/service/prompter/prompt/promptSingleSelect.ts +102 -0
  77. package/src/service/prompter/prompt/promptText.ts +107 -0
  78. package/src/service/prompter/prompt/promptToggle.ts +28 -0
  79. package/src/service/shutdown/DefaultShutdownService.ts +13 -0
  80. package/src/service/shutdown/ShutdownServiceProvider.ts +28 -9
  81. package/src/service/shutdown/ShutdownState.ts +5 -0
  82. package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +1 -1
  83. package/src/service/tableGenerator/DefaultTableGeneratorService.ts +415 -0
  84. package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +43 -0
  85. package/src/service/treePrinter/DefaultTreePrinterService.ts +49 -0
  86. package/src/service/treePrinter/TreePrinterServiceProvider.ts +40 -0
  87. package/src/terminal/Ansi.ts +27 -0
  88. package/src/terminal/ImageRenderer.ts +199 -0
  89. package/src/terminal/KeyReader.ts +23 -0
  90. package/src/terminal/PngDecoder.ts +143 -0
  91. package/src/{service/printer/terminal → terminal}/Styler.ts +3 -0
  92. package/src/{service/printer/terminal → terminal}/Terminal.ts +1 -0
  93. package/src/terminal/TtyKeyReader.ts +83 -0
  94. package/src/terminal/TtyStyler.ts +78 -0
  95. package/src/{service/printer/terminal → terminal}/TtyTerminal.ts +9 -1
  96. package/src/terminal/supportsHyperlinks.ts +110 -0
  97. package/src/util/configHelper.ts +2 -2
  98. package/src/util/envVarHelper.ts +2 -2
  99. package/src/util/helpHelper.ts +66 -122
  100. package/src/util/logger.ts +16 -14
  101. package/src/util/runnerHelper.ts +1 -1
  102. package/tests/cli/BaseCLI.test.ts +50 -54
  103. package/tests/command/CompletionCommand.test.ts +68 -0
  104. package/tests/command/UsageCommand.test.ts +3 -2
  105. package/tests/command/VersionCommand.test.ts +3 -2
  106. package/tests/fixtures/Context.ts +9 -2
  107. package/tests/fixtures/util.ts +1 -1
  108. package/tests/runtime/parser.test.ts +9 -7
  109. package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +3 -3
  110. package/tests/runtime/values/argumentValueValidation.test.ts +193 -0
  111. package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +47 -0
  112. package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +754 -0
  113. package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +5 -4
  114. package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +163 -3
  115. package/tests/service/asciiBannerGenerator/__snapshots__/DefaultAsciiBannerGeneratorService.test.ts.snap +1 -1
  116. package/tests/service/banner/BannerServiceProvider.test.ts +8 -4
  117. package/tests/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.test.ts +52 -0
  118. package/tests/service/completion/CompletionServiceProvider.test.ts +404 -0
  119. package/tests/service/completion/DefaultCompletionService.test.ts +278 -0
  120. package/tests/service/completion/shell/bash.test.ts +73 -0
  121. package/tests/service/completion/shell/fish.test.ts +62 -0
  122. package/tests/service/completion/shell/powershell.test.ts +59 -0
  123. package/tests/service/completion/shell/zsh.test.ts +60 -0
  124. package/tests/service/configuration/ConfigurationServiceProvider.test.ts +24 -12
  125. package/tests/service/configuration/DefaultKeyValueService.test.ts +118 -16
  126. package/tests/service/configuration/DefaultSecretService.test.ts +148 -0
  127. package/tests/service/configuration/command/ConfigCommand.test.ts +29 -0
  128. package/tests/service/configuration/command/DumpConfigCommand.test.ts +60 -0
  129. package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +57 -0
  130. package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +217 -0
  131. package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +96 -0
  132. package/tests/service/imagePrinter/ImagePrinterServiceProvider.test.ts +17 -0
  133. package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +2 -2
  134. package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +5 -4
  135. package/tests/service/printer/DefaultPrinterService.test.ts +233 -2
  136. package/tests/service/printer/PrinterServiceProvider.test.ts +6 -5
  137. package/tests/service/printer/command/DarkModeCommand.test.ts +83 -0
  138. package/tests/service/printer/command/LogLevelCommand.test.ts +7 -5
  139. package/tests/service/printer/command/NoColorCommand.test.ts +83 -0
  140. package/tests/service/printer/command/NoHyperlinksCommand.test.ts +89 -0
  141. package/tests/service/printer/terminal/Progress.test.ts +64 -4
  142. package/tests/service/printer/terminal/Spinner.test.ts +44 -3
  143. package/tests/service/prompter/DefaultPrompterService.test.ts +615 -0
  144. package/tests/service/prompter/PrompterServiceProvider.test.ts +47 -0
  145. package/tests/service/prompter/command/NoPromptCommand.test.ts +58 -0
  146. package/tests/service/shutdown/ShutdownServiceProvider.test.ts +4 -2
  147. package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +3 -2
  148. package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +5 -4
  149. package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +363 -0
  150. package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +47 -0
  151. package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +144 -0
  152. package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +55 -0
  153. package/tests/terminal/ImageRenderer.test.ts +161 -0
  154. package/tests/terminal/PngDecoder.test.ts +223 -0
  155. package/tests/terminal/supportsHyperlinks.test.ts +149 -0
  156. package/tests/util/configHelper.test.ts +4 -4
  157. package/tests/util/logger.test.ts +23 -1
  158. package/tsconfig.json +31 -0
  159. package/src/service/printer/terminal/Ansi.ts +0 -10
  160. package/src/service/printer/terminal/TtyStyler.ts +0 -39
@@ -4,7 +4,7 @@ import { getCLIConfig } from "../../fixtures/CLIConfig.ts";
4
4
  import AsciiBannerGeneratorServiceProvider from "../../../src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts";
5
5
 
6
6
  describe("AsciiBannerGeneratorServiceProvider tests", () => {
7
- test("AsciiBannerGeneratorServiceProvider provide and initService works", async () => {
7
+ test("AsciiBannerGeneratorServiceProvider getServiceInfo and initService works", async () => {
8
8
  const asciiBannerGeneratorServiceProvider =
9
9
  new AsciiBannerGeneratorServiceProvider(
10
10
  100,
@@ -12,9 +12,10 @@ describe("AsciiBannerGeneratorServiceProvider tests", () => {
12
12
  const cliConfig = getCLIConfig();
13
13
  const context = new DefaultContext(cliConfig);
14
14
 
15
- const serviceInfo = await asciiBannerGeneratorServiceProvider.provide(
16
- cliConfig,
17
- );
15
+ const serviceInfo = await asciiBannerGeneratorServiceProvider
16
+ .getServiceInfo(
17
+ cliConfig,
18
+ );
18
19
  expect(serviceInfo.commands.length).toEqual(0);
19
20
 
20
21
  await asciiBannerGeneratorServiceProvider.initService(context);
@@ -38,7 +38,8 @@ describe("DefaultAsciiBannerGeneratorService tests", () => {
38
38
  const asciiBannerGeneratorService =
39
39
  new DefaultAsciiBannerGeneratorService();
40
40
 
41
- expect(asciiBannerGeneratorService.generate("foo", "small")).rejects
41
+ expect(asciiBannerGeneratorService.generate("foo", { fontName: "small" }))
42
+ .rejects
42
43
  .toThrow();
43
44
  });
44
45
 
@@ -50,7 +51,7 @@ describe("DefaultAsciiBannerGeneratorService tests", () => {
50
51
 
51
52
  const generated = await asciiBannerGeneratorService.generate(
52
53
  "foo",
53
- "standard",
54
+ { fontName: "standard" },
54
55
  );
55
56
  expect(generated).toMatchSnapshot();
56
57
  });
@@ -63,8 +64,167 @@ describe("DefaultAsciiBannerGeneratorService tests", () => {
63
64
 
64
65
  const generated = await asciiBannerGeneratorService.generate(
65
66
  "foo",
66
- "small",
67
+ { fontName: "small" },
67
68
  );
68
69
  expect(generated).toMatchSnapshot();
69
70
  });
71
+
72
+ test("subMessage is uppercased and double-spaced", async () => {
73
+ const service = new DefaultAsciiBannerGeneratorService();
74
+ const result = await service.generate("foo", {
75
+ fontName: "standard",
76
+ subMessage: "hello",
77
+ });
78
+ expect(result).toContain("H E L L O");
79
+ });
80
+
81
+ test("fixed foreground color effect adds ANSI codes to title chars", async () => {
82
+ const service = new DefaultAsciiBannerGeneratorService();
83
+ const result = await service.generate("foo", {
84
+ fontName: "standard",
85
+ colorEffects: {
86
+ messageForeground: { type: "fixed", color: "#ff0000" },
87
+ },
88
+ });
89
+ expect(result).toContain("\x1b[38;2;");
90
+ expect(result).toContain("\x1b[39m");
91
+ });
92
+
93
+ test("background color effect adds background ANSI codes", async () => {
94
+ const service = new DefaultAsciiBannerGeneratorService();
95
+ const result = await service.generate("foo", {
96
+ fontName: "standard",
97
+ colorEffects: {
98
+ background: { type: "fixed", color: "#0000ff" },
99
+ },
100
+ });
101
+ expect(result).toContain("\x1b[48;2;");
102
+ expect(result).toContain("\x1b[49m");
103
+ });
104
+
105
+ test("no ANSI codes when no color effects specified", async () => {
106
+ const service = new DefaultAsciiBannerGeneratorService();
107
+ const result = await service.generate("foo", { fontName: "standard" });
108
+ expect(result).not.toContain("\x1b[");
109
+ });
110
+
111
+ test("subMessage narrower than banner is padded to center", async () => {
112
+ const service = new DefaultAsciiBannerGeneratorService();
113
+ const result = await service.generate("foo", {
114
+ fontName: "standard",
115
+ subMessage: "hi",
116
+ });
117
+ const lines = result.trim().split("\n");
118
+ const subLine = lines[lines.length - 1]!;
119
+ expect(subLine.startsWith(" ")).toBe(true);
120
+ });
121
+
122
+ test("subMessage wider than banner pads title lines", async () => {
123
+ const service = new DefaultAsciiBannerGeneratorService();
124
+ const withoutSub = await service.generate("i", { fontName: "standard" });
125
+ const withSub = await service.generate("i", {
126
+ fontName: "standard",
127
+ subMessage: "x".repeat(40),
128
+ });
129
+ const withoutLines = withoutSub.trim().split("\n");
130
+ const withLines = withSub.trim().split("\n").slice(0, withoutLines.length);
131
+ const maxWith = Math.max(...withLines.map((l) => l.length));
132
+ const maxWithout = Math.max(...withoutLines.map((l) => l.length));
133
+ expect(maxWith).toBeGreaterThan(maxWithout);
134
+ });
135
+
136
+ test("gradient vertical applies different color per line", async () => {
137
+ const service = new DefaultAsciiBannerGeneratorService();
138
+ const result = await service.generate("foo", {
139
+ fontName: "standard",
140
+ colorEffects: {
141
+ messageForeground: {
142
+ type: "gradient",
143
+ colors: ["#ff0000", "#0000ff"],
144
+ direction: "vertical",
145
+ },
146
+ },
147
+ });
148
+ const lines = result.trim().split("\n").filter((l) =>
149
+ l.includes("\x1b[38;2;")
150
+ );
151
+ const firstCodes = lines.map((l) =>
152
+ // deno-lint-ignore no-control-regex
153
+ l.match(/\x1b\[38;2;(\d+;\d+;\d+)m/)?.[1]
154
+ );
155
+ const unique = new Set(firstCodes.filter(Boolean));
156
+ expect(unique.size).toBeGreaterThan(1);
157
+ });
158
+
159
+ test("gradient horizontal applies different color per char within a line", async () => {
160
+ const service = new DefaultAsciiBannerGeneratorService();
161
+ const result = await service.generate("foo", {
162
+ fontName: "standard",
163
+ colorEffects: {
164
+ messageForeground: {
165
+ type: "gradient",
166
+ colors: ["#ff0000", "#0000ff"],
167
+ direction: "horizontal",
168
+ },
169
+ },
170
+ });
171
+ const lines = result.trim().split("\n").filter((l) =>
172
+ l.includes("\x1b[38;2;")
173
+ );
174
+ const firstLine = lines[0]!;
175
+ // deno-lint-ignore no-control-regex
176
+ const codes = [...firstLine.matchAll(/\x1b\[38;2;(\d+;\d+;\d+)m/g)].map((
177
+ m,
178
+ ) => m[1]);
179
+ const unique = new Set(codes);
180
+ expect(unique.size).toBeGreaterThan(1);
181
+ });
182
+
183
+ test("rainbow horizontal applies ANSI codes varying per char", async () => {
184
+ const service = new DefaultAsciiBannerGeneratorService();
185
+ const result = await service.generate("foo", {
186
+ fontName: "standard",
187
+ colorEffects: {
188
+ messageForeground: {
189
+ type: "rainbow",
190
+ direction: "horizontal",
191
+ seed: 0.1,
192
+ },
193
+ },
194
+ });
195
+ expect(result).toContain("\x1b[38;2;");
196
+ const lines = result.trim().split("\n").filter((l) =>
197
+ l.includes("\x1b[38;2;")
198
+ );
199
+ const firstLine = lines[0]!;
200
+ // deno-lint-ignore no-control-regex
201
+ const codes = [...firstLine.matchAll(/\x1b\[38;2;(\d+;\d+;\d+)m/g)].map((
202
+ m,
203
+ ) => m[1]);
204
+ const unique = new Set(codes);
205
+ expect(unique.size).toBeGreaterThan(1);
206
+ });
207
+
208
+ test("rainbow vertical applies ANSI codes varying per line", async () => {
209
+ const service = new DefaultAsciiBannerGeneratorService();
210
+ const result = await service.generate("foo", {
211
+ fontName: "standard",
212
+ colorEffects: {
213
+ messageForeground: {
214
+ type: "rainbow",
215
+ direction: "vertical",
216
+ seed: 0.1,
217
+ },
218
+ },
219
+ });
220
+ const lines = result.trim().split("\n").filter((l) =>
221
+ l.includes("\x1b[38;2;")
222
+ );
223
+ const firstCodes = lines.map((l) =>
224
+ // deno-lint-ignore no-control-regex
225
+ l.match(/\x1b\[38;2;(\d+;\d+;\d+)m/)?.[1]
226
+ );
227
+ const unique = new Set(firstCodes.filter(Boolean));
228
+ expect(unique.size).toBeGreaterThan(1);
229
+ });
70
230
  });
@@ -1,4 +1,4 @@
1
- // Bun Snapshot v1, https://goo.gl/fbAQLP
1
+ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2
2
 
3
3
  exports[`DefaultAsciiBannerGeneratorService tests Can generate with standard font 1`] = `
4
4
  "
@@ -6,9 +6,9 @@ import { PRINTER_SERVICE_ID } from "../../../src/api/service/core/PrinterService
6
6
  import DefaultContext from "../../../src/runtime/DefaultContext.ts";
7
7
  import { ASCII_BANNER_GENERATOR_SERVICE_ID } from "../../../src/api/service/core/AsciiBannerGeneratorService.ts";
8
8
  import DefaultAsciiBannerGeneratorService from "../../../src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts";
9
- import TtyTerminal from "../../../src/service/printer/terminal/TtyTerminal.ts";
9
+ import TtyTerminal from "../../../src/terminal/TtyTerminal.ts";
10
10
  import StreamString from "../../fixtures/StreamString.ts";
11
- import TtyStyler from "../../../src/service/printer/terminal/TtyStyler.ts";
11
+ import TtyStyler from "../../../src/terminal/TtyStyler.ts";
12
12
  import { getConfigurationServiceProvider } from "../../fixtures/ConfigurationServiceProvider.ts";
13
13
 
14
14
  // FIGlet font is converted to a JSON string and embedded in a simple JSON file: `{ "font": "<figlet font definition>" }`
@@ -17,9 +17,11 @@ import smallFont from "../asciiBannerGenerator/small.flf.json" with {
17
17
  };
18
18
 
19
19
  describe("BannerServiceProvider tests", () => {
20
- test("BannerServiceProvider provide works", async () => {
20
+ test("BannerServiceProvider getServiceInfo works", async () => {
21
21
  const bannerServiceProvider = new BannerServiceProvider(100);
22
- const serviceInfo = await bannerServiceProvider.provide(getCLIConfig());
22
+ const serviceInfo = await bannerServiceProvider.getServiceInfo(
23
+ getCLIConfig(),
24
+ );
23
25
  expect(serviceInfo.commands.length).toEqual(1);
24
26
  });
25
27
 
@@ -31,6 +33,7 @@ describe("BannerServiceProvider tests", () => {
31
33
  dummyStderr.writableStream,
32
34
  true,
33
35
  true,
36
+ new TtyTerminal(dummyStdout.writeStream),
34
37
  new TtyTerminal(dummyStderr.writeStream),
35
38
  new TtyStyler(3),
36
39
  );
@@ -61,6 +64,7 @@ describe("BannerServiceProvider tests", () => {
61
64
  dummyStderr.writableStream,
62
65
  true,
63
66
  true,
67
+ new TtyTerminal(dummyStdout.writeStream),
64
68
  new TtyTerminal(dummyStderr.writeStream),
65
69
  new TtyStyler(3),
66
70
  );
@@ -0,0 +1,52 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import ChiselFontAsciiBannerGeneratorService from "../../../src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts";
3
+
4
+ describe("ChiselFontAsciiBannerGeneratorService tests", () => {
5
+ test("registerFont throws", () => {
6
+ const service = new ChiselFontAsciiBannerGeneratorService();
7
+ expect(() => service.registerFont("anything", "definition")).toThrow();
8
+ });
9
+
10
+ test("getRegisteredFonts returns chisel only", () => {
11
+ const service = new ChiselFontAsciiBannerGeneratorService();
12
+ expect(service.getRegisteredFonts()).toEqual(["chisel"]);
13
+ });
14
+
15
+ test("generate returns non-empty string with ANSI codes", async () => {
16
+ const service = new ChiselFontAsciiBannerGeneratorService();
17
+ const result = await service.generate("HI");
18
+ expect(result.length).toBeGreaterThan(0);
19
+ expect(result).toContain("\x1b[");
20
+ });
21
+
22
+ test("custom chisel colors replace default ANSI codes", async () => {
23
+ const service = new ChiselFontAsciiBannerGeneratorService();
24
+ // Generate without custom colors to get baseline
25
+ const baseline = await service.generate("HI");
26
+ // Generate with custom colors
27
+ const result = await service.generate("HI", {
28
+ chiselColors: { shadowForeground: 33 },
29
+ });
30
+ // The result should differ from baseline (color replacement occurred)
31
+ // shadowForeground maps \x1b[90m -> \x1b[33m
32
+ expect(result).not.toContain("\x1b[90m");
33
+ expect(result).toContain("\x1b[33m");
34
+ expect(result).not.toEqual(baseline);
35
+ });
36
+
37
+ test("subMessage appears uppercased and double-spaced", async () => {
38
+ const service = new ChiselFontAsciiBannerGeneratorService();
39
+ const result = await service.generate("HI", { subMessage: "world" });
40
+ expect(result).toContain("W O R L D");
41
+ });
42
+
43
+ test("fixed foreground color effect adds ANSI codes", async () => {
44
+ const service = new ChiselFontAsciiBannerGeneratorService();
45
+ const result = await service.generate("HI", {
46
+ colorEffects: {
47
+ messageForeground: { type: "fixed", color: "#00ff00" },
48
+ },
49
+ });
50
+ expect(result).toContain("\x1b[38;2;");
51
+ });
52
+ });