@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
@@ -128,21 +128,13 @@ function createService(
128
128
  } {
129
129
  const terminal = new MockTerminal();
130
130
  const config = { ...DEFAULT_PROMPTER_CONFIG, ...configOverrides };
131
- const service = new DefaultPrompterService(
132
- config,
133
- terminal,
134
- keyReader,
135
- getMockPrinterService(),
136
- );
131
+ const service = new DefaultPrompterService(config, terminal, keyReader, getMockPrinterService());
137
132
  return { service, terminal };
138
133
  }
139
134
 
140
135
  const SSH_ENV_KEYS = ["SSH_CONNECTION", "SSH_CLIENT", "SSH_TTY"] as const;
141
136
 
142
- function withSshEnvOverride<T>(
143
- overrides: Record<string, string | undefined>,
144
- fn: () => T,
145
- ): T {
137
+ function withSshEnvOverride<T>(overrides: Record<string, string | undefined>, fn: () => T): T {
146
138
  const saved = SSH_ENV_KEYS.map((k) => process.env[k]);
147
139
  SSH_ENV_KEYS.forEach((k) => {
148
140
  if (k in overrides) {
@@ -171,7 +163,9 @@ describe("DefaultPrompterService tests", () => {
171
163
  const keyReader = new MockKeyReader();
172
164
  keyReader.addKeys(
173
165
  { specialKey: SpecialKey.DOWN },
174
- { specialKey: SpecialKey.ENTER },
166
+ {
167
+ specialKey: SpecialKey.ENTER,
168
+ },
175
169
  );
176
170
  const { service } = createService(keyReader);
177
171
 
@@ -219,7 +213,9 @@ describe("DefaultPrompterService tests", () => {
219
213
  const keyReader = new MockKeyReader();
220
214
  keyReader.addKeys(
221
215
  { specialKey: SpecialKey.UP },
222
- { specialKey: SpecialKey.ENTER },
216
+ {
217
+ specialKey: SpecialKey.ENTER,
218
+ },
223
219
  );
224
220
  const { service } = createService(keyReader);
225
221
 
@@ -238,7 +234,9 @@ describe("DefaultPrompterService tests", () => {
238
234
  const keyReader = new MockKeyReader();
239
235
  keyReader.addKeys(
240
236
  { specialKey: SpecialKey.DOWN },
241
- { specialKey: SpecialKey.ENTER },
237
+ {
238
+ specialKey: SpecialKey.ENTER,
239
+ },
242
240
  );
243
241
  const { service } = createService(keyReader);
244
242
 
@@ -258,7 +256,9 @@ describe("DefaultPrompterService tests", () => {
258
256
  keyReader.addKeys(
259
257
  { key: "h" },
260
258
  { key: "i" },
261
- { specialKey: SpecialKey.ENTER },
259
+ {
260
+ specialKey: SpecialKey.ENTER,
261
+ },
262
262
  );
263
263
  const { service } = createService(keyReader);
264
264
 
@@ -325,9 +325,7 @@ describe("DefaultPrompterService tests", () => {
325
325
  name: "test",
326
326
  promptText: "Pick one",
327
327
  type: PromptType.SINGLE_SELECT,
328
- options: [
329
- { displayValue: "A", returnedValue: "a" },
330
- ],
328
+ options: [{ displayValue: "A", returnedValue: "a" }],
331
329
  }),
332
330
  ).rejects.toThrow("Prompting is disabled and no default for prompt: test");
333
331
  });
@@ -342,9 +340,7 @@ describe("DefaultPrompterService tests", () => {
342
340
  name: "test",
343
341
  promptText: "Pick one",
344
342
  type: PromptType.SINGLE_SELECT,
345
- options: [
346
- { displayValue: "A", returnedValue: "a" },
347
- ],
343
+ options: [{ displayValue: "A", returnedValue: "a" }],
348
344
  }),
349
345
  ).rejects.toThrow("Prompt cancelled");
350
346
  });
@@ -460,9 +456,7 @@ describe("DefaultPrompterService tests", () => {
460
456
 
461
457
  expect(terminal.buffer).toContain("Login at:");
462
458
  expect(terminal.buffer).toContain("https://example.com/login");
463
- expect(terminal.buffer).toContain(
464
- "Press ENTER to open in the browser...",
465
- );
459
+ expect(terminal.buffer).toContain("Press ENTER to open in the browser...");
466
460
  expect(terminal.buffer).toContain("Open browser to login");
467
461
  }));
468
462
 
@@ -491,9 +485,7 @@ describe("DefaultPrompterService tests", () => {
491
485
 
492
486
  expect(result.name).toEqual("login");
493
487
  expect(result.value).toEqual("https://example.com/login");
494
- expect(terminal.buffer).toContain(
495
- "Failed to open URL: browser not found",
496
- );
488
+ expect(terminal.buffer).toContain("Failed to open URL: browser not found");
497
489
  }));
498
490
 
499
491
  test("OPEN_URL with promptEnabled=false and defaultOption returns default", async () => {
@@ -538,49 +530,42 @@ describe("DefaultPrompterService tests", () => {
538
530
  },
539
531
  ],
540
532
  }),
541
- ).rejects.toThrow(
542
- "Prompting is disabled and no default for prompt: login",
543
- );
533
+ ).rejects.toThrow("Prompting is disabled and no default for prompt: login");
544
534
  });
545
535
 
546
536
  test("OPEN_URL in SSH session shows copy message and skips openUrl", () =>
547
- withSshEnvOverride(
548
- { SSH_CONNECTION: "192.168.1.1 12345 192.168.1.2 22" },
549
- async () => {
550
- const keyReader = new MockKeyReader();
551
- keyReader.addKeys({ specialKey: SpecialKey.ENTER });
552
- let openUrlCalled = false;
553
- const mockOpenUrl = (_url: string): Promise<void> => {
554
- openUrlCalled = true;
555
- return Promise.resolve();
556
- };
557
- const { service, terminal } = createService(keyReader, {
558
- openUrl: mockOpenUrl,
559
- });
560
-
561
- const result = await service.prompt({
562
- name: "login",
563
- promptText: "Login at:",
564
- type: PromptType.OPEN_URL,
565
- options: [
566
- {
567
- displayValue: "Open browser",
568
- returnedValue: "https://example.com/login",
569
- },
570
- ],
571
- });
572
-
573
- expect(result.name).toEqual("login");
574
- expect(result.value).toEqual("https://example.com/login");
575
- expect(openUrlCalled).toBe(false);
576
- expect(terminal.buffer).toContain(
577
- "Copy the URL above and open it in your local browser, then press ENTER to continue...",
578
- );
579
- expect(terminal.buffer).not.toContain(
580
- "Press ENTER to open in the browser...",
581
- );
582
- },
583
- ));
537
+ withSshEnvOverride({ SSH_CONNECTION: "192.168.1.1 12345 192.168.1.2 22" }, async () => {
538
+ const keyReader = new MockKeyReader();
539
+ keyReader.addKeys({ specialKey: SpecialKey.ENTER });
540
+ let openUrlCalled = false;
541
+ const mockOpenUrl = (_url: string): Promise<void> => {
542
+ openUrlCalled = true;
543
+ return Promise.resolve();
544
+ };
545
+ const { service, terminal } = createService(keyReader, {
546
+ openUrl: mockOpenUrl,
547
+ });
548
+
549
+ const result = await service.prompt({
550
+ name: "login",
551
+ promptText: "Login at:",
552
+ type: PromptType.OPEN_URL,
553
+ options: [
554
+ {
555
+ displayValue: "Open browser",
556
+ returnedValue: "https://example.com/login",
557
+ },
558
+ ],
559
+ });
560
+
561
+ expect(result.name).toEqual("login");
562
+ expect(result.value).toEqual("https://example.com/login");
563
+ expect(openUrlCalled).toBe(false);
564
+ expect(terminal.buffer).toContain(
565
+ "Copy the URL above and open it in your local browser, then press ENTER to continue...",
566
+ );
567
+ expect(terminal.buffer).not.toContain("Press ENTER to open in the browser...");
568
+ }));
584
569
 
585
570
  test("OPEN_URL outside SSH session shows open message", () =>
586
571
  withoutSshEnv(async () => {
@@ -608,8 +593,6 @@ describe("DefaultPrompterService tests", () => {
608
593
  });
609
594
 
610
595
  expect(openUrlCalled).toBe(true);
611
- expect(terminal.buffer).toContain(
612
- "Press ENTER to open in the browser...",
613
- );
596
+ expect(terminal.buffer).toContain("Press ENTER to open in the browser...");
614
597
  }));
615
598
  });
@@ -15,10 +15,7 @@ function getMockPrompterService(): PrompterService {
15
15
 
16
16
  describe("PrompterServiceProvider tests", () => {
17
17
  test("PrompterServiceProvider has correct serviceId", () => {
18
- const provider = new PrompterServiceProvider(
19
- 100,
20
- getMockPrompterService(),
21
- );
18
+ const provider = new PrompterServiceProvider(100, getMockPrompterService());
22
19
 
23
20
  expect(provider.serviceId).toEqual(PROMPTER_SERVICE_ID);
24
21
  });
@@ -36,10 +33,7 @@ describe("PrompterServiceProvider tests", () => {
36
33
  });
37
34
 
38
35
  test("PrompterServiceProvider initService resolves", async () => {
39
- const provider = new PrompterServiceProvider(
40
- 100,
41
- getMockPrompterService(),
42
- );
36
+ const provider = new PrompterServiceProvider(100, getMockPrompterService());
43
37
  const context = new DefaultContext(getCLIConfig());
44
38
 
45
39
  await expect(provider.initService(context)).resolves.toBeUndefined();
@@ -5,9 +5,7 @@ import { getCLIConfig } from "../../fixtures/CLIConfig.ts";
5
5
  describe("ShutdownServiceProvider tests", () => {
6
6
  test("ShutdownServiceProvider getServiceInfo works", async () => {
7
7
  const shutdownServiceProvider = new ShutdownServiceProvider(100);
8
- const serviceInfo = await shutdownServiceProvider.getServiceInfo(
9
- getCLIConfig(),
10
- );
8
+ const serviceInfo = await shutdownServiceProvider.getServiceInfo(getCLIConfig());
11
9
  expect(serviceInfo.commands.length).toEqual(0);
12
10
 
13
11
  await ShutdownServiceProvider.shutdown();
@@ -17,57 +17,30 @@ describe("DefaultSyntaxHighlighterService tests", () => {
17
17
  test("Cannot register a syntax if already registered", () => {
18
18
  const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
19
19
 
20
- expect(() => syntaxHighlighterService.registerSyntax("jSon", yaml))
21
- .toThrow();
20
+ expect(() => syntaxHighlighterService.registerSyntax("jSon", yaml)).toThrow();
22
21
  });
23
22
 
24
23
  test("Can register new syntax", () => {
25
24
  const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
26
25
 
27
26
  syntaxHighlighterService.registerSyntax("yaml", yaml);
28
- expect(syntaxHighlighterService.getRegisteredSyntaxes()).toEqual([
29
- "json",
30
- "yaml",
31
- ]);
27
+ expect(syntaxHighlighterService.getRegisteredSyntaxes()).toEqual(["json", "yaml"]);
32
28
  });
33
29
 
34
30
  test("Cannot highlight with unknown syntax", () => {
35
31
  const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
36
32
 
37
- expect(() => syntaxHighlighterService.highlight("foo: 1", "yaml"))
38
- .toThrow();
33
+ expect(() => syntaxHighlighterService.highlight("foo: 1", "yaml")).toThrow();
39
34
  });
40
35
 
41
36
  test("Can highlight with JSON syntax", () => {
42
37
  const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
43
38
 
44
- const highlighted = syntaxHighlighterService.highlight(
45
- "{ foo: 1 }",
46
- "json",
47
- );
39
+ const highlighted = syntaxHighlighterService.highlight("{ foo: 1 }", "json");
48
40
  expectBytesEquals(
49
41
  highlighted,
50
42
  new Uint8Array([
51
- 123,
52
- 32,
53
- 102,
54
- 111,
55
- 111,
56
- 58,
57
- 32,
58
- 27,
59
- 91,
60
- 51,
61
- 54,
62
- 109,
63
- 49,
64
- 27,
65
- 91,
66
- 51,
67
- 57,
68
- 109,
69
- 32,
70
- 125,
43
+ 123, 32, 102, 111, 111, 58, 32, 27, 91, 51, 54, 109, 49, 27, 91, 51, 57, 109, 32, 125,
71
44
  ]),
72
45
  );
73
46
  });
@@ -90,46 +63,14 @@ describe("DefaultSyntaxHighlighterService tests", () => {
90
63
 
91
64
  syntaxHighlighterService.colorFunction = printer.color.bind(printer);
92
65
 
93
- const highlighted = syntaxHighlighterService.highlight(
94
- "{ foo: 1 }",
95
- "json",
96
- {
97
- "number": "#FF0000",
98
- },
99
- );
66
+ const highlighted = syntaxHighlighterService.highlight("{ foo: 1 }", "json", {
67
+ number: "#FF0000",
68
+ });
100
69
  expectBytesEquals(
101
70
  highlighted,
102
71
  new Uint8Array([
103
- 123,
104
- 32,
105
- 102,
106
- 111,
107
- 111,
108
- 58,
109
- 32,
110
- 27,
111
- 91,
112
- 51,
113
- 56,
114
- 59,
115
- 50,
116
- 59,
117
- 50,
118
- 53,
119
- 53,
120
- 59,
121
- 48,
122
- 59,
123
- 48,
124
- 109,
125
- 49,
126
- 27,
127
- 91,
128
- 51,
129
- 57,
130
- 109,
131
- 32,
132
- 125,
72
+ 123, 32, 102, 111, 111, 58, 32, 27, 91, 51, 56, 59, 50, 59, 50, 53, 53, 59, 48, 59, 48, 109,
73
+ 49, 27, 91, 51, 57, 109, 32, 125,
133
74
  ]),
134
75
  );
135
76
  });
@@ -143,32 +84,8 @@ describe("DefaultSyntaxHighlighterService tests", () => {
143
84
  expectBytesEquals(
144
85
  highlighted,
145
86
  new Uint8Array([
146
- 27,
147
- 91,
148
- 51,
149
- 51,
150
- 109,
151
- 102,
152
- 111,
153
- 111,
154
- 58,
155
- 27,
156
- 91,
157
- 51,
158
- 57,
159
- 109,
160
- 32,
161
- 27,
162
- 91,
163
- 51,
164
- 54,
165
- 109,
166
- 49,
167
- 27,
168
- 91,
169
- 51,
170
- 57,
171
- 109,
87
+ 27, 91, 51, 51, 109, 102, 111, 111, 58, 27, 91, 51, 57, 109, 32, 27, 91, 51, 54, 109, 49,
88
+ 27, 91, 51, 57, 109,
172
89
  ]),
173
90
  );
174
91
  });
@@ -177,10 +94,7 @@ describe("DefaultSyntaxHighlighterService tests", () => {
177
94
  const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
178
95
  syntaxHighlighterService.colorEnabled = false;
179
96
 
180
- const highlighted = syntaxHighlighterService.highlight(
181
- "{ foo: 1 }",
182
- "json",
183
- );
97
+ const highlighted = syntaxHighlighterService.highlight("{ foo: 1 }", "json");
184
98
 
185
99
  expect(highlighted).toEqual("{ foo: 1 }");
186
100
  });
@@ -12,10 +12,7 @@ describe("SyntaxHighlighterServiceProvider tests", () => {
12
12
  test("SyntaxHighlighterServiceProvider getServiceInfo and initService works", async () => {
13
13
  const dummyStdout = new StreamString();
14
14
  const dummyStderr = new StreamString();
15
- const syntaxHighlighterServiceProvider =
16
- new SyntaxHighlighterServiceProvider(
17
- 100,
18
- );
15
+ const syntaxHighlighterServiceProvider = new SyntaxHighlighterServiceProvider(100);
19
16
  const cliConfig = getCLIConfig();
20
17
  const context = new DefaultContext(cliConfig);
21
18
 
@@ -32,9 +29,7 @@ describe("SyntaxHighlighterServiceProvider tests", () => {
32
29
  ),
33
30
  );
34
31
 
35
- const serviceInfo = await syntaxHighlighterServiceProvider.getServiceInfo(
36
- cliConfig,
37
- );
32
+ const serviceInfo = await syntaxHighlighterServiceProvider.getServiceInfo(cliConfig);
38
33
  expect(serviceInfo.commands.length).toEqual(0);
39
34
 
40
35
  await syntaxHighlighterServiceProvider.initService(context);
@@ -136,9 +136,7 @@ describe("DefaultTableGeneratorService tests", () => {
136
136
 
137
137
  const result = service.render(table);
138
138
  const lines = result.split("\n");
139
- const contentLines = lines.filter((l) =>
140
- l.startsWith("│") && !l.includes("─")
141
- );
139
+ const contentLines = lines.filter((l) => l.startsWith("│") && !l.includes("─"));
142
140
  expect(contentLines.length).toBeGreaterThan(1);
143
141
  // Each content line should have complete words (no mid-word breaks)
144
142
  for (const line of contentLines) {
@@ -146,9 +144,7 @@ describe("DefaultTableGeneratorService tests", () => {
146
144
  if (content.length > 0) {
147
145
  const words = content.split(/\s+/);
148
146
  for (const word of words) {
149
- expect(
150
- ["hello", "world", "foo", "bar", ""].includes(word),
151
- ).toBe(true);
147
+ expect(["hello", "world", "foo", "bar", ""].includes(word)).toBe(true);
152
148
  }
153
149
  }
154
150
  }
@@ -163,14 +159,10 @@ describe("DefaultTableGeneratorService tests", () => {
163
159
 
164
160
  const result = service.render(table);
165
161
  const lines = result.split("\n");
166
- const contentLines = lines.filter((l) =>
167
- l.startsWith("│") && !l.includes("─")
168
- );
162
+ const contentLines = lines.filter((l) => l.startsWith("│") && !l.includes("─"));
169
163
  expect(contentLines.length).toBeGreaterThan(1);
170
164
  // Verify all characters are present
171
- const allContent = contentLines
172
- .map((l) => l.replace(/│/g, "").replace(/ /g, ""))
173
- .join("");
165
+ const allContent = contentLines.map((l) => l.replace(/│/g, "").replace(/ /g, "")).join("");
174
166
  expect(allContent).toBe("ABCDEFGHIJKLMNOP");
175
167
  });
176
168
 
@@ -245,8 +237,7 @@ describe("DefaultTableGeneratorService tests", () => {
245
237
 
246
238
  test("empty cells render as blank space", () => {
247
239
  const service = createService();
248
- const table = new Table(1, 2, { maxWidth: 20, padding: 1 })
249
- .cell(0, 0, "Hi");
240
+ const table = new Table(1, 2, { maxWidth: 20, padding: 1 }).cell(0, 0, "Hi");
250
241
  // cell(0, 1) not set
251
242
 
252
243
  const result = service.render(table);
@@ -269,9 +260,7 @@ describe("DefaultTableGeneratorService tests", () => {
269
260
  const result = service.render(table);
270
261
  const lines = result.split("\n");
271
262
  // Filter content lines (between top and bottom borders)
272
- const contentLines = lines.filter((l) =>
273
- l.startsWith("│") && !l.includes("─")
274
- );
263
+ const contentLines = lines.filter((l) => l.startsWith("│") && !l.includes("─"));
275
264
  // Row should have 3 sub-lines due to multi-line content
276
265
  expect(contentLines.length).toBe(3);
277
266
  expect(contentLines[0]).toContain("line1");
@@ -304,8 +293,7 @@ describe("DefaultTableGeneratorService tests", () => {
304
293
 
305
294
  test("1x1 table renders correctly", () => {
306
295
  const service = createService();
307
- const table = new Table(1, 1, { maxWidth: 10, padding: 0 })
308
- .cell(0, 0, "Hi");
296
+ const table = new Table(1, 1, { maxWidth: 10, padding: 0 }).cell(0, 0, "Hi");
309
297
 
310
298
  const result = service.render(table);
311
299
  const lines = result.split("\n");
@@ -319,8 +307,7 @@ describe("DefaultTableGeneratorService tests", () => {
319
307
 
320
308
  test("padding=0 works", () => {
321
309
  const service = createService();
322
- const table = new Table(1, 1, { maxWidth: 10, padding: 0 })
323
- .cell(0, 0, "AB");
310
+ const table = new Table(1, 1, { maxWidth: 10, padding: 0 }).cell(0, 0, "AB");
324
311
 
325
312
  const result = service.render(table);
326
313
  const lines = result.split("\n");
@@ -335,22 +322,14 @@ describe("DefaultTableGeneratorService tests", () => {
335
322
 
336
323
  test("out-of-bounds row index throws", () => {
337
324
  const table = new Table(2, 2);
338
- expect(() => table.row(5, { align: Align.LEFT })).toThrow(
339
- /out of bounds/,
340
- );
341
- expect(() => table.row(-1, { align: Align.LEFT })).toThrow(
342
- /out of bounds/,
343
- );
325
+ expect(() => table.row(5, { align: Align.LEFT })).toThrow(/out of bounds/);
326
+ expect(() => table.row(-1, { align: Align.LEFT })).toThrow(/out of bounds/);
344
327
  });
345
328
 
346
329
  test("out-of-bounds column index throws", () => {
347
330
  const table = new Table(2, 2);
348
- expect(() => table.column(5, { flexWeight: 1 })).toThrow(
349
- /out of bounds/,
350
- );
351
- expect(() => table.column(-1, { flexWeight: 1 })).toThrow(
352
- /out of bounds/,
353
- );
331
+ expect(() => table.column(5, { flexWeight: 1 })).toThrow(/out of bounds/);
332
+ expect(() => table.column(-1, { flexWeight: 1 })).toThrow(/out of bounds/);
354
333
  });
355
334
 
356
335
  test("out-of-bounds cell index throws", () => {
@@ -38,8 +38,8 @@ describe("TableGeneratorServiceProvider tests", () => {
38
38
  const serviceInfo = await provider.getServiceInfo(cliConfig);
39
39
  expect(serviceInfo.commands.length).toEqual(0);
40
40
  await provider.initService(context);
41
- const service = serviceInfo
42
- .service as import("../../../src/service/tableGenerator/DefaultTableGeneratorService.ts").default;
41
+ const service =
42
+ serviceInfo.service as import("../../../src/service/tableGenerator/DefaultTableGeneratorService.ts").default;
43
43
  expect(service.colorEnabled).toBe(true);
44
44
  expect(typeof service.colorFunction).toBe("function");
45
45
  expect(typeof service.backgroundColorFunction).toBe("function");
@@ -33,7 +33,9 @@ describe("DefaultTreePrinterService tests", () => {
33
33
  label: "Root",
34
34
  children: [
35
35
  { label: "Child1", children: ["Leaf1", "Leaf2"] },
36
- { label: "Child2" },
36
+ {
37
+ label: "Child2",
38
+ },
37
39
  ],
38
40
  });
39
41
 
@@ -51,11 +53,7 @@ describe("DefaultTreePrinterService tests", () => {
51
53
 
52
54
  const result = service.print({
53
55
  label: "Root",
54
- children: [
55
- "StringChild",
56
- { label: "NodeChild", children: ["Nested"] },
57
- "Last",
58
- ],
56
+ children: ["StringChild", { label: "NodeChild", children: ["Nested"] }, "Last"],
59
57
  });
60
58
 
61
59
  const lines = result.split("\n");
@@ -13,9 +13,7 @@ describe("TreePrinterServiceProvider tests", () => {
13
13
  const treePrinterServiceProvider = new TreePrinterServiceProvider(100);
14
14
  const cliConfig = getCLIConfig();
15
15
 
16
- const serviceInfo = await treePrinterServiceProvider.getServiceInfo(
17
- cliConfig,
18
- );
16
+ const serviceInfo = await treePrinterServiceProvider.getServiceInfo(cliConfig);
19
17
  expect(serviceInfo.commands.length).toEqual(0);
20
18
  expect(serviceInfo.service).toBeDefined();
21
19
  });
@@ -40,15 +38,13 @@ describe("TreePrinterServiceProvider tests", () => {
40
38
  ),
41
39
  );
42
40
 
43
- const serviceInfo = await treePrinterServiceProvider.getServiceInfo(
44
- cliConfig,
45
- );
41
+ const serviceInfo = await treePrinterServiceProvider.getServiceInfo(cliConfig);
46
42
  expect(serviceInfo.commands.length).toEqual(0);
47
43
 
48
44
  await treePrinterServiceProvider.initService(context);
49
45
 
50
- const service = serviceInfo
51
- .service as import("../../../src/service/treePrinter/DefaultTreePrinterService.ts").default;
46
+ const service =
47
+ serviceInfo.service as import("../../../src/service/treePrinter/DefaultTreePrinterService.ts").default;
52
48
  expect(service.colorEnabled).toBe(true);
53
49
  expect(typeof service.colorFunction).toBe("function");
54
50
  });
@@ -31,11 +31,7 @@ function crc32(data: Uint8Array): number {
31
31
  return (crc ^ 0xffffffff) >>> 0;
32
32
  }
33
33
 
34
- function buildValidPng(
35
- width: number,
36
- height: number,
37
- colorType: number = 6,
38
- ): Uint8Array {
34
+ function buildValidPng(width: number, height: number, colorType: number = 6): Uint8Array {
39
35
  const parts: number[] = [];
40
36
 
41
37
  // PNG signature
@@ -44,12 +40,7 @@ function buildValidPng(
44
40
  function addChunk(type: string, data: Uint8Array) {
45
41
  // Length (4 bytes big-endian)
46
42
  const len = data.length;
47
- parts.push(
48
- (len >>> 24) & 0xff,
49
- (len >>> 16) & 0xff,
50
- (len >>> 8) & 0xff,
51
- len & 0xff,
52
- );
43
+ parts.push((len >>> 24) & 0xff, (len >>> 16) & 0xff, (len >>> 8) & 0xff, len & 0xff);
53
44
 
54
45
  // Type (4 bytes)
55
46
  const typeBytes = new TextEncoder().encode(type);
@@ -3,9 +3,7 @@ import { describe, expect, test } from "bun:test";
3
3
  import { decodePngToRGBA } from "../../src/terminal/PngDecoder.ts";
4
4
 
5
5
  // Helper to build a minimal PNG from raw components
6
- function buildPng(
7
- chunks: Array<{ type: string; data: Uint8Array }>,
8
- ): Uint8Array {
6
+ function buildPng(chunks: Array<{ type: string; data: Uint8Array }>): Uint8Array {
9
7
  const parts: Uint8Array[] = [];
10
8
  // PNG signature
11
9
  parts.push(new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]));
@@ -177,9 +175,7 @@ describe("decodePngToRGBA", () => {
177
175
  { type: "IHDR", data: makeIHDR(1, 1, 8, 6, 1) },
178
176
  { type: "IEND", data: new Uint8Array(0) },
179
177
  ]);
180
- expect(() => decodePngToRGBA(png)).toThrow(
181
- "Interlaced PNGs are not supported",
182
- );
178
+ expect(() => decodePngToRGBA(png)).toThrow("Interlaced PNGs are not supported");
183
179
  });
184
180
 
185
181
  test("throws on unknown filter type", () => {