@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
@@ -1,29 +1,9 @@
1
1
  import type Styler from "../../../terminal/Styler.ts";
2
2
  import type Terminal from "../../../terminal/Terminal.ts";
3
3
 
4
- const BOX_FRAMES = [
5
- "⠋",
6
- "⠙",
7
- "⠹",
8
- "⠸",
9
- "⠼",
10
- "⠴",
11
- "⠦",
12
- "⠧",
13
- "⠇",
14
- "⠏",
15
- ];
4
+ const BOX_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
16
5
 
17
- const STAR_FRAMES = [
18
- "★",
19
- "✶",
20
- "✷",
21
- "✹",
22
- "✷",
23
- "✶",
24
- "★",
25
- "✦",
26
- ];
6
+ const STAR_FRAMES = ["★", "✶", "✷", "✹", "✷", "✶", "★", "✦"];
27
7
 
28
8
  export { SpinnerStyle } from "../../../api/service/core/PrinterService.ts";
29
9
  import { SpinnerStyle } from "../../../api/service/core/PrinterService.ts";
@@ -56,9 +36,10 @@ export default class Spinner {
56
36
  await this.#terminal.clearLine();
57
37
  if (this.#message) {
58
38
  await this.#terminal.write(
59
- `${
60
- this.#styler.colorText(frames[this.#frameIndex]!, this.#spinColor)
61
- } ${this.#styler.colorText(this.#message!, this.#msgColor)}`,
39
+ `${this.#styler.colorText(
40
+ frames[this.#frameIndex]!,
41
+ this.#spinColor,
42
+ )} ${this.#styler.colorText(this.#message!, this.#msgColor)}`,
62
43
  );
63
44
  } else {
64
45
  await this.#terminal.write(
@@ -102,7 +83,7 @@ export default class Spinner {
102
83
  }
103
84
 
104
85
  public resume(): void {
105
- if ((!this.#isShown) || (this.#timer !== undefined)) {
86
+ if (!this.#isShown || this.#timer !== undefined) {
106
87
  return;
107
88
  }
108
89
  this.#timer = setInterval(async () => {
@@ -53,9 +53,7 @@ export default class DefaultPrompterService implements PrompterService {
53
53
  });
54
54
  }
55
55
  return Promise.reject(
56
- new Error(
57
- `Prompting is disabled and no default for prompt: ${promptDef.name}`,
58
- ),
56
+ new Error(`Prompting is disabled and no default for prompt: ${promptDef.name}`),
59
57
  );
60
58
  }
61
59
 
@@ -75,9 +73,7 @@ export default class DefaultPrompterService implements PrompterService {
75
73
  }
76
74
  }
77
75
 
78
- async promptAll(
79
- prompts: ReadonlyArray<Prompt>,
80
- ): Promise<ReadonlyArray<PromptResult>> {
76
+ async promptAll(prompts: ReadonlyArray<Prompt>): Promise<ReadonlyArray<PromptResult>> {
81
77
  const results: PromptResult[] = [];
82
78
  for (const p of prompts) {
83
79
  results.push(await this.prompt(p));
@@ -1,8 +1,5 @@
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 type PrompterService from "../../api/service/core/PrompterService.ts";
7
4
  import { PROMPTER_SERVICE_ID } from "../../api/service/core/PrompterService.ts";
8
5
  import NoPromptCommand from "./command/NoPromptCommand.ts";
@@ -13,10 +10,7 @@ export default class PrompterServiceProvider implements ServiceProvider {
13
10
  readonly servicePriority: number;
14
11
  readonly prompterService: PrompterService;
15
12
 
16
- public constructor(
17
- servicePriority: number,
18
- prompterService: PrompterService,
19
- ) {
13
+ public constructor(servicePriority: number, prompterService: PrompterService) {
20
14
  this.servicePriority = servicePriority;
21
15
  this.prompterService = prompterService;
22
16
  }
@@ -24,9 +18,7 @@ export default class PrompterServiceProvider implements ServiceProvider {
24
18
  public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
25
19
  return Promise.resolve({
26
20
  service: this.prompterService,
27
- commands: [
28
- new NoPromptCommand(this, this.servicePriority),
29
- ],
21
+ commands: [new NoPromptCommand(this, this.servicePriority)],
30
22
  });
31
23
  }
32
24
 
@@ -20,20 +20,13 @@ export default class NoPromptCommand implements GlobalModifierCommand {
20
20
 
21
21
  readonly #prompterServiceProvider: PrompterServiceProvider;
22
22
 
23
- public constructor(
24
- prompterServiceProvider: PrompterServiceProvider,
25
- executePriority: number,
26
- ) {
23
+ public constructor(prompterServiceProvider: PrompterServiceProvider, executePriority: number) {
27
24
  this.#prompterServiceProvider = prompterServiceProvider;
28
25
  this.executePriority = executePriority;
29
26
  }
30
27
 
31
- public execute(
32
- _context: Context,
33
- argumentValue: ArgumentSingleValueType,
34
- ): Promise<void> {
35
- this.#prompterServiceProvider.prompterService.promptEnabled =
36
- !(argumentValue as boolean);
28
+ public execute(_context: Context, argumentValue: ArgumentSingleValueType): Promise<void> {
29
+ this.#prompterServiceProvider.prompterService.promptEnabled = !(argumentValue as boolean);
37
30
 
38
31
  return Promise.resolve();
39
32
  }
@@ -11,20 +11,14 @@ export interface PromptContext {
11
11
  readonly printerService: PrinterService;
12
12
  }
13
13
 
14
- export function physicalLineCount(
15
- terminal: Terminal,
16
- text: string,
17
- ): number {
14
+ export function physicalLineCount(terminal: Terminal, text: string): number {
18
15
  const cols = terminal.columns();
19
16
  if (cols <= 0) return 1;
20
17
  const width = Bun.stringWidth(text);
21
18
  return Math.max(1, Math.ceil(width / cols));
22
19
  }
23
20
 
24
- export function headerLineCount(
25
- terminal: Terminal,
26
- promptDef: Prompt,
27
- ): number {
21
+ export function headerLineCount(terminal: Terminal, promptDef: Prompt): number {
28
22
  let count = physicalLineCount(terminal, promptDef.promptText);
29
23
  if (promptDef.description) {
30
24
  count += physicalLineCount(terminal, promptDef.description);
@@ -32,16 +26,9 @@ export function headerLineCount(
32
26
  return count;
33
27
  }
34
28
 
35
- export async function renderPromptHeader(
36
- ctx: PromptContext,
37
- promptDef: Prompt,
38
- ): Promise<void> {
39
- await ctx.terminal.write(
40
- `${ctx.printerService.emphasised(promptDef.promptText)}\n`,
41
- );
29
+ export async function renderPromptHeader(ctx: PromptContext, promptDef: Prompt): Promise<void> {
30
+ await ctx.terminal.write(`${ctx.printerService.emphasised(promptDef.promptText)}\n`);
42
31
  if (promptDef.description) {
43
- await ctx.terminal.write(
44
- `${ctx.printerService.secondary(promptDef.description)}\n`,
45
- );
32
+ await ctx.terminal.write(`${ctx.printerService.secondary(promptDef.description)}\n`);
46
33
  }
47
34
  }
@@ -1,7 +1,4 @@
1
- import type {
2
- Prompt,
3
- PromptResult,
4
- } from "../../../api/service/core/PrompterService.ts";
1
+ import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
5
2
  import { SpecialKey } from "../../../terminal/KeyReader.ts";
6
3
  import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
7
4
  import { headerLineCount, renderPromptHeader } from "./PromptContext.ts";
@@ -19,10 +16,7 @@ export default async function promptMultiSelect(
19
16
  let focusIndex = 0;
20
17
  const checked = new Set<number>();
21
18
  let scrollOffset = 0;
22
- const visibleCount = Math.min(
23
- ctx.config.scrollVisibleOptions,
24
- options.length,
25
- );
19
+ const visibleCount = Math.min(ctx.config.scrollVisibleOptions, options.length);
26
20
 
27
21
  ctx.keyReader.enableRawMode();
28
22
  try {
@@ -51,15 +45,11 @@ export default async function promptMultiSelect(
51
45
  const isChecked = checked.has(i);
52
46
  const checkbox = isChecked
53
47
  ? ctx.printerService.green(ctx.config.checkboxCheckedChars)
54
- : ctx.printerService.secondary(
55
- ctx.config.checkboxUncheckedChars,
56
- );
48
+ : ctx.printerService.secondary(ctx.config.checkboxUncheckedChars);
57
49
  const text = option.displayValue;
58
50
  await ctx.terminal.write(
59
51
  `${checkbox} ${
60
- isFocused
61
- ? ctx.printerService.cyan(text)
62
- : ctx.printerService.secondary(text)
52
+ isFocused ? ctx.printerService.cyan(text) : ctx.printerService.secondary(text)
63
53
  }\n`,
64
54
  );
65
55
  }
@@ -67,10 +57,7 @@ export default async function promptMultiSelect(
67
57
  const keyEvent = await ctx.keyReader.readKey();
68
58
  if (keyEvent.specialKey === SpecialKey.UP && focusIndex > 0) {
69
59
  focusIndex--;
70
- } else if (
71
- keyEvent.specialKey === SpecialKey.DOWN &&
72
- focusIndex < options.length - 1
73
- ) {
60
+ } else if (keyEvent.specialKey === SpecialKey.DOWN && focusIndex < options.length - 1) {
74
61
  focusIndex++;
75
62
  } else if (keyEvent.specialKey === SpecialKey.SPACE) {
76
63
  if (checked.has(focusIndex)) {
@@ -80,9 +67,7 @@ export default async function promptMultiSelect(
80
67
  }
81
68
  } else if (keyEvent.specialKey === SpecialKey.ENTER) {
82
69
  await ctx.terminal.showCursor();
83
- const values = [...checked].sort().map(
84
- (i) => options[i]!.returnedValue,
85
- );
70
+ const values = [...checked].sort().map((i) => options[i]!.returnedValue);
86
71
  return { name: promptDef.name, value: values };
87
72
  } else if (keyEvent.specialKey === SpecialKey.ESCAPE) {
88
73
  await ctx.terminal.showCursor();
@@ -1,18 +1,11 @@
1
- import type {
2
- Prompt,
3
- PromptResult,
4
- } from "../../../api/service/core/PrompterService.ts";
1
+ import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
5
2
  import { SpecialKey } from "../../../terminal/KeyReader.ts";
6
3
  import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
7
4
  import { renderPromptHeader } from "./PromptContext.ts";
8
5
  import type { PromptContext } from "./PromptContext.ts";
9
6
 
10
7
  function isRemoteSession(): boolean {
11
- return !!(
12
- process.env.SSH_CONNECTION ||
13
- process.env.SSH_CLIENT ||
14
- process.env.SSH_TTY
15
- );
8
+ return !!(process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY);
16
9
  }
17
10
 
18
11
  async function defaultOpenUrl(url: string): Promise<void> {
@@ -53,16 +46,12 @@ export default async function promptOpenUrl(
53
46
  try {
54
47
  await renderPromptHeader(ctx, promptDef);
55
48
 
56
- await ctx.terminal.write(
57
- `${displayLabel}: ${ctx.printerService.cyan(url)}\n`,
58
- );
49
+ await ctx.terminal.write(`${displayLabel}: ${ctx.printerService.cyan(url)}\n`);
59
50
 
60
51
  const instruction = canOpenBrowser
61
52
  ? "Press ENTER to open in the browser..."
62
53
  : "Copy the URL above and open it in your local browser, then press ENTER to continue...";
63
- await ctx.terminal.write(
64
- `${ctx.printerService.secondary(instruction)}\n`,
65
- );
54
+ await ctx.terminal.write(`${ctx.printerService.secondary(instruction)}\n`);
66
55
 
67
56
  while (true) {
68
57
  const keyEvent = await ctx.keyReader.readKey();
@@ -73,13 +62,9 @@ export default async function promptOpenUrl(
73
62
  await openUrlFn(url);
74
63
  } catch (e) {
75
64
  await ctx.terminal.write(
76
- `${
77
- ctx.printerService.red(
78
- `Failed to open URL: ${
79
- e instanceof Error ? e.message : String(e)
80
- }`,
81
- )
82
- }\n`,
65
+ `${ctx.printerService.red(
66
+ `Failed to open URL: ${e instanceof Error ? e.message : String(e)}`,
67
+ )}\n`,
83
68
  );
84
69
  }
85
70
  }
@@ -1,7 +1,4 @@
1
- import type {
2
- Prompt,
3
- PromptResult,
4
- } from "../../../api/service/core/PrompterService.ts";
1
+ import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
5
2
  import { SpecialKey } from "../../../terminal/KeyReader.ts";
6
3
  import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
7
4
  import { headerLineCount, renderPromptHeader } from "./PromptContext.ts";
@@ -25,10 +22,7 @@ export default async function promptSingleSelect(
25
22
  }
26
23
 
27
24
  let scrollOffset = 0;
28
- const visibleCount = Math.min(
29
- ctx.config.scrollVisibleOptions,
30
- options.length,
31
- );
25
+ const visibleCount = Math.min(ctx.config.scrollVisibleOptions, options.length);
32
26
 
33
27
  ctx.keyReader.enableRawMode();
34
28
  try {
@@ -57,32 +51,21 @@ export default async function promptSingleSelect(
57
51
  const prefix = isSelected ? ctx.config.inputPromptCharacters : " ";
58
52
  const text = prefix + option.displayValue;
59
53
  await ctx.terminal.write(
60
- `${
61
- isSelected
62
- ? ctx.printerService.cyan(text)
63
- : ctx.printerService.secondary(text)
64
- }\n`,
54
+ `${isSelected ? ctx.printerService.cyan(text) : ctx.printerService.secondary(text)}\n`,
65
55
  );
66
56
  }
67
57
 
68
58
  const keyEvent = await ctx.keyReader.readKey();
69
59
  if (keyEvent.specialKey === SpecialKey.UP && selectedIndex > 0) {
70
60
  selectedIndex--;
71
- } else if (
72
- keyEvent.specialKey === SpecialKey.DOWN &&
73
- selectedIndex < options.length - 1
74
- ) {
61
+ } else if (keyEvent.specialKey === SpecialKey.DOWN && selectedIndex < options.length - 1) {
75
62
  selectedIndex++;
76
63
  } else if (keyEvent.specialKey === SpecialKey.ENTER) {
77
64
  await ctx.terminal.showCursor();
78
65
  const option = options[selectedIndex]!;
79
- const validationError = option.validate
80
- ? option.validate(option.returnedValue)
81
- : undefined;
66
+ const validationError = option.validate ? option.validate(option.returnedValue) : undefined;
82
67
  if (validationError) {
83
- await ctx.terminal.write(
84
- `${ctx.printerService.red(validationError)}\n`,
85
- );
68
+ await ctx.terminal.write(`${ctx.printerService.red(validationError)}\n`);
86
69
  firstRender = true;
87
70
  continue;
88
71
  }
@@ -1,7 +1,4 @@
1
- import type {
2
- Prompt,
3
- PromptResult,
4
- } from "../../../api/service/core/PrompterService.ts";
1
+ import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
5
2
  import type { ArgumentSingleValueType } from "../../../api/argument/ArgumentValueTypes.ts";
6
3
  import { SpecialKey } from "../../../terminal/KeyReader.ts";
7
4
  import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
@@ -16,14 +13,10 @@ export default async function promptText(
16
13
  try {
17
14
  while (true) {
18
15
  await renderPromptHeader(ctx, promptDef);
19
- const promptMarker = ctx.printerService.cyan(
20
- ctx.config.inputPromptCharacters,
21
- );
16
+ const promptMarker = ctx.printerService.cyan(ctx.config.inputPromptCharacters);
22
17
  await ctx.terminal.write(promptMarker);
23
18
 
24
- let buffer = promptDef.defaultOption
25
- ? String(promptDef.defaultOption.returnedValue)
26
- : "";
19
+ let buffer = promptDef.defaultOption ? String(promptDef.defaultOption.returnedValue) : "";
27
20
  if (buffer.length > 0) {
28
21
  await ctx.terminal.write(buffer);
29
22
  }
@@ -48,30 +41,24 @@ export default async function promptText(
48
41
  }
49
42
  } else if (keyEvent.key) {
50
43
  buffer += keyEvent.key;
51
- const isSecret = promptDef.options.length > 0 &&
52
- promptDef.options[0]!.displayValue === "__SECRET__";
44
+ const isSecret =
45
+ promptDef.options.length > 0 && promptDef.options[0]!.displayValue === "__SECRET__";
53
46
  await ctx.terminal.write(isSecret ? "*" : keyEvent.key);
54
47
  }
55
48
  }
56
49
 
57
50
  if (buffer.length === 0 && !promptDef.defaultOption) {
58
- await ctx.terminal.write(
59
- ctx.printerService.red("Value required\n"),
60
- );
51
+ await ctx.terminal.write(ctx.printerService.red("Value required\n"));
61
52
  continue;
62
53
  }
63
54
 
64
55
  const value: ArgumentSingleValueType = buffer;
65
56
 
66
- const validationOption = promptDef.options.length > 0
67
- ? promptDef.options[0]
68
- : undefined;
57
+ const validationOption = promptDef.options.length > 0 ? promptDef.options[0] : undefined;
69
58
  if (validationOption?.validate) {
70
59
  const error = validationOption.validate(value);
71
60
  if (error) {
72
- await ctx.terminal.write(
73
- `${ctx.printerService.red(error)}\n`,
74
- );
61
+ await ctx.terminal.write(`${ctx.printerService.red(error)}\n`);
75
62
  continue;
76
63
  }
77
64
  }
@@ -80,9 +67,7 @@ export default async function promptText(
80
67
  const num = Number(value);
81
68
  if (!isNaN(num) && num < validationOption.min) {
82
69
  await ctx.terminal.write(
83
- ctx.printerService.red(
84
- `Value must be at least ${validationOption.min}\n`,
85
- ),
70
+ ctx.printerService.red(`Value must be at least ${validationOption.min}\n`),
86
71
  );
87
72
  continue;
88
73
  }
@@ -91,9 +76,7 @@ export default async function promptText(
91
76
  const num = Number(value);
92
77
  if (!isNaN(num) && num > validationOption.max) {
93
78
  await ctx.terminal.write(
94
- ctx.printerService.red(
95
- `Value must be at most ${validationOption.max}\n`,
96
- ),
79
+ ctx.printerService.red(`Value must be at most ${validationOption.max}\n`),
97
80
  );
98
81
  continue;
99
82
  }
@@ -6,10 +6,7 @@ import {
6
6
  import type { PromptContext } from "./PromptContext.ts";
7
7
  import promptSingleSelect from "./promptSingleSelect.ts";
8
8
 
9
- export default function promptToggle(
10
- ctx: PromptContext,
11
- promptDef: Prompt,
12
- ): Promise<PromptResult> {
9
+ export default function promptToggle(ctx: PromptContext, promptDef: Prompt): Promise<PromptResult> {
13
10
  const trueFalse: Prompt = {
14
11
  name: promptDef.name,
15
12
  promptText: promptDef.promptText,
@@ -19,10 +16,13 @@ export default function promptToggle(
19
16
  displayValue: "False",
20
17
  returnedValue: false,
21
18
  },
22
- options: promptDef.options.length > 0 ? promptDef.options : [
23
- { displayValue: "True", returnedValue: true },
24
- { displayValue: "False", returnedValue: false },
25
- ],
19
+ options:
20
+ promptDef.options.length > 0
21
+ ? promptDef.options
22
+ : [
23
+ { displayValue: "True", returnedValue: true },
24
+ { displayValue: "False", returnedValue: false },
25
+ ],
26
26
  };
27
27
  return promptSingleSelect(ctx, trueFalse);
28
28
  }
@@ -1,8 +1,5 @@
1
1
  import process from "node:process";
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 DefaultShutdownService from "./DefaultShutdownService.ts";
7
4
  import type ShutdownService from "../../api/service/core/ShutdownService.ts";
8
5
  import { SHUTDOWN_SERVICE_ID } from "../../api/service/core/ShutdownService.ts";
@@ -18,9 +15,7 @@ export default class ShutdownServiceProvider implements ServiceProvider {
18
15
  readonly #shutdownService: ShutdownService;
19
16
  static #shutdownInProgress = false;
20
17
 
21
- public constructor(
22
- readonly servicePriority: number,
23
- ) {
18
+ public constructor(readonly servicePriority: number) {
24
19
  this.#shutdownService = new DefaultShutdownService();
25
20
  process.on("beforeExit", ShutdownServiceProvider.shutdown);
26
21
  process.on("SIGINT", ShutdownServiceProvider.onInterrupt);
@@ -40,9 +35,7 @@ export default class ShutdownServiceProvider implements ServiceProvider {
40
35
 
41
36
  static onInterrupt(): void {
42
37
  shutdownState.interruptCount++;
43
- if (
44
- !shutdownState.longRunningMode || shutdownState.interruptCount >= 3
45
- ) {
38
+ if (!shutdownState.longRunningMode || shutdownState.interruptCount >= 3) {
46
39
  ShutdownServiceProvider.shutdown().then(() => {
47
40
  process.exit(130);
48
41
  });
@@ -9,11 +9,7 @@ type Sheet = Record<string, (value: string) => string> | undefined;
9
9
  interface Emphasize {
10
10
  listLanguages(): ReadonlyArray<string>;
11
11
  registered(name: string): boolean;
12
- highlight(
13
- name: string,
14
- text: string,
15
- sheet: Sheet,
16
- ): { value: string };
12
+ highlight(name: string, text: string, sheet: Sheet): { value: string };
17
13
  register(name: string, syntax: HighlightSyntax): void;
18
14
  }
19
15
 
@@ -21,30 +17,24 @@ interface Emphasize {
21
17
  * Default implementation of {@link SyntaxHighlighterService} which has a syntax definition
22
18
  * for JSON already registered.
23
19
  */
24
- export default class DefaultSyntaxHighlighterService
25
- implements SyntaxHighlighterService {
20
+ export default class DefaultSyntaxHighlighterService implements SyntaxHighlighterService {
26
21
  colorEnabled = true;
27
- colorFunction: (text: string, hexFormattedColor: string) => string = (text) =>
28
- text;
22
+ colorFunction: (text: string, hexFormattedColor: string) => string = (text) => text;
29
23
 
30
- emphasize: Emphasize;
24
+ #emphasize: Emphasize;
31
25
 
32
26
  constructor() {
33
- this.emphasize = createEmphasize();
27
+ this.#emphasize = createEmphasize();
34
28
  this.registerSyntax("json", json);
35
29
  }
36
30
 
37
31
  getRegisteredSyntaxes(): ReadonlyArray<string> {
38
- return this.emphasize.listLanguages();
32
+ return this.#emphasize.listLanguages();
39
33
  }
40
34
 
41
- highlight(
42
- text: string,
43
- syntaxName: string,
44
- colorScheme?: ColorScheme,
45
- ): string {
35
+ highlight(text: string, syntaxName: string, colorScheme?: ColorScheme): string {
46
36
  const name = syntaxName.toLowerCase();
47
- if (!this.emphasize.registered(name)) {
37
+ if (!this.#emphasize.registered(name)) {
48
38
  throw new Error(`Syntax name is not registered: ${name}`);
49
39
  }
50
40
 
@@ -62,30 +52,27 @@ export default class DefaultSyntaxHighlighterService
62
52
  if (!value) {
63
53
  throw new Error(`Invalid color for entry: ${key}`);
64
54
  }
65
- if (
66
- (value.length !== 7) ||
67
- (!value.toLowerCase().startsWith("#"))
68
- ) {
55
+ if (value.length !== 7 || !value.toLowerCase().startsWith("#")) {
69
56
  throw new Error(`Invalid color: ${value}`);
70
57
  }
71
58
 
72
59
  const colorValue = parseInt(value.slice(1), 16);
73
60
 
74
- if (isNaN(colorValue) || (colorValue < 0 || colorValue > 0xffffff)) {
61
+ if (isNaN(colorValue) || colorValue < 0 || colorValue > 0xffffff) {
75
62
  throw new Error(`Invalid color: ${value}`);
76
63
  }
77
64
  sheet[key] = (text: string) => this.colorFunction(text, value);
78
65
  }
79
66
  }
80
67
 
81
- return this.emphasize.highlight(name, text, sheet).value;
68
+ return this.#emphasize.highlight(name, text, sheet).value;
82
69
  }
83
70
 
84
71
  registerSyntax(syntaxName: string, syntaxDefinition: HighlightSyntax): void {
85
72
  const name = syntaxName.toLowerCase();
86
- if (this.emphasize.registered(name)) {
73
+ if (this.#emphasize.registered(name)) {
87
74
  throw new Error(`Syntax name already registered: ${name}`);
88
75
  }
89
- this.emphasize.register(name, syntaxDefinition);
76
+ this.#emphasize.register(name, syntaxDefinition);
90
77
  }
91
78
  }
@@ -1,11 +1,6 @@
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 DefaultSyntaxHighlighterService from "./DefaultSyntaxHighlighterService.ts";
6
- import {
7
- SYNTAX_HIGHLIGHTER_SERVICE_ID,
8
- } from "../../api/service/core/SyntaxHighlighterService.ts";
3
+ import { SYNTAX_HIGHLIGHTER_SERVICE_ID } from "../../api/service/core/SyntaxHighlighterService.ts";
9
4
  import type Context from "../../api/Context.ts";
10
5
  import type PrinterService from "../../api/service/core/PrinterService.ts";
11
6
  import { PRINTER_SERVICE_ID } from "../../api/service/core/PrinterService.ts";
@@ -14,8 +9,7 @@ import type CLIConfig from "../../api/CLIConfig.ts";
14
9
  /**
15
10
  * Provides a {@link SyntaxHighlighterService}.
16
11
  */
17
- export default class SyntaxHighlighterServiceProvider
18
- implements ServiceProvider {
12
+ export default class SyntaxHighlighterServiceProvider implements ServiceProvider {
19
13
  readonly serviceId: string = SYNTAX_HIGHLIGHTER_SERVICE_ID;
20
14
  readonly #defaultSyntaxHighlighterService: DefaultSyntaxHighlighterService;
21
15
 
@@ -24,11 +18,8 @@ export default class SyntaxHighlighterServiceProvider
24
18
  *
25
19
  * @param servicePriority the priority of the service.
26
20
  */
27
- public constructor(
28
- readonly servicePriority: number,
29
- ) {
30
- this.#defaultSyntaxHighlighterService =
31
- new DefaultSyntaxHighlighterService();
21
+ public constructor(readonly servicePriority: number) {
22
+ this.#defaultSyntaxHighlighterService = new DefaultSyntaxHighlighterService();
32
23
  }
33
24
 
34
25
  public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
@@ -39,14 +30,10 @@ export default class SyntaxHighlighterServiceProvider
39
30
  }
40
31
 
41
32
  initService(context: Context): Promise<void> {
42
- const printerService = context.getServiceById(
43
- PRINTER_SERVICE_ID,
44
- ) as PrinterService;
33
+ const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
45
34
 
46
- this.#defaultSyntaxHighlighterService.colorEnabled =
47
- printerService.colorEnabled;
48
- this.#defaultSyntaxHighlighterService.colorFunction = printerService.color
49
- .bind(printerService);
35
+ this.#defaultSyntaxHighlighterService.colorEnabled = printerService.colorEnabled;
36
+ this.#defaultSyntaxHighlighterService.colorFunction = printerService.color.bind(printerService);
50
37
 
51
38
  return Promise.resolve(undefined);
52
39
  }