@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
@@ -46,14 +46,11 @@ describe("CompletionServiceProvider", () => {
46
46
  await provider.getServiceInfo(getCLIConfig());
47
47
 
48
48
  const context = new DefaultContext(getCLIConfig());
49
- context.addServiceInstance(
50
- "@flowscripter/dynamic-cli-framework/prompter-service",
51
- {
52
- promptEnabled: true,
53
- prompt: () => Promise.resolve({ name: "", value: false }),
54
- promptAll: () => Promise.resolve([]),
55
- },
56
- );
49
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
50
+ promptEnabled: true,
51
+ prompt: () => Promise.resolve({ name: "", value: false }),
52
+ promptAll: () => Promise.resolve([]),
53
+ });
57
54
  await expect(provider.initService(context)).resolves.toBeUndefined();
58
55
  });
59
56
 
@@ -63,23 +60,17 @@ describe("CompletionServiceProvider", () => {
63
60
  await provider.getServiceInfo(getCLIConfig());
64
61
 
65
62
  const context = new DefaultContext(getCLIConfig());
66
- context.addServiceInstance(
67
- "@flowscripter/dynamic-cli-framework/prompter-service",
68
- {
69
- promptEnabled: true,
70
- prompt: () => Promise.resolve({ name: "", value: false }),
71
- promptAll: () => Promise.resolve([]),
72
- },
73
- );
74
- context.addServiceInstance(
75
- "@flowscripter/dynamic-cli-framework/key-value-service",
76
- {
77
- hasKey: (key: string) => Promise.resolve(key === "completion-status"),
78
- getKey: () => Promise.resolve("installed"),
79
- setKey: () => Promise.resolve(),
80
- deleteKey: () => Promise.resolve(),
81
- },
82
- );
63
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
64
+ promptEnabled: true,
65
+ prompt: () => Promise.resolve({ name: "", value: false }),
66
+ promptAll: () => Promise.resolve([]),
67
+ });
68
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
69
+ hasKey: (key: string) => Promise.resolve(key === "completion-status"),
70
+ getKey: () => Promise.resolve("installed"),
71
+ setKey: () => Promise.resolve(),
72
+ deleteKey: () => Promise.resolve(),
73
+ });
83
74
  await expect(provider.initService(context)).resolves.toBeUndefined();
84
75
  });
85
76
 
@@ -89,23 +80,17 @@ describe("CompletionServiceProvider", () => {
89
80
  await provider.getServiceInfo(getCLIConfig());
90
81
 
91
82
  const context = new DefaultContext(getCLIConfig());
92
- context.addServiceInstance(
93
- "@flowscripter/dynamic-cli-framework/prompter-service",
94
- {
95
- promptEnabled: true,
96
- prompt: () => Promise.resolve({ name: "", value: false }),
97
- promptAll: () => Promise.resolve([]),
98
- },
99
- );
100
- context.addServiceInstance(
101
- "@flowscripter/dynamic-cli-framework/key-value-service",
102
- {
103
- hasKey: (key: string) => Promise.resolve(key === "completion-status"),
104
- getKey: () => Promise.resolve("declined"),
105
- setKey: () => Promise.resolve(),
106
- deleteKey: () => Promise.resolve(),
107
- },
108
- );
83
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
84
+ promptEnabled: true,
85
+ prompt: () => Promise.resolve({ name: "", value: false }),
86
+ promptAll: () => Promise.resolve([]),
87
+ });
88
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
89
+ hasKey: (key: string) => Promise.resolve(key === "completion-status"),
90
+ getKey: () => Promise.resolve("declined"),
91
+ setKey: () => Promise.resolve(),
92
+ deleteKey: () => Promise.resolve(),
93
+ });
109
94
  await expect(provider.initService(context)).resolves.toBeUndefined();
110
95
  });
111
96
 
@@ -115,23 +100,17 @@ describe("CompletionServiceProvider", () => {
115
100
  await provider.getServiceInfo(getCLIConfig());
116
101
 
117
102
  const context = new DefaultContext(getCLIConfig());
118
- context.addServiceInstance(
119
- "@flowscripter/dynamic-cli-framework/prompter-service",
120
- {
121
- promptEnabled: false,
122
- prompt: () => Promise.resolve({ name: "", value: false }),
123
- promptAll: () => Promise.resolve([]),
124
- },
125
- );
126
- context.addServiceInstance(
127
- "@flowscripter/dynamic-cli-framework/key-value-service",
128
- {
129
- hasKey: () => Promise.resolve(false),
130
- getKey: () => Promise.resolve(""),
131
- setKey: () => Promise.resolve(),
132
- deleteKey: () => Promise.resolve(),
133
- },
134
- );
103
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
104
+ promptEnabled: false,
105
+ prompt: () => Promise.resolve({ name: "", value: false }),
106
+ promptAll: () => Promise.resolve([]),
107
+ });
108
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
109
+ hasKey: () => Promise.resolve(false),
110
+ getKey: () => Promise.resolve(""),
111
+ setKey: () => Promise.resolve(),
112
+ deleteKey: () => Promise.resolve(),
113
+ });
135
114
  await expect(provider.initService(context)).resolves.toBeUndefined();
136
115
  });
137
116
 
@@ -144,26 +123,20 @@ describe("CompletionServiceProvider", () => {
144
123
  const context = new DefaultContext(getCLIConfig());
145
124
 
146
125
  let promptCalled = false;
147
- context.addServiceInstance(
148
- "@flowscripter/dynamic-cli-framework/prompter-service",
149
- {
150
- promptEnabled: true,
151
- prompt: () => {
152
- promptCalled = true;
153
- return Promise.resolve({ name: "", value: false });
154
- },
155
- promptAll: () => Promise.resolve([]),
126
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
127
+ promptEnabled: true,
128
+ prompt: () => {
129
+ promptCalled = true;
130
+ return Promise.resolve({ name: "", value: false });
156
131
  },
157
- );
158
- context.addServiceInstance(
159
- "@flowscripter/dynamic-cli-framework/key-value-service",
160
- {
161
- hasKey: () => Promise.resolve(false),
162
- getKey: () => Promise.resolve(""),
163
- setKey: () => Promise.resolve(),
164
- deleteKey: () => Promise.resolve(),
165
- },
166
- );
132
+ promptAll: () => Promise.resolve([]),
133
+ });
134
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
135
+ hasKey: () => Promise.resolve(false),
136
+ getKey: () => Promise.resolve(""),
137
+ setKey: () => Promise.resolve(),
138
+ deleteKey: () => Promise.resolve(),
139
+ });
167
140
 
168
141
  await provider.initService(context);
169
142
  expect(promptCalled).toBe(false);
@@ -179,28 +152,21 @@ describe("CompletionServiceProvider", () => {
179
152
 
180
153
  let storedKey = "";
181
154
  let storedValue = "";
182
- context.addServiceInstance(
183
- "@flowscripter/dynamic-cli-framework/prompter-service",
184
- {
185
- promptEnabled: true,
186
- prompt: () =>
187
- Promise.resolve({ name: "enable-completion", value: false }),
188
- promptAll: () => Promise.resolve([]),
189
- },
190
- );
191
- context.addServiceInstance(
192
- "@flowscripter/dynamic-cli-framework/key-value-service",
193
- {
194
- hasKey: () => Promise.resolve(false),
195
- getKey: () => Promise.resolve(""),
196
- setKey: (key: string, value: string) => {
197
- storedKey = key;
198
- storedValue = value;
199
- return Promise.resolve();
200
- },
201
- deleteKey: () => Promise.resolve(),
155
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
156
+ promptEnabled: true,
157
+ prompt: () => Promise.resolve({ name: "enable-completion", value: false }),
158
+ promptAll: () => Promise.resolve([]),
159
+ });
160
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
161
+ hasKey: () => Promise.resolve(false),
162
+ getKey: () => Promise.resolve(""),
163
+ setKey: (key: string, value: string) => {
164
+ storedKey = key;
165
+ storedValue = value;
166
+ return Promise.resolve();
202
167
  },
203
- );
168
+ deleteKey: () => Promise.resolve(),
169
+ });
204
170
 
205
171
  await provider.initService(context);
206
172
  expect(storedKey).toEqual("completion-status");
@@ -209,8 +175,7 @@ describe("CompletionServiceProvider", () => {
209
175
 
210
176
  test("initService skips shell prompt when only one shell detected", async () => {
211
177
  const service = new DefaultCompletionService();
212
- service.validateShellEnvironment = (shell) =>
213
- Promise.resolve(shell === "bash");
178
+ service.validateShellEnvironment = (shell) => Promise.resolve(shell === "bash");
214
179
  const provider = new CompletionServiceProvider(60, service);
215
180
  await provider.getServiceInfo(getCLIConfig());
216
181
 
@@ -219,53 +184,42 @@ describe("CompletionServiceProvider", () => {
219
184
  const storedEntries: Array<{ key: string; value: string }> = [];
220
185
  const promptNames: string[] = [];
221
186
 
222
- context.addServiceInstance(
223
- "@flowscripter/dynamic-cli-framework/prompter-service",
224
- {
225
- promptEnabled: true,
226
- prompt: (promptDef: { name: string }) => {
227
- promptNames.push(promptDef.name);
228
- return Promise.resolve({
229
- name: promptDef.name,
230
- value: true,
231
- });
232
- },
233
- promptAll: () => Promise.resolve([]),
187
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
188
+ promptEnabled: true,
189
+ prompt: (promptDef: { name: string }) => {
190
+ promptNames.push(promptDef.name);
191
+ return Promise.resolve({
192
+ name: promptDef.name,
193
+ value: true,
194
+ });
234
195
  },
235
- );
236
- context.addServiceInstance(
237
- "@flowscripter/dynamic-cli-framework/key-value-service",
238
- {
239
- hasKey: () => Promise.resolve(false),
240
- getKey: () => Promise.resolve(""),
241
- setKey: (key: string, value: string) => {
242
- storedEntries.push({ key, value });
243
- return Promise.resolve();
244
- },
245
- deleteKey: () => Promise.resolve(),
196
+ promptAll: () => Promise.resolve([]),
197
+ });
198
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
199
+ hasKey: () => Promise.resolve(false),
200
+ getKey: () => Promise.resolve(""),
201
+ setKey: (key: string, value: string) => {
202
+ storedEntries.push({ key, value });
203
+ return Promise.resolve();
246
204
  },
247
- );
205
+ deleteKey: () => Promise.resolve(),
206
+ });
248
207
 
249
208
  let infoMessage = "";
250
- context.addServiceInstance(
251
- "@flowscripter/dynamic-cli-framework/printer-service",
252
- {
253
- info: (msg: string) => {
254
- infoMessage = msg;
255
- return Promise.resolve();
256
- },
257
- warn: () => Promise.resolve(),
258
- error: () => Promise.resolve(),
259
- print: () => Promise.resolve(),
209
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/printer-service", {
210
+ info: (msg: string) => {
211
+ infoMessage = msg;
212
+ return Promise.resolve();
260
213
  },
261
- );
214
+ warn: () => Promise.resolve(),
215
+ error: () => Promise.resolve(),
216
+ print: () => Promise.resolve(),
217
+ });
262
218
 
263
219
  await provider.initService(context);
264
220
 
265
221
  expect(promptNames).toEqual(["enable-completion"]);
266
- const statusEntry = storedEntries.find(
267
- (e) => e.key === "completion-status",
268
- );
222
+ const statusEntry = storedEntries.find((e) => e.key === "completion-status");
269
223
  expect(statusEntry).toBeDefined();
270
224
  expect(statusEntry!.value).toEqual("installed");
271
225
  expect(infoMessage).toContain("Shell completion installed for bash");
@@ -286,51 +240,39 @@ describe("CompletionServiceProvider", () => {
286
240
  promptResponses.set("shell-type", "zsh");
287
241
 
288
242
  let shellPromptDefault: unknown;
289
- context.addServiceInstance(
290
- "@flowscripter/dynamic-cli-framework/prompter-service",
291
- {
292
- promptEnabled: true,
293
- prompt: (promptDef: {
294
- name: string;
295
- defaultOption?: { returnedValue: unknown };
296
- }) => {
297
- if (promptDef.name === "shell-type") {
298
- shellPromptDefault = promptDef.defaultOption;
299
- }
300
- return Promise.resolve({
301
- name: promptDef.name,
302
- value: promptResponses.get(promptDef.name),
303
- });
304
- },
305
- promptAll: () => Promise.resolve([]),
243
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
244
+ promptEnabled: true,
245
+ prompt: (promptDef: { name: string; defaultOption?: { returnedValue: unknown } }) => {
246
+ if (promptDef.name === "shell-type") {
247
+ shellPromptDefault = promptDef.defaultOption;
248
+ }
249
+ return Promise.resolve({
250
+ name: promptDef.name,
251
+ value: promptResponses.get(promptDef.name),
252
+ });
306
253
  },
307
- );
308
- context.addServiceInstance(
309
- "@flowscripter/dynamic-cli-framework/key-value-service",
310
- {
311
- hasKey: () => Promise.resolve(false),
312
- getKey: () => Promise.resolve(""),
313
- setKey: (key: string, value: string) => {
314
- storedEntries.push({ key, value });
315
- return Promise.resolve();
316
- },
317
- deleteKey: () => Promise.resolve(),
254
+ promptAll: () => Promise.resolve([]),
255
+ });
256
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
257
+ hasKey: () => Promise.resolve(false),
258
+ getKey: () => Promise.resolve(""),
259
+ setKey: (key: string, value: string) => {
260
+ storedEntries.push({ key, value });
261
+ return Promise.resolve();
318
262
  },
319
- );
263
+ deleteKey: () => Promise.resolve(),
264
+ });
320
265
 
321
266
  let infoMessage = "";
322
- context.addServiceInstance(
323
- "@flowscripter/dynamic-cli-framework/printer-service",
324
- {
325
- info: (msg: string) => {
326
- infoMessage = msg;
327
- return Promise.resolve();
328
- },
329
- warn: () => Promise.resolve(),
330
- error: () => Promise.resolve(),
331
- print: () => Promise.resolve(),
267
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/printer-service", {
268
+ info: (msg: string) => {
269
+ infoMessage = msg;
270
+ return Promise.resolve();
332
271
  },
333
- );
272
+ warn: () => Promise.resolve(),
273
+ error: () => Promise.resolve(),
274
+ print: () => Promise.resolve(),
275
+ });
334
276
 
335
277
  await provider.initService(context);
336
278
 
@@ -338,9 +280,7 @@ describe("CompletionServiceProvider", () => {
338
280
  displayValue: "bash",
339
281
  returnedValue: "bash",
340
282
  });
341
- const statusEntry = storedEntries.find(
342
- (e) => e.key === "completion-status",
343
- );
283
+ const statusEntry = storedEntries.find((e) => e.key === "completion-status");
344
284
  expect(statusEntry).toBeDefined();
345
285
  expect(statusEntry!.value).toEqual("installed");
346
286
  expect(infoMessage).toContain("Shell completion installed for zsh");
@@ -359,41 +299,32 @@ describe("CompletionServiceProvider", () => {
359
299
 
360
300
  const context = new DefaultContext(getCLIConfig());
361
301
 
362
- context.addServiceInstance(
363
- "@flowscripter/dynamic-cli-framework/prompter-service",
364
- {
365
- promptEnabled: true,
366
- prompt: (promptDef: { name: string }) =>
367
- Promise.resolve({
368
- name: promptDef.name,
369
- value: promptDef.name === "enable-completion" ? true : "bash",
370
- }),
371
- promptAll: () => Promise.resolve([]),
372
- },
373
- );
374
- context.addServiceInstance(
375
- "@flowscripter/dynamic-cli-framework/key-value-service",
376
- {
377
- hasKey: () => Promise.resolve(false),
378
- getKey: () => Promise.resolve(""),
379
- setKey: () => Promise.resolve(),
380
- deleteKey: () => Promise.resolve(),
381
- },
382
- );
302
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/prompter-service", {
303
+ promptEnabled: true,
304
+ prompt: (promptDef: { name: string }) =>
305
+ Promise.resolve({
306
+ name: promptDef.name,
307
+ value: promptDef.name === "enable-completion" ? true : "bash",
308
+ }),
309
+ promptAll: () => Promise.resolve([]),
310
+ });
311
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/key-value-service", {
312
+ hasKey: () => Promise.resolve(false),
313
+ getKey: () => Promise.resolve(""),
314
+ setKey: () => Promise.resolve(),
315
+ deleteKey: () => Promise.resolve(),
316
+ });
383
317
 
384
318
  let errorMessage = "";
385
- context.addServiceInstance(
386
- "@flowscripter/dynamic-cli-framework/printer-service",
387
- {
388
- info: () => Promise.resolve(),
389
- warn: () => Promise.resolve(),
390
- error: (msg: string) => {
391
- errorMessage = msg;
392
- return Promise.resolve();
393
- },
394
- print: () => Promise.resolve(),
319
+ context.addServiceInstance("@flowscripter/dynamic-cli-framework/printer-service", {
320
+ info: () => Promise.resolve(),
321
+ warn: () => Promise.resolve(),
322
+ error: (msg: string) => {
323
+ errorMessage = msg;
324
+ return Promise.resolve();
395
325
  },
396
- );
326
+ print: () => Promise.resolve(),
327
+ });
397
328
 
398
329
  await provider.initService(context);
399
330
  expect(errorMessage).toContain("Failed to install completion");
@@ -26,11 +26,7 @@ function makeSubCommand(
26
26
  };
27
27
  }
28
28
 
29
- function makeGroupCommand(
30
- name: string,
31
- description: string,
32
- members: SubCommand[],
33
- ): GroupCommand {
29
+ function makeGroupCommand(name: string, description: string, members: SubCommand[]): GroupCommand {
34
30
  return {
35
31
  name,
36
32
  description,
@@ -40,10 +36,7 @@ function makeGroupCommand(
40
36
  };
41
37
  }
42
38
 
43
- function makeGlobalCommand(
44
- name: string,
45
- description: string,
46
- ): GlobalCommand {
39
+ function makeGlobalCommand(name: string, description: string): GlobalCommand {
47
40
  return {
48
41
  name,
49
42
  description,
@@ -53,10 +46,7 @@ function makeGlobalCommand(
53
46
  };
54
47
  }
55
48
 
56
- function makeGlobalModifierCommand(
57
- name: string,
58
- description: string,
59
- ): GlobalModifierCommand {
49
+ function makeGlobalModifierCommand(name: string, description: string): GlobalModifierCommand {
60
50
  return {
61
51
  name,
62
52
  description,
@@ -69,9 +59,7 @@ function makeGlobalModifierCommand(
69
59
 
70
60
  describe("DefaultCompletionService", () => {
71
61
  function createService(
72
- commands: Array<
73
- SubCommand | GroupCommand | GlobalCommand | GlobalModifierCommand
74
- >,
62
+ commands: Array<SubCommand | GroupCommand | GlobalCommand | GlobalModifierCommand>,
75
63
  ): DefaultCompletionService {
76
64
  const service = new DefaultCompletionService();
77
65
  const registry = new DefaultCommandRegistry(commands);
@@ -81,11 +69,7 @@ describe("DefaultCompletionService", () => {
81
69
 
82
70
  test("returns empty completions if no registry set", async () => {
83
71
  const service = new DefaultCompletionService();
84
- const result = await service.generateCompletions(
85
- ShellType.BASH,
86
- "mycli ",
87
- 6,
88
- );
72
+ const result = await service.generateCompletions(ShellType.BASH, "mycli ", 6);
89
73
  expect(result).toEqual([]);
90
74
  });
91
75
 
@@ -96,11 +80,7 @@ describe("DefaultCompletionService", () => {
96
80
  makeSubCommand("run", "Run something"),
97
81
  ]);
98
82
 
99
- const result = await service.generateCompletions(
100
- ShellType.BASH,
101
- "mycli h",
102
- 7,
103
- );
83
+ const result = await service.generateCompletions(ShellType.BASH, "mycli h", 7);
104
84
  expect(result.length).toEqual(2);
105
85
  expect(result.map((r) => r.value)).toContain("help");
106
86
  expect(result.map((r) => r.value)).toContain("history");
@@ -112,11 +92,7 @@ describe("DefaultCompletionService", () => {
112
92
  makeSubCommand("run", "Run something"),
113
93
  ]);
114
94
 
115
- const result = await service.generateCompletions(
116
- ShellType.BASH,
117
- "mycli ",
118
- 6,
119
- );
95
+ const result = await service.generateCompletions(ShellType.BASH, "mycli ", 6);
120
96
  expect(result.map((r) => r.value)).toContain("help");
121
97
  expect(result.map((r) => r.value)).toContain("run");
122
98
  });
@@ -126,18 +102,10 @@ describe("DefaultCompletionService", () => {
126
102
  makeSubCommand("integration", "Install completion"),
127
103
  makeSubCommand("complete", "Generate completions"),
128
104
  ];
129
- const group = makeGroupCommand(
130
- "completions",
131
- "Completion management",
132
- members,
133
- );
105
+ const group = makeGroupCommand("completions", "Completion management", members);
134
106
  const service = createService([group]);
135
107
 
136
- const result = await service.generateCompletions(
137
- ShellType.BASH,
138
- "mycli comp",
139
- 10,
140
- );
108
+ const result = await service.generateCompletions(ShellType.BASH, "mycli comp", 10);
141
109
  const values = result.map((r) => r.value);
142
110
  expect(values).toContain("completions");
143
111
  expect(values).toContain("completions:integration");
@@ -149,18 +117,10 @@ describe("DefaultCompletionService", () => {
149
117
  makeSubCommand("integration", "Install completion"),
150
118
  makeSubCommand("complete", "Generate completions"),
151
119
  ];
152
- const group = makeGroupCommand(
153
- "completions",
154
- "Completion management",
155
- members,
156
- );
120
+ const group = makeGroupCommand("completions", "Completion management", members);
157
121
  const service = createService([group]);
158
122
 
159
- const result = await service.generateCompletions(
160
- ShellType.BASH,
161
- "mycli completions:i",
162
- 19,
163
- );
123
+ const result = await service.generateCompletions(ShellType.BASH, "mycli completions:i", 19);
164
124
  const values = result.map((r) => r.value);
165
125
  expect(values).toContain("completions:integration");
166
126
  expect(values).not.toContain("completions:complete");
@@ -184,11 +144,7 @@ describe("DefaultCompletionService", () => {
184
144
  ]);
185
145
  const service = createService([cmd]);
186
146
 
187
- const result = await service.generateCompletions(
188
- ShellType.BASH,
189
- "mycli deploy --t",
190
- 16,
191
- );
147
+ const result = await service.generateCompletions(ShellType.BASH, "mycli deploy --t", 16);
192
148
  const values = result.map((r) => r.value);
193
149
  expect(values).toContain("--target");
194
150
  });
@@ -205,29 +161,18 @@ describe("DefaultCompletionService", () => {
205
161
  ]);
206
162
  const service = createService([cmd]);
207
163
 
208
- const result = await service.generateCompletions(
209
- ShellType.BASH,
210
- "mycli deploy --env st",
211
- 21,
212
- );
164
+ const result = await service.generateCompletions(ShellType.BASH, "mycli deploy --env st", 21);
213
165
  const values = result.map((r) => r.value);
214
166
  expect(values).toContain("staging");
215
167
  expect(values).not.toContain("production");
216
168
  });
217
169
 
218
170
  test("completes global modifier commands with -- prefix", async () => {
219
- const modifier = makeGlobalModifierCommand(
220
- "verbose",
221
- "Enable verbose output",
222
- );
171
+ const modifier = makeGlobalModifierCommand("verbose", "Enable verbose output");
223
172
  const cmd = makeSubCommand("run", "Run something");
224
173
  const service = createService([modifier, cmd]);
225
174
 
226
- const result = await service.generateCompletions(
227
- ShellType.BASH,
228
- "mycli --v",
229
- 9,
230
- );
175
+ const result = await service.generateCompletions(ShellType.BASH, "mycli --v", 9);
231
176
  const values = result.map((r) => r.value);
232
177
  expect(values).toContain("--verbose");
233
178
  });
@@ -237,11 +182,7 @@ describe("DefaultCompletionService", () => {
237
182
  const cmd = makeSubCommand("run", "Run something");
238
183
  const service = createService([global, cmd]);
239
184
 
240
- const result = await service.generateCompletions(
241
- ShellType.BASH,
242
- "mycli --ver",
243
- 11,
244
- );
185
+ const result = await service.generateCompletions(ShellType.BASH, "mycli --ver", 11);
245
186
  const values = result.map((r) => r.value);
246
187
  expect(values).toContain("--version");
247
188
  });
@@ -268,10 +209,7 @@ describe("DefaultCompletionService", () => {
268
209
 
269
210
  test("parseCompletionContext delegates to shell handler", () => {
270
211
  const service = new DefaultCompletionService();
271
- const result = service.parseCompletionContext(ShellType.BASH, [
272
- "mycli help",
273
- "10",
274
- ]);
212
+ const result = service.parseCompletionContext(ShellType.BASH, ["mycli help", "10"]);
275
213
  expect(result.line).toEqual("mycli help");
276
214
  expect(result.cursorPosition).toEqual(10);
277
215
  });
@@ -8,9 +8,7 @@ describe("FishShellHandler", () => {
8
8
 
9
9
  test("getDefaultConfigPath returns fish config.fish", () => {
10
10
  const configPath = handler.getDefaultConfigPath();
11
- expect(configPath).toEndWith(
12
- path.sep + path.join(".config", "fish", "config.fish"),
13
- );
11
+ expect(configPath).toEndWith(path.sep + path.join(".config", "fish", "config.fish"));
14
12
  });
15
13
 
16
14
  test("getBootstrapScript generates correct complete command", () => {