@flowscripter/dynamic-cli-framework 1.0.0

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 (133) hide show
  1. package/.github/workflows/check-bun-dependencies.yml +9 -0
  2. package/.github/workflows/lint-pr-message.yml +11 -0
  3. package/.github/workflows/release-bun-library.yml +8 -0
  4. package/.github/workflows/validate-bun-library-pr.yml +8 -0
  5. package/LICENSE +21 -0
  6. package/README.md +1475 -0
  7. package/bun.lock +63 -0
  8. package/index.ts +89 -0
  9. package/package.json +23 -0
  10. package/src/api/CLI.ts +17 -0
  11. package/src/api/CLIConfig.ts +19 -0
  12. package/src/api/Context.ts +25 -0
  13. package/src/api/RunResult.ts +142 -0
  14. package/src/api/argument/Argument.ts +36 -0
  15. package/src/api/argument/ArgumentValueTypes.ts +87 -0
  16. package/src/api/argument/ComplexOption.ts +31 -0
  17. package/src/api/argument/GlobalCommandArgument.ts +17 -0
  18. package/src/api/argument/Option.ts +32 -0
  19. package/src/api/argument/Positional.ts +27 -0
  20. package/src/api/argument/SubCommandArgument.ts +20 -0
  21. package/src/api/command/Command.ts +22 -0
  22. package/src/api/command/GlobalCommand.ts +33 -0
  23. package/src/api/command/GlobalModifierCommand.ts +12 -0
  24. package/src/api/command/GroupCommand.ts +20 -0
  25. package/src/api/command/SubCommand.ts +41 -0
  26. package/src/api/command/UsageExample.ts +21 -0
  27. package/src/api/service/ServiceProvider.ts +52 -0
  28. package/src/api/service/core/AsciiBannerGeneratorService.ts +35 -0
  29. package/src/api/service/core/KeyValueService.ts +28 -0
  30. package/src/api/service/core/PrinterService.ts +266 -0
  31. package/src/api/service/core/ShutdownService.ts +12 -0
  32. package/src/api/service/core/SyntaxHighlighterService.ts +42 -0
  33. package/src/cli/BaseCLI.ts +312 -0
  34. package/src/cli/DefaultRuntimeCLI.ts +54 -0
  35. package/src/command/MultiCommandCliHelpCommand.ts +394 -0
  36. package/src/command/SingleCommandCliHelpCommand.ts +183 -0
  37. package/src/command/UsageCommand.ts +35 -0
  38. package/src/command/VersionCommand.ts +22 -0
  39. package/src/launcher.ts +127 -0
  40. package/src/runtime/DefaultContext.ts +32 -0
  41. package/src/runtime/argument/ArgumentTypeGuards.ts +8 -0
  42. package/src/runtime/command/CommandTypeGuards.ts +30 -0
  43. package/src/runtime/command/CommandValidator.ts +549 -0
  44. package/src/runtime/parser.ts +219 -0
  45. package/src/runtime/registry/CommandRegistry.ts +121 -0
  46. package/src/runtime/registry/DefaultCommandRegistry.ts +318 -0
  47. package/src/runtime/registry/DefaultServiceProviderRegistry.ts +26 -0
  48. package/src/runtime/registry/ServiceProviderRegistry.ts +11 -0
  49. package/src/runtime/runner.ts +697 -0
  50. package/src/runtime/scanner.ts +417 -0
  51. package/src/runtime/values/ValuePopulationResult.ts +41 -0
  52. package/src/runtime/values/argumentValueMerge.ts +201 -0
  53. package/src/runtime/values/argumentValueValidation.ts +610 -0
  54. package/src/runtime/values/globalCommandValuePopulation.ts +96 -0
  55. package/src/runtime/values/subCommandValuePopulation.ts +680 -0
  56. package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +45 -0
  57. package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +38 -0
  58. package/src/service/asciiBannerGenerator/standard.flf.json +3 -0
  59. package/src/service/banner/BannerServiceProvider.ts +99 -0
  60. package/src/service/banner/command/NoBannerCommand.ts +42 -0
  61. package/src/service/configuration/ConfigurationServiceProvider.ts +571 -0
  62. package/src/service/configuration/DefaultKeyValueService.ts +60 -0
  63. package/src/service/configuration/command/ConfigCommand.ts +43 -0
  64. package/src/service/configuration/command/DumpConfigCommand.ts +47 -0
  65. package/src/service/printer/DefaultPrinterService.ts +256 -0
  66. package/src/service/printer/PrinterServiceProvider.ts +61 -0
  67. package/src/service/printer/command/DarkModeCommand.ts +43 -0
  68. package/src/service/printer/command/LogLevelCommand.ts +68 -0
  69. package/src/service/printer/command/NoColorCommand.ts +43 -0
  70. package/src/service/printer/terminal/Ansi.ts +10 -0
  71. package/src/service/printer/terminal/Color.ts +14 -0
  72. package/src/service/printer/terminal/Progress.ts +373 -0
  73. package/src/service/printer/terminal/Spinner.ts +100 -0
  74. package/src/service/printer/terminal/Styler.ts +5 -0
  75. package/src/service/printer/terminal/Terminal.ts +8 -0
  76. package/src/service/printer/terminal/Theme.ts +34 -0
  77. package/src/service/printer/terminal/TtyStyler.ts +39 -0
  78. package/src/service/printer/terminal/TtyTerminal.ts +65 -0
  79. package/src/service/shutdown/DefaultShutdownService.ts +9 -0
  80. package/src/service/shutdown/ShutdownServiceProvider.ts +55 -0
  81. package/src/service/syntaxHighlighter/DefaultSyntaxHighlighterService.ts +52 -0
  82. package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +51 -0
  83. package/src/util/configHelper.ts +95 -0
  84. package/src/util/envVarHelper.ts +338 -0
  85. package/src/util/helpHelper.ts +751 -0
  86. package/src/util/logger.ts +84 -0
  87. package/src/util/runnerHelper.ts +112 -0
  88. package/tests/cli/BaseCLI.test.ts +344 -0
  89. package/tests/command/MultiCommandCliHelpCommand.test.ts +650 -0
  90. package/tests/command/SingleCommandCliHelpCommand.test.ts +384 -0
  91. package/tests/command/UsageCommand.test.ts +53 -0
  92. package/tests/command/VersionCommand.test.ts +36 -0
  93. package/tests/fixtures/CLIConfig.ts +9 -0
  94. package/tests/fixtures/Command.ts +229 -0
  95. package/tests/fixtures/CommandRegistry.ts +8 -0
  96. package/tests/fixtures/ConfigurationServiceProvider.ts +28 -0
  97. package/tests/fixtures/Context.ts +33 -0
  98. package/tests/fixtures/ServiceProviderRegistry.ts +16 -0
  99. package/tests/fixtures/StreamString.ts +37 -0
  100. package/tests/fixtures/util.ts +41 -0
  101. package/tests/runtime/DefaultContext.test.ts +20 -0
  102. package/tests/runtime/argument/ArgumentTypeGuards.test.ts +49 -0
  103. package/tests/runtime/command/CommandTypeGuards.test.ts +43 -0
  104. package/tests/runtime/command/CommandValidator.test.ts +816 -0
  105. package/tests/runtime/parser.test.ts +766 -0
  106. package/tests/runtime/registry/DefaultCommandRegistry.test.ts +166 -0
  107. package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +42 -0
  108. package/tests/runtime/runner.test.ts +1298 -0
  109. package/tests/runtime/scanner.test.ts +1113 -0
  110. package/tests/runtime/values/argumentValueMerge.test.ts +314 -0
  111. package/tests/runtime/values/argumentValueValidation.test.ts +1020 -0
  112. package/tests/runtime/values/globalCommandValuePopulation.test.ts +662 -0
  113. package/tests/runtime/values/subCommandValuePopulation.test.ts +2658 -0
  114. package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +22 -0
  115. package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +70 -0
  116. package/tests/service/asciiBannerGenerator/__snapshots__/DefaultAsciiBannerGeneratorService.test.ts.snap +22 -0
  117. package/tests/service/asciiBannerGenerator/small.flf.json +3 -0
  118. package/tests/service/configuration/ConfigurationServiceProvider.test.ts +249 -0
  119. package/tests/service/configuration/DefaultKeyValueService.test.ts +65 -0
  120. package/tests/service/launchBanner/BannerServiceProvider.test.ts +49 -0
  121. package/tests/service/launchBanner/__snapshots__/BannerServiceProvider.test.ts.snap +3 -0
  122. package/tests/service/launchBanner/command/NoBannerCommand.test.ts +21 -0
  123. package/tests/service/printer/DefaultPrinterService.test.ts +409 -0
  124. package/tests/service/printer/PrinterServiceProvider.test.ts +29 -0
  125. package/tests/service/printer/command/LogLevelCommand.test.ts +58 -0
  126. package/tests/service/printer/terminal/Progress.test.ts +40 -0
  127. package/tests/service/printer/terminal/Spinner.test.ts +57 -0
  128. package/tests/service/shutdown/ShutdownServiceProvider.test.ts +13 -0
  129. package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +123 -0
  130. package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +41 -0
  131. package/tests/util/configHelper.test.ts +275 -0
  132. package/tests/util/envVarHelper.test.ts +318 -0
  133. package/tests/util/logger.test.ts +10 -0
@@ -0,0 +1,1298 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import DefaultCommandRegistry from "../../src/runtime/registry/DefaultCommandRegistry.ts";
3
+ import {
4
+ getGlobalCommandWithShortAlias,
5
+ getGlobalModifierCommandWithArgument,
6
+ getGroupCommand,
7
+ getSubCommand,
8
+ getSubCommandWithOption,
9
+ } from "../fixtures/Command.ts";
10
+ import { run } from "../../src/runtime/runner.ts";
11
+ import { RunState } from "../../src/api/RunResult.ts";
12
+ import { getContext } from "../fixtures/Context.ts";
13
+ import { getServiceProviderRegistry } from "../fixtures/ServiceProviderRegistry.ts";
14
+ import { expectStringIncludes } from "../fixtures/util.ts";
15
+ import { getConfigurationServiceProvider } from "../fixtures/ConfigurationServiceProvider.ts";
16
+ import type GlobalModifierCommand from "../../src/api/command/GlobalModifierCommand.ts";
17
+ import {
18
+ type ArgumentSingleValueType,
19
+ type ArgumentValues,
20
+ ArgumentValueTypeName,
21
+ ComplexValueTypeName,
22
+ } from "../../src/api/argument/ArgumentValueTypes.ts";
23
+ import WritableStreamString from "../fixtures/StreamString.ts";
24
+ import StreamString from "../fixtures/StreamString.ts";
25
+ describe("runner Tests", () => {
26
+ test("Sub-Command run", async () => {
27
+ let hasRun = false;
28
+
29
+ const option = {
30
+ name: "foo",
31
+ type: ArgumentValueTypeName.STRING,
32
+ };
33
+ const command = getSubCommand("command", [option]);
34
+
35
+ command.execute = (): Promise<void> => {
36
+ hasRun = true;
37
+
38
+ return Promise.resolve();
39
+ };
40
+
41
+ const commandRegistry = new DefaultCommandRegistry([command]);
42
+
43
+ const runResult = await run(
44
+ ["command", "--foo", "bar"],
45
+ commandRegistry,
46
+ getServiceProviderRegistry(),
47
+ undefined,
48
+ getContext(new WritableStreamString()),
49
+ );
50
+
51
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
52
+ expect(hasRun).toBeTrue();
53
+ });
54
+
55
+ test("Global Modifier run", async () => {
56
+ let modifierHasRun = false;
57
+ let subHasRun = false;
58
+
59
+ const globalModifierCommand = getGlobalModifierCommandWithArgument(
60
+ "modifierCommand",
61
+ "c",
62
+ 1,
63
+ {
64
+ type: ArgumentValueTypeName.STRING,
65
+ },
66
+ );
67
+ const subCommand = getSubCommand("subCommand", [], []);
68
+
69
+ globalModifierCommand.execute = (): Promise<void> => {
70
+ modifierHasRun = true;
71
+ return Promise.resolve();
72
+ };
73
+ subCommand.execute = (): Promise<void> => {
74
+ subHasRun = true;
75
+ return Promise.resolve();
76
+ };
77
+
78
+ const commandRegistry = new DefaultCommandRegistry([
79
+ globalModifierCommand,
80
+ subCommand,
81
+ ]);
82
+ let runResult = await run(
83
+ ["--modifierCommand=bar", "subCommand"],
84
+ commandRegistry,
85
+ getServiceProviderRegistry(),
86
+ undefined,
87
+ getContext(new WritableStreamString()),
88
+ );
89
+
90
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
91
+ expect(modifierHasRun).toBeTrue();
92
+ expect(subHasRun).toBeTrue();
93
+
94
+ modifierHasRun = false;
95
+ subHasRun = false;
96
+
97
+ runResult = await run(
98
+ ["-c", "bar", "subCommand"],
99
+ commandRegistry,
100
+ getServiceProviderRegistry(),
101
+ undefined,
102
+ getContext(new WritableStreamString()),
103
+ );
104
+
105
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
106
+ expect(modifierHasRun).toBeTrue();
107
+ expect(subHasRun).toBeTrue();
108
+ });
109
+
110
+ test("Global Command run", async () => {
111
+ let hasRun = false;
112
+
113
+ const command = getGlobalCommandWithShortAlias("command", "c", {
114
+ type: ArgumentValueTypeName.STRING,
115
+ });
116
+
117
+ command.execute = (): Promise<void> => {
118
+ hasRun = true;
119
+ return Promise.resolve();
120
+ };
121
+
122
+ const commandRegistry = new DefaultCommandRegistry([command]);
123
+ let runResult = await run(
124
+ ["--command=bar"],
125
+ commandRegistry,
126
+ getServiceProviderRegistry(),
127
+ undefined,
128
+ getContext(new WritableStreamString()),
129
+ );
130
+
131
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
132
+ expect(hasRun).toBeTrue();
133
+
134
+ hasRun = false;
135
+
136
+ runResult = await run(
137
+ ["-c", "bar"],
138
+ commandRegistry,
139
+ getServiceProviderRegistry(),
140
+ undefined,
141
+ getContext(new WritableStreamString()),
142
+ );
143
+
144
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
145
+ expect(hasRun).toBeTrue();
146
+ });
147
+
148
+ test("Group Command run", async () => {
149
+ let subHasRun = false;
150
+ let groupHasRun = false;
151
+
152
+ const subCommand = getSubCommand("command", [], []);
153
+ const groupCommand = getGroupCommand("group", [subCommand]);
154
+
155
+ subCommand.execute = (): Promise<void> => {
156
+ subHasRun = true;
157
+ return Promise.resolve();
158
+ };
159
+ groupCommand.execute = (): Promise<void> => {
160
+ groupHasRun = true;
161
+ return Promise.resolve();
162
+ };
163
+
164
+ const commandRegistry = new DefaultCommandRegistry([groupCommand]);
165
+ let runResult = await run(
166
+ ["group", "command"],
167
+ commandRegistry,
168
+ getServiceProviderRegistry(),
169
+ undefined,
170
+ getContext(new WritableStreamString()),
171
+ );
172
+
173
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
174
+ expect(groupHasRun).toBeTrue();
175
+ expect(subHasRun).toBeTrue();
176
+
177
+ runResult = await run(
178
+ ["group:command"],
179
+ commandRegistry,
180
+ getServiceProviderRegistry(),
181
+ undefined,
182
+ getContext(new WritableStreamString()),
183
+ );
184
+
185
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
186
+ expect(groupHasRun).toBeTrue();
187
+ expect(subHasRun).toBeTrue();
188
+ });
189
+
190
+ test("Global modifier and sub-command run", async () => {
191
+ let modifierHasRun = false;
192
+ let subHasRun = false;
193
+
194
+ const modifierCommand = getGlobalModifierCommandWithArgument(
195
+ "modifier",
196
+ "m",
197
+ 1,
198
+ {
199
+ type: ArgumentValueTypeName.STRING,
200
+ },
201
+ );
202
+ const option = {
203
+ name: "foo",
204
+ type: ArgumentValueTypeName.STRING,
205
+ shortAlias: "f",
206
+ };
207
+ const subCommand = getSubCommand("command", [option], []);
208
+
209
+ modifierCommand.execute = (): Promise<void> => {
210
+ modifierHasRun = true;
211
+ return Promise.resolve();
212
+ };
213
+ subCommand.execute = (): Promise<void> => {
214
+ subHasRun = true;
215
+ return Promise.resolve();
216
+ };
217
+
218
+ const commandRegistry = new DefaultCommandRegistry([
219
+ modifierCommand,
220
+ subCommand,
221
+ ]);
222
+ const runResult = await run(
223
+ ["--modifier=bar", "command", "--foo", "bar"],
224
+ commandRegistry,
225
+ getServiceProviderRegistry(),
226
+ undefined,
227
+ getContext(new WritableStreamString()),
228
+ );
229
+
230
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
231
+ expect(modifierHasRun).toBeTrue();
232
+ expect(subHasRun).toBeTrue();
233
+ });
234
+
235
+ test("Global modifier and global run", async () => {
236
+ let modifierHasRun = false;
237
+ let globalHasRun = false;
238
+
239
+ const modifierCommand = getGlobalModifierCommandWithArgument(
240
+ "modifier",
241
+ "m",
242
+ 1,
243
+ {
244
+ type: ArgumentValueTypeName.STRING,
245
+ },
246
+ );
247
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g", {
248
+ type: ArgumentValueTypeName.STRING,
249
+ });
250
+
251
+ modifierCommand.execute = (): Promise<void> => {
252
+ modifierHasRun = true;
253
+ return Promise.resolve();
254
+ };
255
+ globalCommand.execute = (): Promise<void> => {
256
+ globalHasRun = true;
257
+ return Promise.resolve();
258
+ };
259
+
260
+ const commandRegistry = new DefaultCommandRegistry([
261
+ modifierCommand,
262
+ globalCommand,
263
+ ]);
264
+ const runResult = await run(
265
+ ["--modifier=bar", "-g", "bar"],
266
+ commandRegistry,
267
+ getServiceProviderRegistry(),
268
+ undefined,
269
+ getContext(new WritableStreamString()),
270
+ );
271
+
272
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
273
+ expect(modifierHasRun).toBeTrue();
274
+ expect(globalHasRun).toBeTrue();
275
+ });
276
+
277
+ test("Two global modifier and global run", async () => {
278
+ let modifier1HasRun = false;
279
+ let modifier2HasRun = false;
280
+ let globalHasRun = false;
281
+
282
+ const modifierCommand1 = getGlobalModifierCommandWithArgument(
283
+ "modifier1",
284
+ "m",
285
+ 1,
286
+ {
287
+ type: ArgumentValueTypeName.STRING,
288
+ },
289
+ );
290
+ const modifierCommand2 = getGlobalModifierCommandWithArgument(
291
+ "modifier2",
292
+ "n",
293
+ 2,
294
+ {
295
+ type: ArgumentValueTypeName.STRING,
296
+ },
297
+ );
298
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g", {
299
+ type: ArgumentValueTypeName.STRING,
300
+ });
301
+
302
+ modifierCommand1.execute = (): Promise<void> => {
303
+ modifier1HasRun = true;
304
+ return Promise.resolve();
305
+ };
306
+ modifierCommand2.execute = (): Promise<void> => {
307
+ modifier2HasRun = true;
308
+ return Promise.resolve();
309
+ };
310
+ globalCommand.execute = (): Promise<void> => {
311
+ globalHasRun = true;
312
+ return Promise.resolve();
313
+ };
314
+
315
+ const commandRegistry = new DefaultCommandRegistry([
316
+ modifierCommand1,
317
+ modifierCommand2,
318
+ globalCommand,
319
+ ]);
320
+ const runResult = await run(
321
+ ["--modifier1=bar", "-g", "bar", "--modifier2=bar"],
322
+ commandRegistry,
323
+ getServiceProviderRegistry(),
324
+ undefined,
325
+ getContext(new WritableStreamString()),
326
+ );
327
+
328
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
329
+ expect(modifier1HasRun).toBeTrue();
330
+ expect(modifier2HasRun).toBeTrue();
331
+ expect(globalHasRun).toBeTrue();
332
+ });
333
+
334
+ test("Two global modifier and group command run", async () => {
335
+ let modifier1HasRun = false;
336
+ let modifier2HasRun = false;
337
+ let groupHasRun = false;
338
+ let subHasRun = false;
339
+
340
+ const modifierCommand1 = getGlobalModifierCommandWithArgument(
341
+ "modifier1",
342
+ "m",
343
+ 1,
344
+ {
345
+ type: ArgumentValueTypeName.STRING,
346
+ },
347
+ );
348
+ const modifierCommand2 = getGlobalModifierCommandWithArgument(
349
+ "modifier2",
350
+ "n",
351
+ 2,
352
+ {
353
+ type: ArgumentValueTypeName.STRING,
354
+ },
355
+ );
356
+ const subCommand = getSubCommandWithOption("subCommand", true);
357
+ const groupCommand = getGroupCommand("group", [subCommand]);
358
+
359
+ modifierCommand1.execute = (_context, argumentValue): Promise<void> => {
360
+ expect(argumentValue).toEqual("bar1");
361
+ modifier1HasRun = true;
362
+ return Promise.resolve();
363
+ };
364
+ modifierCommand2.execute = (_context, argumentValue): Promise<void> => {
365
+ expect(argumentValue).toEqual("bar2");
366
+ modifier2HasRun = true;
367
+ return Promise.resolve();
368
+ };
369
+ groupCommand.execute = (): Promise<void> => {
370
+ groupHasRun = true;
371
+ return Promise.resolve();
372
+ };
373
+ subCommand.execute = (_context, argumentValues): Promise<void> => {
374
+ expect(argumentValues.foo).toEqual("subfoo");
375
+ subHasRun = true;
376
+ return Promise.resolve();
377
+ };
378
+
379
+ const commandRegistry = new DefaultCommandRegistry([
380
+ modifierCommand1,
381
+ modifierCommand2,
382
+ groupCommand,
383
+ ]);
384
+ const runResult = await run(
385
+ [
386
+ "--modifier1=bar1",
387
+ "group",
388
+ "subCommand",
389
+ "--foo",
390
+ "subfoo",
391
+ "--modifier2=bar2",
392
+ ],
393
+ commandRegistry,
394
+ getServiceProviderRegistry(),
395
+ undefined,
396
+ getContext(new WritableStreamString()),
397
+ );
398
+
399
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
400
+ expect(modifier1HasRun).toBeTrue();
401
+ expect(modifier2HasRun).toBeTrue();
402
+ expect(groupHasRun).toBeTrue();
403
+ expect(subHasRun).toBeTrue();
404
+ });
405
+
406
+ test("Global modifier and default run", async () => {
407
+ let modifierHasRun = false;
408
+ let defaultHasRun = false;
409
+
410
+ const modifierCommand = getGlobalModifierCommandWithArgument(
411
+ "modifier",
412
+ "m",
413
+ 1,
414
+ {
415
+ type: ArgumentValueTypeName.STRING,
416
+ },
417
+ );
418
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g");
419
+
420
+ modifierCommand.execute = (): Promise<void> => {
421
+ modifierHasRun = true;
422
+ return Promise.resolve();
423
+ };
424
+ globalCommand.execute = (): Promise<void> => {
425
+ defaultHasRun = true;
426
+ return Promise.resolve();
427
+ };
428
+
429
+ const commandRegistry = new DefaultCommandRegistry([
430
+ modifierCommand,
431
+ globalCommand,
432
+ ]);
433
+ const runResult = await run(
434
+ ["--modifier=bar"],
435
+ commandRegistry,
436
+ getServiceProviderRegistry(),
437
+ undefined,
438
+ getContext(new WritableStreamString()),
439
+ globalCommand,
440
+ );
441
+
442
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
443
+ expect(modifierHasRun).toBeTrue();
444
+ expect(defaultHasRun).toBeTrue();
445
+ });
446
+
447
+ test("Global modifier parse error", async () => {
448
+ const streamString = new StreamString();
449
+
450
+ let modifierHasRun = false;
451
+ let defaultHasRun = false;
452
+
453
+ const modifierCommand = getGlobalModifierCommandWithArgument(
454
+ "modifier",
455
+ "m",
456
+ 1,
457
+ {
458
+ type: ArgumentValueTypeName.STRING,
459
+ },
460
+ );
461
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g");
462
+
463
+ modifierCommand.execute = (): Promise<void> => {
464
+ modifierHasRun = true;
465
+ return Promise.resolve();
466
+ };
467
+ globalCommand.execute = (): Promise<void> => {
468
+ defaultHasRun = true;
469
+ return Promise.resolve();
470
+ };
471
+
472
+ const commandRegistry = new DefaultCommandRegistry([
473
+ modifierCommand,
474
+ globalCommand,
475
+ ]);
476
+ const runResult = await run(
477
+ ["--modifier"],
478
+ commandRegistry,
479
+ getServiceProviderRegistry(),
480
+ undefined,
481
+ getContext(streamString),
482
+ globalCommand,
483
+ );
484
+
485
+ expect(runResult.runState).toEqual(RunState.PARSE_ERROR);
486
+ expectStringIncludes(streamString.getString(), "(missing value)");
487
+ expect(modifierHasRun).toBeFalse();
488
+ expect(defaultHasRun).toBeFalse();
489
+ });
490
+
491
+ test("Default run", async () => {
492
+ let subHasRun = false;
493
+
494
+ const option = {
495
+ name: "foo",
496
+ type: ArgumentValueTypeName.STRING,
497
+ shortAlias: "f",
498
+ };
499
+ const subCommand = getSubCommand("command", [option], []);
500
+
501
+ subCommand.execute = (): Promise<void> => {
502
+ subHasRun = true;
503
+ return Promise.resolve();
504
+ };
505
+
506
+ const runResult = await run(
507
+ ["--foo=bar"],
508
+ new DefaultCommandRegistry([]),
509
+ getServiceProviderRegistry(),
510
+ undefined,
511
+ getContext(new WritableStreamString()),
512
+ subCommand,
513
+ );
514
+
515
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
516
+ expect(subHasRun).toBeTrue();
517
+ });
518
+
519
+ test("Error thrown in non-global run", async () => {
520
+ const option = {
521
+ name: "foo",
522
+ type: ArgumentValueTypeName.STRING,
523
+ shortAlias: "f",
524
+ };
525
+ const subCommand = getSubCommand("command", [option], []);
526
+
527
+ subCommand.execute = (): Promise<void> => {
528
+ throw new Error("d34db33f");
529
+ };
530
+
531
+ const commandRegistry = new DefaultCommandRegistry([subCommand]);
532
+ const runResult = await run(
533
+ ["command", "--foo", "bar"],
534
+ commandRegistry,
535
+ getServiceProviderRegistry(),
536
+ undefined,
537
+ getContext(new WritableStreamString()),
538
+ );
539
+
540
+ expect(runResult.runState).toEqual(RunState.EXECUTION_ERROR);
541
+ });
542
+
543
+ test("Error thrown in global run", async () => {
544
+ const streamString = new StreamString();
545
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g", {
546
+ type: ArgumentValueTypeName.STRING,
547
+ });
548
+
549
+ globalCommand.execute = (): Promise<void> => {
550
+ throw new Error("d34db33f");
551
+ };
552
+
553
+ const commandRegistry = new DefaultCommandRegistry([globalCommand]);
554
+ const runResult = await run(
555
+ ["--global=bar"],
556
+ commandRegistry,
557
+ getServiceProviderRegistry(),
558
+ undefined,
559
+ getContext(streamString),
560
+ );
561
+
562
+ expect(runResult.runState).toEqual(RunState.EXECUTION_ERROR);
563
+ expectStringIncludes(streamString.getString(), "Execution error");
564
+ expectStringIncludes(streamString.getString(), "d34db33f");
565
+ });
566
+
567
+ test("Error thrown in global modifier run", async () => {
568
+ const streamString = new StreamString();
569
+
570
+ let globalHasRun = false;
571
+
572
+ const globalModifierCommand = getGlobalModifierCommandWithArgument(
573
+ "modifier",
574
+ "m",
575
+ 1,
576
+ );
577
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g");
578
+
579
+ globalModifierCommand.execute = (): Promise<void> => {
580
+ throw new Error("d34db33f");
581
+ };
582
+ globalCommand.execute = (): Promise<void> => {
583
+ globalHasRun = true;
584
+ return Promise.resolve();
585
+ };
586
+
587
+ const commandRegistry = new DefaultCommandRegistry([
588
+ globalCommand,
589
+ globalModifierCommand,
590
+ ]);
591
+ const runResult = await run(
592
+ ["--global", "--modifier"],
593
+ commandRegistry,
594
+ getServiceProviderRegistry(),
595
+ undefined,
596
+ getContext(streamString),
597
+ );
598
+
599
+ expect(runResult.runState).toEqual(RunState.EXECUTION_ERROR);
600
+ expectStringIncludes(streamString.getString(), "Execution error");
601
+ expectStringIncludes(streamString.getString(), "d34db33f");
602
+ expect(globalHasRun).toBeFalse();
603
+ });
604
+
605
+ test("Parse error warning in non-global run", async () => {
606
+ const streamString = new StreamString();
607
+ let hasRun = false;
608
+ const option = {
609
+ name: "foo",
610
+ type: ArgumentValueTypeName.STRING,
611
+ shortAlias: "f",
612
+ };
613
+ const subCommand = getSubCommand("command", [option], []);
614
+
615
+ subCommand.execute = (): Promise<void> => {
616
+ hasRun = true;
617
+ return Promise.resolve();
618
+ };
619
+
620
+ const commandRegistry = new DefaultCommandRegistry([subCommand]);
621
+ const runResult = await run(
622
+ ["command", "-f"],
623
+ commandRegistry,
624
+ getServiceProviderRegistry(),
625
+ undefined,
626
+ getContext(streamString),
627
+ );
628
+
629
+ expect(runResult.runState).toEqual(RunState.PARSE_ERROR);
630
+ expectStringIncludes(
631
+ streamString.getString(),
632
+ "-f (missing value)",
633
+ );
634
+ expect(hasRun).toBeFalse();
635
+ });
636
+
637
+ test("Missing Group Command member", async () => {
638
+ const subCommand = getSubCommand("command", [], []);
639
+ const groupCommand = getGroupCommand("group", [subCommand]);
640
+
641
+ subCommand.execute = (): Promise<void> => {
642
+ return Promise.resolve();
643
+ };
644
+ groupCommand.execute = (): Promise<void> => {
645
+ return Promise.resolve();
646
+ };
647
+
648
+ const commandRegistry = new DefaultCommandRegistry([groupCommand]);
649
+ const runResult = await run(
650
+ ["group", "wrongcommand"],
651
+ commandRegistry,
652
+ getServiceProviderRegistry(),
653
+ undefined,
654
+ getContext(new WritableStreamString()),
655
+ );
656
+
657
+ expect(runResult.runState).toEqual(RunState.NO_COMMAND);
658
+ });
659
+
660
+ test("No command specified", async () => {
661
+ const streamString = new StreamString();
662
+ let hasRun = false;
663
+ const option = {
664
+ name: "foo",
665
+ type: ArgumentValueTypeName.STRING,
666
+ shortAlias: "f",
667
+ };
668
+ const subCommand = getSubCommand("command", [option], []);
669
+
670
+ subCommand.execute = (): Promise<void> => {
671
+ hasRun = true;
672
+ return Promise.resolve();
673
+ };
674
+
675
+ const commandRegistry = new DefaultCommandRegistry([subCommand]);
676
+ const runResult = await run(
677
+ [],
678
+ commandRegistry,
679
+ getServiceProviderRegistry(),
680
+ undefined,
681
+ getContext(streamString),
682
+ );
683
+
684
+ expect(runResult.runState).toEqual(RunState.NO_COMMAND);
685
+ expectStringIncludes(
686
+ streamString.getString(),
687
+ "No command specified",
688
+ );
689
+ expect(hasRun).toBeFalse();
690
+ });
691
+
692
+ test("Unknown arg warning in non-global run", async () => {
693
+ const streamString = new StreamString();
694
+ let hasRun = false;
695
+ const subCommand = getSubCommand("command", [], []);
696
+
697
+ subCommand.execute = (): Promise<void> => {
698
+ hasRun = true;
699
+ return Promise.resolve();
700
+ };
701
+
702
+ const commandRegistry = new DefaultCommandRegistry([subCommand]);
703
+ const runResult = await run(
704
+ ["command", "-bad"],
705
+ commandRegistry,
706
+ getServiceProviderRegistry(),
707
+ undefined,
708
+ getContext(streamString),
709
+ );
710
+
711
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
712
+ expectStringIncludes(streamString.getString(), "Unused arg: -bad");
713
+ expect(hasRun).toBeTrue();
714
+ });
715
+
716
+ test("Unknown arg warning in global run", async () => {
717
+ const streamString = new StreamString();
718
+ let hasRun = false;
719
+
720
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g");
721
+
722
+ globalCommand.execute = (): Promise<void> => {
723
+ hasRun = true;
724
+ return Promise.resolve();
725
+ };
726
+
727
+ const runResult = await run(
728
+ ["--bad"],
729
+ new DefaultCommandRegistry([]),
730
+ getServiceProviderRegistry(),
731
+ undefined,
732
+ getContext(streamString),
733
+ globalCommand,
734
+ );
735
+
736
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
737
+ expectStringIncludes(streamString.getString(), "Unused arg: --bad");
738
+ expect(hasRun).toBeTrue();
739
+ });
740
+
741
+ test("Error thrown for default run", async () => {
742
+ const streamString = new StreamString();
743
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g");
744
+
745
+ globalCommand.execute = (): Promise<void> => {
746
+ throw new Error("d34db33f");
747
+ };
748
+
749
+ const runResult = await run(
750
+ [],
751
+ new DefaultCommandRegistry([]),
752
+ getServiceProviderRegistry(),
753
+ undefined,
754
+ getContext(streamString),
755
+ globalCommand,
756
+ );
757
+
758
+ expect(runResult.runState).toEqual(RunState.EXECUTION_ERROR);
759
+ expectStringIncludes(streamString.getString(), "Execution error:");
760
+ expectStringIncludes(streamString.getString(), "d34db33f");
761
+ });
762
+
763
+ test("Run default based on all args", async () => {
764
+ const command = getSubCommand("command", [{
765
+ name: "foo",
766
+ type: ArgumentValueTypeName.STRING,
767
+ }, {
768
+ name: "goo",
769
+ type: ArgumentValueTypeName.STRING,
770
+ }], []);
771
+ const runResult = await run(
772
+ ["--foo=f", "--goo=g"],
773
+ new DefaultCommandRegistry([]),
774
+ getServiceProviderRegistry(),
775
+ undefined,
776
+ getContext(new WritableStreamString()),
777
+ command,
778
+ );
779
+
780
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
781
+ });
782
+
783
+ test("Run default command based on config only and treating all args as unused", async () => {
784
+ const streamString = new StreamString();
785
+ const command = getSubCommand(
786
+ "command",
787
+ [{
788
+ name: "foo",
789
+ type: ArgumentValueTypeName.STRING,
790
+ }, {
791
+ name: "goo",
792
+ type: ArgumentValueTypeName.STRING,
793
+ }],
794
+ [],
795
+ true,
796
+ );
797
+ const runResult = await run(
798
+ ["--bip=b", "--bop=b"],
799
+ new DefaultCommandRegistry([]),
800
+ getServiceProviderRegistry(),
801
+ getConfigurationServiceProvider(
802
+ 90,
803
+ new Map([
804
+ ["command", {
805
+ foo: "f",
806
+ goo: "g",
807
+ }],
808
+ ]),
809
+ ),
810
+ getContext(streamString),
811
+ command,
812
+ );
813
+
814
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
815
+ expectStringIncludes(
816
+ streamString.getString(),
817
+ "Unused args: --bip=b --bop=b",
818
+ );
819
+ });
820
+
821
+ test("Run default command based on some args and treating some args as unused", async () => {
822
+ const streamString = new StreamString();
823
+ const command = getSubCommand(
824
+ "command",
825
+ [{
826
+ name: "foo",
827
+ type: ArgumentValueTypeName.STRING,
828
+ }, {
829
+ name: "goo",
830
+ type: ArgumentValueTypeName.STRING,
831
+ }],
832
+ [],
833
+ true,
834
+ );
835
+
836
+ const runResult = await run(
837
+ ["--bip=b", "--goo=g"],
838
+ new DefaultCommandRegistry([]),
839
+ getServiceProviderRegistry(),
840
+ getConfigurationServiceProvider(
841
+ 90,
842
+ new Map([
843
+ ["command", {
844
+ foo: "f",
845
+ }],
846
+ ]),
847
+ ),
848
+ getContext(streamString),
849
+ command,
850
+ );
851
+
852
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
853
+ expectStringIncludes(
854
+ streamString.getString(),
855
+ "Unused arg: --bip=b",
856
+ );
857
+ });
858
+
859
+ test("Fail to parse default command with some unused args and missing required values", async () => {
860
+ const streamString = new StreamString();
861
+ const command = getSubCommand("command", [{
862
+ name: "foo",
863
+ type: ArgumentValueTypeName.STRING,
864
+ }, {
865
+ name: "goo",
866
+ type: ArgumentValueTypeName.STRING,
867
+ }], []);
868
+
869
+ const runResult = await run(
870
+ ["--bip=b", "--goo=g"],
871
+ new DefaultCommandRegistry([]),
872
+ getServiceProviderRegistry(),
873
+ undefined,
874
+ getContext(streamString),
875
+ command,
876
+ );
877
+ expect(runResult.runState).toEqual(RunState.PARSE_ERROR);
878
+ expectStringIncludes(streamString.getString(), "missing value");
879
+ });
880
+
881
+ test("Fail to parse default command with some unused args", async () => {
882
+ const streamString = new StreamString();
883
+ const command = getSubCommand("command", [{
884
+ name: "foo",
885
+ type: ArgumentValueTypeName.STRING,
886
+ isOptional: true,
887
+ }, {
888
+ name: "goo",
889
+ type: ArgumentValueTypeName.STRING,
890
+ }], []);
891
+
892
+ const runResult = await run(
893
+ ["--bip=b", "--goo=g"],
894
+ new DefaultCommandRegistry([]),
895
+ getServiceProviderRegistry(),
896
+ undefined,
897
+ getContext(streamString),
898
+ command,
899
+ );
900
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
901
+ expectStringIncludes(streamString.getString(), "Unused arg");
902
+ });
903
+
904
+ test("Illegal second command treated as unknown arg", async () => {
905
+ const streamString = new StreamString();
906
+ let hasRun = false;
907
+ const option = {
908
+ name: "foo",
909
+ type: ArgumentValueTypeName.STRING,
910
+ shortAlias: "f",
911
+ };
912
+ const subCommand1 = getSubCommand("command1", [option], []);
913
+
914
+ subCommand1.execute = (): Promise<void> => {
915
+ hasRun = true;
916
+ return Promise.resolve();
917
+ };
918
+
919
+ const subCommand2 = getSubCommand("command2", [], []);
920
+ const commandRegistry = new DefaultCommandRegistry([
921
+ subCommand1,
922
+ subCommand2,
923
+ ]);
924
+ const runResult = await run(
925
+ ["command1", "--foo", "bar", "command2"],
926
+ commandRegistry,
927
+ getServiceProviderRegistry(),
928
+ undefined,
929
+ getContext(streamString),
930
+ );
931
+
932
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
933
+ expectStringIncludes(
934
+ streamString.getString(),
935
+ "Unused arg: command2",
936
+ );
937
+ expect(hasRun).toBeTrue();
938
+ });
939
+
940
+ test("Ensure global modifier and global run priority order", async () => {
941
+ const hasRun: string[] = [];
942
+ const modifier1Command = getGlobalModifierCommandWithArgument(
943
+ "modifier1",
944
+ "1",
945
+ 2,
946
+ {
947
+ type: ArgumentValueTypeName.STRING,
948
+ },
949
+ );
950
+ const modifier2Command = getGlobalModifierCommandWithArgument(
951
+ "modifier2",
952
+ "2",
953
+ 1,
954
+ {
955
+ type: ArgumentValueTypeName.STRING,
956
+ },
957
+ );
958
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g", {
959
+ type: ArgumentValueTypeName.STRING,
960
+ });
961
+
962
+ modifier1Command.execute = (): Promise<void> => {
963
+ hasRun.push(modifier1Command.name);
964
+ return Promise.resolve();
965
+ };
966
+ modifier2Command.execute = (): Promise<void> => {
967
+ hasRun.push(modifier2Command.name);
968
+ return Promise.resolve();
969
+ };
970
+ globalCommand.execute = (): Promise<void> => {
971
+ hasRun.push(globalCommand.name);
972
+ return Promise.resolve();
973
+ };
974
+
975
+ const commandRegistry = new DefaultCommandRegistry([
976
+ globalCommand,
977
+ modifier1Command,
978
+ modifier2Command,
979
+ ]);
980
+ const runResult = await run(
981
+ ["--modifier2=foo", "-g", "bar", "--modifier1=bar"],
982
+ commandRegistry,
983
+ getServiceProviderRegistry(),
984
+ undefined,
985
+ getContext(new WritableStreamString()),
986
+ );
987
+
988
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
989
+ expect(hasRun[0]).toEqual("modifier1");
990
+ expect(hasRun[1]).toEqual("modifier2");
991
+ expect(hasRun[2]).toEqual("global");
992
+ });
993
+
994
+ test("Warning for unused leading args", async () => {
995
+ const streamString = new StreamString();
996
+ const option = {
997
+ name: "foo",
998
+ type: ArgumentValueTypeName.STRING,
999
+ shortAlias: "f",
1000
+ };
1001
+ const subCommand = getSubCommand("command", [option], []);
1002
+ const commandRegistry = new DefaultCommandRegistry([subCommand]);
1003
+ const runResult = await run(
1004
+ ["blah", "command", "--foo", "bar"],
1005
+ commandRegistry,
1006
+ getServiceProviderRegistry(),
1007
+ undefined,
1008
+ getContext(streamString),
1009
+ );
1010
+
1011
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1012
+ expectStringIncludes(streamString.getString(), "Unused arg: blah");
1013
+ });
1014
+
1015
+ test("Warning for unused trailing args", async () => {
1016
+ const streamString = new StreamString();
1017
+ const option = {
1018
+ name: "foo",
1019
+ type: ArgumentValueTypeName.STRING,
1020
+ shortAlias: "f",
1021
+ };
1022
+ const subCommand = getSubCommand("command", [option], []);
1023
+ const commandRegistry = new DefaultCommandRegistry([subCommand]);
1024
+ const runResult = await run(
1025
+ ["command", "--foo", "bar", "blah"],
1026
+ commandRegistry,
1027
+ getServiceProviderRegistry(),
1028
+ undefined,
1029
+ getContext(streamString),
1030
+ );
1031
+
1032
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1033
+ expectStringIncludes(streamString.getString(), "Unused arg: blah");
1034
+ });
1035
+
1036
+ test("Sub-Command run with complex options and explicit arrays", async () => {
1037
+ let hasRun = false;
1038
+ const options = [{
1039
+ name: "alpha",
1040
+ shortAlias: "a",
1041
+ type: ComplexValueTypeName.COMPLEX,
1042
+ isArray: true,
1043
+ properties: [{
1044
+ name: "beta",
1045
+ shortAlias: "b",
1046
+ type: ComplexValueTypeName.COMPLEX,
1047
+ isArray: true,
1048
+ properties: [{
1049
+ name: "gamma",
1050
+ shortAlias: "g",
1051
+ type: ArgumentValueTypeName.STRING,
1052
+ }, {
1053
+ name: "delta",
1054
+ shortAlias: "d",
1055
+ type: ArgumentValueTypeName.NUMBER,
1056
+ isArray: true,
1057
+ }],
1058
+ }],
1059
+ }, {
1060
+ name: "epsilon",
1061
+ shortAlias: "e",
1062
+ type: ComplexValueTypeName.COMPLEX,
1063
+ properties: [{
1064
+ name: "gamma",
1065
+ shortAlias: "g",
1066
+ type: ArgumentValueTypeName.STRING,
1067
+ }, {
1068
+ name: "delta",
1069
+ shortAlias: "d",
1070
+ type: ArgumentValueTypeName.NUMBER,
1071
+ }],
1072
+ }];
1073
+ const command = getSubCommand("command", options, []);
1074
+
1075
+ command.execute = (): Promise<void> => {
1076
+ hasRun = true;
1077
+
1078
+ return Promise.resolve();
1079
+ };
1080
+
1081
+ const commandRegistry = new DefaultCommandRegistry([command]);
1082
+ const runResult = await run(
1083
+ [
1084
+ "command",
1085
+ "-e.g=bar",
1086
+ "-e.d=1",
1087
+ "-a.b[1].g=foo2",
1088
+ "--alpha.beta[0].gamma=foo1",
1089
+ "-a.b[1].d[1]=2",
1090
+ "-a.b[0].d=1",
1091
+ "-a.b[1].d[0]=3",
1092
+ ],
1093
+ commandRegistry,
1094
+ getServiceProviderRegistry(),
1095
+ undefined,
1096
+ getContext(new WritableStreamString()),
1097
+ );
1098
+
1099
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1100
+ expect(hasRun).toBeTrue();
1101
+ });
1102
+
1103
+ test("Sub-Command run with complex options and positionals", async () => {
1104
+ let hasRun = false;
1105
+ const options = [{
1106
+ name: "alpha",
1107
+ shortAlias: "a",
1108
+ type: ComplexValueTypeName.COMPLEX,
1109
+ isArray: true,
1110
+ properties: [{
1111
+ name: "beta",
1112
+ shortAlias: "b",
1113
+ type: ComplexValueTypeName.COMPLEX,
1114
+ isArray: true,
1115
+ properties: [{
1116
+ name: "gamma",
1117
+ shortAlias: "g",
1118
+ type: ArgumentValueTypeName.STRING,
1119
+ }, {
1120
+ name: "delta",
1121
+ shortAlias: "d",
1122
+ type: ArgumentValueTypeName.NUMBER,
1123
+ isArray: true,
1124
+ }],
1125
+ }],
1126
+ }, {
1127
+ name: "epsilon",
1128
+ shortAlias: "e",
1129
+ type: ComplexValueTypeName.COMPLEX,
1130
+ properties: [{
1131
+ name: "gamma",
1132
+ shortAlias: "g",
1133
+ type: ArgumentValueTypeName.STRING,
1134
+ }, {
1135
+ name: "delta",
1136
+ shortAlias: "d",
1137
+ type: ArgumentValueTypeName.NUMBER,
1138
+ }],
1139
+ }];
1140
+ const positionals = [{
1141
+ name: "foo",
1142
+ type: ArgumentValueTypeName.STRING,
1143
+ }, {
1144
+ name: "bar",
1145
+ type: ArgumentValueTypeName.INTEGER,
1146
+ isVarargMultiple: true,
1147
+ isVarargOptional: true,
1148
+ }];
1149
+
1150
+ const command = getSubCommand("command", options, positionals);
1151
+
1152
+ command.execute = (): Promise<void> => {
1153
+ hasRun = true;
1154
+
1155
+ return Promise.resolve();
1156
+ };
1157
+
1158
+ const commandRegistry = new DefaultCommandRegistry([command]);
1159
+ let runResult = await run(
1160
+ [
1161
+ "command",
1162
+ "-e.g=bar",
1163
+ "-e.d=1",
1164
+ "-a.b[1].g=foo2",
1165
+ "--alpha.beta[0].gamma=foo1",
1166
+ "-a.b[1].d[1]=2",
1167
+ "-a.b[0].d=1",
1168
+ "-a.b[1].d[0]=3",
1169
+ "foo",
1170
+ ],
1171
+ commandRegistry,
1172
+ getServiceProviderRegistry(),
1173
+ undefined,
1174
+ getContext(new WritableStreamString()),
1175
+ );
1176
+
1177
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1178
+ expect(hasRun).toBeTrue();
1179
+
1180
+ runResult = await run(
1181
+ [
1182
+ "command",
1183
+ "-e.g=bar",
1184
+ "-e.d=1",
1185
+ "-a.b[1].g=foo2",
1186
+ "--alpha.beta[0].gamma=foo1",
1187
+ "-a.b[1].d[1]=2",
1188
+ "-a.b[0].d=1",
1189
+ "-a.b[1].d[0]=3",
1190
+ "foo",
1191
+ "1",
1192
+ "2",
1193
+ ],
1194
+ commandRegistry,
1195
+ getServiceProviderRegistry(),
1196
+ undefined,
1197
+ getContext(new WritableStreamString()),
1198
+ );
1199
+
1200
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1201
+ expect(hasRun).toBeTrue();
1202
+
1203
+ runResult = await run(
1204
+ [
1205
+ "command",
1206
+ "foo",
1207
+ "-e.g=bar",
1208
+ "-e.d=1",
1209
+ "-a.b[1].g=foo2",
1210
+ "--alpha.beta[0].gamma=foo1",
1211
+ "-a.b[1].d[1]=2",
1212
+ "-a.b[0].d=1",
1213
+ "-a.b[1].d[0]=3",
1214
+ "1",
1215
+ "2",
1216
+ ],
1217
+ commandRegistry,
1218
+ getServiceProviderRegistry(),
1219
+ undefined,
1220
+ getContext(new WritableStreamString()),
1221
+ );
1222
+
1223
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1224
+ expect(hasRun).toBeTrue();
1225
+ });
1226
+
1227
+ test("Group command as default command is invalid", async () => {
1228
+ const streamString = new StreamString();
1229
+ const groupCommand = getGroupCommand();
1230
+
1231
+ groupCommand.execute = (): Promise<void> => {
1232
+ return Promise.resolve();
1233
+ };
1234
+
1235
+ await expect(
1236
+ run(
1237
+ [],
1238
+ new DefaultCommandRegistry([]),
1239
+ getServiceProviderRegistry(),
1240
+ undefined,
1241
+ getContext(streamString),
1242
+ groupCommand as unknown as GlobalModifierCommand,
1243
+ ),
1244
+ ).rejects.toThrow();
1245
+ });
1246
+
1247
+ test("Global modifier specified fully by config and global run", async () => {
1248
+ let modifierHasRun = false;
1249
+ let globalHasRun = false;
1250
+
1251
+ const modifierCommand = getGlobalModifierCommandWithArgument(
1252
+ "modifier",
1253
+ "m",
1254
+ 1,
1255
+ {
1256
+ type: ArgumentValueTypeName.STRING,
1257
+ },
1258
+ true,
1259
+ );
1260
+ const globalCommand = getGlobalCommandWithShortAlias("global", "g", {
1261
+ type: ArgumentValueTypeName.STRING,
1262
+ });
1263
+
1264
+ modifierCommand.execute = (_context, argumentValue): Promise<void> => {
1265
+ expect(argumentValue).toEqual("foo");
1266
+ modifierHasRun = true;
1267
+ return Promise.resolve();
1268
+ };
1269
+ globalCommand.execute = (_context, argumentValue): Promise<void> => {
1270
+ expect(argumentValue).toEqual("bar");
1271
+ globalHasRun = true;
1272
+ return Promise.resolve();
1273
+ };
1274
+
1275
+ const commandRegistry = new DefaultCommandRegistry([
1276
+ modifierCommand,
1277
+ globalCommand,
1278
+ ]);
1279
+ const runResult = await run(
1280
+ ["-g", "bar"],
1281
+ commandRegistry,
1282
+ getServiceProviderRegistry(),
1283
+ getConfigurationServiceProvider(
1284
+ 90,
1285
+ new Map<string, ArgumentValues | ArgumentSingleValueType>([
1286
+ ["modifier", "foo"],
1287
+ ["irrelevant", {
1288
+ name: "value",
1289
+ }],
1290
+ ]),
1291
+ ),
1292
+ getContext(new WritableStreamString()),
1293
+ );
1294
+ expect(runResult.runState).toEqual(RunState.SUCCESS);
1295
+ expect(modifierHasRun).toBeTrue();
1296
+ expect(globalHasRun).toBeTrue();
1297
+ });
1298
+ });