@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,816 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { getCLIConfig } from "../../fixtures/CLIConfig.ts";
3
+ import CommandValidator from "../../../src/runtime/command/CommandValidator.ts";
4
+ import {
5
+ getGlobalCommandWithShortAlias,
6
+ getGroupCommand,
7
+ getSubCommandWithComplexOptions,
8
+ } from "../../fixtures/Command.ts";
9
+ import type ComplexOption from "../../../src/api/argument/ComplexOption.ts";
10
+ import {
11
+ ArgumentValueTypeName,
12
+ ComplexValueTypeName,
13
+ } from "../../../src/api/argument/ArgumentValueTypes.ts";
14
+ import type Option from "../../../src/api/argument/Option.ts";
15
+ import type Positional from "../../../src/api/argument/Positional.ts";
16
+ import type SubCommand from "../../../src/api/command/SubCommand.ts";
17
+
18
+ function getSubCommand(
19
+ name: string,
20
+ options: ReadonlyArray<Option | ComplexOption>,
21
+ positionals: ReadonlyArray<Positional>,
22
+ enableConfiguration = false,
23
+ ): SubCommand {
24
+ return {
25
+ name,
26
+ options,
27
+ positionals,
28
+ enableConfiguration,
29
+ execute: async (): Promise<void> => {},
30
+ };
31
+ }
32
+ describe("CommandValidator Tests", () => {
33
+ test("SubCommand validation fails due to duplicate argument names", () => {
34
+ let command = getSubCommand("command", [{
35
+ name: "foo",
36
+ type: ArgumentValueTypeName.STRING,
37
+ }, {
38
+ name: "foo",
39
+ type: ArgumentValueTypeName.STRING,
40
+ }], []);
41
+
42
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
43
+ .toThrow();
44
+
45
+ command = getSubCommand("command", [{
46
+ name: "foo",
47
+ type: ArgumentValueTypeName.STRING,
48
+ }], [{
49
+ name: "foo",
50
+ type: ArgumentValueTypeName.STRING,
51
+ }]);
52
+
53
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
54
+ .toThrow();
55
+ command = getSubCommand("command", [], [{
56
+ name: "foo",
57
+ type: ArgumentValueTypeName.STRING,
58
+ }, {
59
+ name: "foo",
60
+ type: ArgumentValueTypeName.STRING,
61
+ }]);
62
+
63
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
64
+ .toThrow();
65
+ });
66
+
67
+ test("SubCommand validation fails due to duplicate argument names or short aliases", () => {
68
+ let command = getSubCommand("command", [{
69
+ name: "f",
70
+ type: ArgumentValueTypeName.STRING,
71
+ }, {
72
+ name: "foo",
73
+ shortAlias: "f",
74
+ type: ArgumentValueTypeName.STRING,
75
+ }], []);
76
+
77
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
78
+ .toThrow();
79
+ command = getSubCommand("command", [{
80
+ name: "foo1",
81
+ shortAlias: "f",
82
+ type: ArgumentValueTypeName.STRING,
83
+ }, {
84
+ name: "foo2",
85
+ shortAlias: "f",
86
+ type: ArgumentValueTypeName.STRING,
87
+ }], []);
88
+
89
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
90
+ .toThrow();
91
+ });
92
+
93
+ test(
94
+ "SubCommand validation fails due to option default value" +
95
+ " not matching any values specified in argument valid values",
96
+ () => {
97
+ const command = getSubCommand("command", [{
98
+ name: "foo",
99
+ type: ArgumentValueTypeName.STRING,
100
+ defaultValue: "bar",
101
+ allowableValues: ["goo"],
102
+ }], []);
103
+
104
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
105
+ .toThrow();
106
+ },
107
+ );
108
+
109
+ test(
110
+ "SubCommand validation fails due to the type of option defaultValue" +
111
+ " not matching the type specified in argument type",
112
+ () => {
113
+ const command = getSubCommand("command", [{
114
+ name: "foo",
115
+ defaultValue: "bar",
116
+ type: ArgumentValueTypeName.BOOLEAN,
117
+ }], []);
118
+
119
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
120
+ .toThrow();
121
+ },
122
+ );
123
+
124
+ test(
125
+ "SubCommand validation fails due to option defaultValue" +
126
+ " being an array and option does not support array",
127
+ () => {
128
+ const command = getSubCommand("command", [{
129
+ name: "foo",
130
+ defaultValue: ["bar1", "bar2"],
131
+ type: ArgumentValueTypeName.STRING,
132
+ }], []);
133
+
134
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
135
+ .toThrow();
136
+ },
137
+ );
138
+
139
+ test(
140
+ "SubCommand validation fails due to the type of values in argument" +
141
+ " allowableValues not matching the type specified in argument type",
142
+ () => {
143
+ const command = getSubCommand("command", [{
144
+ name: "foo",
145
+ defaultValue: "bar",
146
+ allowableValues: [1],
147
+ type: ArgumentValueTypeName.STRING,
148
+ }], []);
149
+
150
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
151
+ .toThrow();
152
+ },
153
+ );
154
+
155
+ test("SubCommand validation fails due to invalid command name", () => {
156
+ const command = getSubCommand("command", [{
157
+ name: "-foo",
158
+ type: ArgumentValueTypeName.STRING,
159
+ }], []);
160
+
161
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
162
+ .toThrow();
163
+ });
164
+
165
+ test("SubCommand validation fails due to invalid command short alias", () => {
166
+ const command = getSubCommand("command", [{
167
+ name: "foo",
168
+ shortAlias: "foo",
169
+ type: ArgumentValueTypeName.STRING,
170
+ }], []);
171
+
172
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
173
+ .toThrow();
174
+ });
175
+
176
+ test("SubCommand validation fails due to non-last positional being varargs", () => {
177
+ let command = getSubCommand("command", [], [{
178
+ name: "foo",
179
+ isVarargMultiple: true,
180
+ type: ArgumentValueTypeName.STRING,
181
+ }, {
182
+ name: "goo",
183
+ type: ArgumentValueTypeName.STRING,
184
+ }]);
185
+
186
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
187
+ .toThrow();
188
+ command = getSubCommand("command", [], [{
189
+ name: "foo",
190
+ isVarargOptional: true,
191
+ type: ArgumentValueTypeName.STRING,
192
+ }, {
193
+ name: "goo",
194
+ type: ArgumentValueTypeName.STRING,
195
+ }]);
196
+
197
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
198
+ .toThrow();
199
+ });
200
+
201
+ test("SubCommand validation fails due to more than one positional being varargs", () => {
202
+ let command = getSubCommand("command", [], [{
203
+ name: "foo",
204
+ isVarargMultiple: true,
205
+ type: ArgumentValueTypeName.STRING,
206
+ }, {
207
+ name: "goo",
208
+ isVarargMultiple: true,
209
+ type: ArgumentValueTypeName.STRING,
210
+ }]);
211
+
212
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
213
+ .toThrow();
214
+ command = getSubCommand("command", [], [{
215
+ name: "foo",
216
+ isVarargOptional: true,
217
+ type: ArgumentValueTypeName.STRING,
218
+ }, {
219
+ name: "goo",
220
+ isVarargOptional: true,
221
+ type: ArgumentValueTypeName.STRING,
222
+ }]);
223
+
224
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
225
+ .toThrow();
226
+ command = getSubCommand("command", [], [{
227
+ name: "foo",
228
+ isVarargOptional: true,
229
+ type: ArgumentValueTypeName.STRING,
230
+ }, {
231
+ name: "goo",
232
+ isVarargMultiple: true,
233
+ type: ArgumentValueTypeName.STRING,
234
+ }]);
235
+
236
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
237
+ .toThrow();
238
+ command = getSubCommand("command", [], [{
239
+ name: "foo",
240
+ isVarargMultiple: true,
241
+ type: ArgumentValueTypeName.STRING,
242
+ }, {
243
+ name: "goo",
244
+ isVarargOptional: true,
245
+ type: ArgumentValueTypeName.STRING,
246
+ }]);
247
+
248
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
249
+ .toThrow();
250
+ });
251
+
252
+ test("SubCommand validation succeeds", () => {
253
+ const command = getSubCommand("command", [{
254
+ name: "foo",
255
+ defaultValue: "bar",
256
+ allowableValues: ["bar", "gar"],
257
+ shortAlias: "f",
258
+ type: ArgumentValueTypeName.STRING,
259
+ }], [{
260
+ name: "boo",
261
+ type: ArgumentValueTypeName.NUMBER,
262
+ isVarargMultiple: true,
263
+ allowableValues: [1, 2],
264
+ }]);
265
+
266
+ new CommandValidator(getCLIConfig()).validate(command);
267
+ });
268
+
269
+ test(
270
+ "GlobalCommand validation fails due to the default value" +
271
+ " not matching any values specified in argument valid values",
272
+ () => {
273
+ const command = getGlobalCommandWithShortAlias("command", "c", {
274
+ type: ArgumentValueTypeName.STRING,
275
+ defaultValue: "bar",
276
+ allowableValues: ["goo"],
277
+ });
278
+
279
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
280
+ .toThrow();
281
+ },
282
+ );
283
+
284
+ test(
285
+ "GlobalCommand validation fails due to the type of defaultValue" +
286
+ " not matching the type specified in global argument type",
287
+ () => {
288
+ const command = getGlobalCommandWithShortAlias("command", "c", {
289
+ type: ArgumentValueTypeName.BOOLEAN,
290
+ defaultValue: "bar",
291
+ });
292
+
293
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
294
+ .toThrow();
295
+ },
296
+ );
297
+
298
+ test(
299
+ "GlobalCommand validation fails due to the type of values in argument" +
300
+ " allowableValues not matching the type specified in argument type",
301
+ () => {
302
+ const command = getGlobalCommandWithShortAlias("command", "c", {
303
+ defaultValue: "bar",
304
+ allowableValues: [1],
305
+ type: ArgumentValueTypeName.STRING,
306
+ });
307
+
308
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
309
+ .toThrow();
310
+ },
311
+ );
312
+
313
+ test("GlobalCommand validation fails due to invalid command name", () => {
314
+ const command = getGlobalCommandWithShortAlias("-command", "c", {
315
+ type: ArgumentValueTypeName.STRING,
316
+ });
317
+
318
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
319
+ .toThrow();
320
+ });
321
+
322
+ test("GlobalCommand validation fails due to invalid command short alias", () => {
323
+ const command = getGlobalCommandWithShortAlias("command", "command", {
324
+ type: ArgumentValueTypeName.STRING,
325
+ });
326
+
327
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
328
+ .toThrow();
329
+ });
330
+
331
+ test("GlobalCommand validation succeeds with global argument", () => {
332
+ const command = getGlobalCommandWithShortAlias("command", "c", {
333
+ defaultValue: "bar",
334
+ allowableValues: ["bar", "gar"],
335
+ type: ArgumentValueTypeName.STRING,
336
+ });
337
+
338
+ new CommandValidator(getCLIConfig()).validate(command);
339
+ });
340
+
341
+ test("GlobalCommand validation succeeds without global argument", () => {
342
+ const command = getGlobalCommandWithShortAlias("command", "c");
343
+
344
+ new CommandValidator(getCLIConfig()).validate(command);
345
+ });
346
+
347
+ test("GrouoCommand validation fails due to name and member duplicate names", () => {
348
+ const command = getGroupCommand("command", [
349
+ getSubCommand("command", [], []),
350
+ ]);
351
+
352
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
353
+ .toThrow();
354
+ });
355
+
356
+ test("GrouoCommand validation fails due to duplicate member command names", () => {
357
+ const command = getGroupCommand("group", [
358
+ getSubCommand("command", [], []),
359
+ getSubCommand("command", [], []),
360
+ ]);
361
+
362
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
363
+ .toThrow();
364
+ });
365
+
366
+ test("GrouoCommand validation fails due to invalid command name", () => {
367
+ const command = getGroupCommand("-group", [
368
+ getSubCommand("command", [], []),
369
+ ]);
370
+
371
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
372
+ .toThrow();
373
+ });
374
+
375
+ test("GroupCommand validation succeeds", () => {
376
+ const command = getGroupCommand("group", [
377
+ getSubCommand("command1", [], []),
378
+ getSubCommand("command2", [{
379
+ name: "foo",
380
+ defaultValue: "bar",
381
+ allowableValues: ["bar", "gar"],
382
+ shortAlias: "f",
383
+ type: ArgumentValueTypeName.STRING,
384
+ }], [{
385
+ name: "boo",
386
+ type: ArgumentValueTypeName.NUMBER,
387
+ isVarargMultiple: true,
388
+ allowableValues: [1, 2],
389
+ }]),
390
+ ]);
391
+
392
+ new CommandValidator(getCLIConfig()).validate(command);
393
+ });
394
+
395
+ test("SubCommand validation succeeds", () => {
396
+ new CommandValidator(getCLIConfig()).validate(
397
+ getSubCommandWithComplexOptions(true),
398
+ );
399
+ });
400
+
401
+ test("SubCommand validation fails due to nested duplicate property paths", () => {
402
+ const command = getSubCommand("command", [{
403
+ name: "alpha",
404
+ shortAlias: "a",
405
+ type: ComplexValueTypeName.COMPLEX,
406
+ isArray: true,
407
+ properties: [{
408
+ name: "beta",
409
+ shortAlias: "b",
410
+ type: ComplexValueTypeName.COMPLEX,
411
+ isArray: true,
412
+ properties: [{
413
+ name: "gamma",
414
+ shortAlias: "g",
415
+ type: ArgumentValueTypeName.STRING,
416
+ }],
417
+ }],
418
+ }, {
419
+ name: "alpha",
420
+ shortAlias: "a",
421
+ type: ComplexValueTypeName.COMPLEX,
422
+ isArray: true,
423
+ properties: [{
424
+ name: "beta",
425
+ shortAlias: "b",
426
+ type: ComplexValueTypeName.COMPLEX,
427
+ isArray: true,
428
+ properties: [{
429
+ name: "gamma",
430
+ shortAlias: "g",
431
+ type: ArgumentValueTypeName.STRING,
432
+ }],
433
+ }],
434
+ }], []);
435
+
436
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
437
+ .toThrow();
438
+ });
439
+
440
+ test("SubCommand validation fails due to duplicate argument names or short aliases in sibling nested properties", () => {
441
+ const command = getSubCommand("command", [{
442
+ name: "alpha",
443
+ shortAlias: "a",
444
+ type: ComplexValueTypeName.COMPLEX,
445
+ isArray: true,
446
+ properties: [{
447
+ name: "beta",
448
+ shortAlias: "b",
449
+ type: ComplexValueTypeName.COMPLEX,
450
+ isArray: true,
451
+ properties: [{
452
+ name: "gamma",
453
+ shortAlias: "g",
454
+ type: ArgumentValueTypeName.STRING,
455
+ }],
456
+ }],
457
+ }, {
458
+ name: "a",
459
+ type: ComplexValueTypeName.COMPLEX,
460
+ isArray: true,
461
+ properties: [{
462
+ name: "b",
463
+ type: ComplexValueTypeName.COMPLEX,
464
+ isArray: true,
465
+ properties: [{
466
+ name: "g",
467
+ type: ArgumentValueTypeName.STRING,
468
+ }],
469
+ }],
470
+ }], []);
471
+
472
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
473
+ .toThrow();
474
+ });
475
+
476
+ test(
477
+ "SubCommand validation fails due to nested property option default value" +
478
+ " not matching any values specified in argument valid values",
479
+ () => {
480
+ let command = getSubCommand("command", [{
481
+ name: "alpha",
482
+ shortAlias: "a",
483
+ type: ComplexValueTypeName.COMPLEX,
484
+ isArray: true,
485
+ properties: [{
486
+ name: "beta",
487
+ shortAlias: "b",
488
+ type: ComplexValueTypeName.COMPLEX,
489
+ isArray: true,
490
+ properties: [{
491
+ name: "gamma",
492
+ shortAlias: "g",
493
+ type: ArgumentValueTypeName.STRING,
494
+ allowableValues: ["foo"],
495
+ defaultValue: "bar",
496
+ }],
497
+ }],
498
+ }], []);
499
+
500
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
501
+ .toThrow();
502
+
503
+ command = getSubCommand("command", [{
504
+ name: "alpha",
505
+ shortAlias: "a",
506
+ type: ComplexValueTypeName.COMPLEX,
507
+ isArray: true,
508
+ properties: [{
509
+ name: "beta",
510
+ shortAlias: "b",
511
+ type: ComplexValueTypeName.COMPLEX,
512
+ isArray: true,
513
+ properties: [{
514
+ name: "gamma",
515
+ shortAlias: "g",
516
+ type: ArgumentValueTypeName.STRING,
517
+ allowableValues: ["foo", "bar"],
518
+ defaultValue: "bar",
519
+ }],
520
+ }],
521
+ }], []);
522
+ new CommandValidator(getCLIConfig()).validate(command);
523
+ },
524
+ );
525
+
526
+ test(
527
+ "SubCommand validation fails due to the type of nested property complex option defaultValue" +
528
+ " not matching the type specified in argument type",
529
+ () => {
530
+ const command = getSubCommand("command", [{
531
+ name: "alpha",
532
+ shortAlias: "a",
533
+ type: ComplexValueTypeName.COMPLEX,
534
+ isArray: true,
535
+ properties: [{
536
+ name: "beta",
537
+ shortAlias: "b",
538
+ type: ComplexValueTypeName.COMPLEX,
539
+ isArray: true,
540
+ properties: [{
541
+ name: "gamma",
542
+ shortAlias: "g",
543
+ type: ArgumentValueTypeName.BOOLEAN,
544
+ defaultValue: 1,
545
+ }],
546
+ }],
547
+ }], []);
548
+
549
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
550
+ .toThrow();
551
+ },
552
+ );
553
+
554
+ test(
555
+ "SubCommand validation fails due to nested property complex option defaultValue" +
556
+ " being an array and option does not support array",
557
+ () => {
558
+ const command = getSubCommand("command", [{
559
+ name: "alpha",
560
+ shortAlias: "a",
561
+ type: ComplexValueTypeName.COMPLEX,
562
+ isArray: true,
563
+ properties: [{
564
+ name: "beta",
565
+ shortAlias: "b",
566
+ type: ComplexValueTypeName.COMPLEX,
567
+ isArray: true,
568
+ properties: [{
569
+ name: "gamma",
570
+ shortAlias: "g",
571
+ type: ArgumentValueTypeName.STRING,
572
+ defaultValue: ["foo", "bar"],
573
+ }],
574
+ }],
575
+ }], []);
576
+
577
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
578
+ .toThrow();
579
+ },
580
+ );
581
+
582
+ test(
583
+ "SubCommand validation fails due to the type of nested property values in complex option" +
584
+ " allowableValues not matching the type specified in argument type",
585
+ () => {
586
+ let command = getSubCommand("command", [{
587
+ name: "alpha",
588
+ type: ComplexValueTypeName.COMPLEX,
589
+ isArray: true,
590
+ defaultValue: [
591
+ {
592
+ beta: 1,
593
+ },
594
+ ],
595
+ properties: [{
596
+ name: "beta",
597
+ type: ComplexValueTypeName.COMPLEX,
598
+ properties: [{
599
+ name: "gamma",
600
+ type: ArgumentValueTypeName.BOOLEAN,
601
+ }],
602
+ }],
603
+ }], []);
604
+
605
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
606
+ .toThrow();
607
+
608
+ command = getSubCommand("command", [{
609
+ name: "alpha",
610
+ type: ComplexValueTypeName.COMPLEX,
611
+ isArray: true,
612
+ defaultValue: [
613
+ {
614
+ beta: {
615
+ gamma: 1,
616
+ },
617
+ },
618
+ ],
619
+ properties: [{
620
+ name: "beta",
621
+ type: ComplexValueTypeName.COMPLEX,
622
+ properties: [{
623
+ name: "gamma",
624
+ type: ArgumentValueTypeName.BOOLEAN,
625
+ }],
626
+ }],
627
+ }], []);
628
+
629
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
630
+ .toThrow();
631
+
632
+ command = getSubCommand("command", [{
633
+ name: "alpha",
634
+ type: ComplexValueTypeName.COMPLEX,
635
+ isArray: true,
636
+ defaultValue: [
637
+ {
638
+ beta: {
639
+ gamma: "foo",
640
+ },
641
+ },
642
+ ],
643
+ properties: [{
644
+ name: "beta",
645
+ type: ComplexValueTypeName.COMPLEX,
646
+ properties: [{
647
+ name: "gamma",
648
+ type: ArgumentValueTypeName.STRING,
649
+ }],
650
+ }],
651
+ }], []);
652
+
653
+ new CommandValidator(getCLIConfig()).validate(command);
654
+ },
655
+ );
656
+
657
+ test("SubCommand validation fails due to invalid complex option property name", () => {
658
+ let command = getSubCommand("command", [{
659
+ name: "alpha",
660
+ type: ComplexValueTypeName.COMPLEX,
661
+ isArray: true,
662
+ properties: [{
663
+ name: "-beta",
664
+ type: ComplexValueTypeName.COMPLEX,
665
+ properties: [{
666
+ name: "gamma",
667
+ type: ArgumentValueTypeName.STRING,
668
+ }],
669
+ }],
670
+ }], []);
671
+
672
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
673
+ .toThrow();
674
+ command = getSubCommand("command", [{
675
+ name: "alpha",
676
+ type: ComplexValueTypeName.COMPLEX,
677
+ isArray: true,
678
+ properties: [{
679
+ name: "beta",
680
+ type: ComplexValueTypeName.COMPLEX,
681
+ properties: [{
682
+ name: "gamma",
683
+ type: ArgumentValueTypeName.STRING,
684
+ }],
685
+ }],
686
+ }], []);
687
+
688
+ new CommandValidator(getCLIConfig()).validate(command);
689
+ });
690
+
691
+ test("SubCommand validation fails due to invalid complex option property short alias", () => {
692
+ let command = getSubCommand("command", [{
693
+ name: "alpha",
694
+ type: ComplexValueTypeName.COMPLEX,
695
+ isArray: true,
696
+ properties: [{
697
+ name: "beta",
698
+ shortAlias: "-",
699
+ type: ComplexValueTypeName.COMPLEX,
700
+ properties: [{
701
+ name: "gamma",
702
+ type: ArgumentValueTypeName.STRING,
703
+ }],
704
+ }],
705
+ }], []);
706
+
707
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
708
+ .toThrow();
709
+
710
+ command = getSubCommand("command", [{
711
+ name: "alpha",
712
+ type: ComplexValueTypeName.COMPLEX,
713
+ isArray: true,
714
+ properties: [{
715
+ name: "beta",
716
+ shortAlias: "b",
717
+ type: ComplexValueTypeName.COMPLEX,
718
+ properties: [{
719
+ name: "gamma",
720
+ type: ArgumentValueTypeName.STRING,
721
+ }],
722
+ }],
723
+ }], []);
724
+
725
+ new CommandValidator(getCLIConfig()).validate(command);
726
+ });
727
+
728
+ test("SubCommand validation fails due to custom configuration key when not enabled", () => {
729
+ let command = getSubCommand("command", [{
730
+ name: "foo",
731
+ type: ArgumentValueTypeName.STRING,
732
+ configurationKey: "FOO_BAR",
733
+ }], []);
734
+
735
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
736
+ .toThrowError(
737
+ "Command: 'command' enableConfiguration is false, but an argument defines a configurationKey: 'FOO_BAR'",
738
+ );
739
+
740
+ command = getSubCommand(
741
+ "command",
742
+ [{
743
+ name: "foo",
744
+ type: ArgumentValueTypeName.STRING,
745
+ configurationKey: "FOO_BAR",
746
+ }],
747
+ [],
748
+ true,
749
+ );
750
+
751
+ new CommandValidator(getCLIConfig()).validate(command);
752
+ });
753
+
754
+ test("SubCommand validation fails due to duplicate custom configuration key", () => {
755
+ let command = getSubCommand("command", [{
756
+ name: "foo1",
757
+ type: ArgumentValueTypeName.STRING,
758
+ configurationKey: "FOO_BAR",
759
+ }], [{
760
+ name: "foo2",
761
+ type: ArgumentValueTypeName.STRING,
762
+ configurationKey: "FOO_BAR",
763
+ }], true);
764
+
765
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
766
+ .toThrowError(
767
+ "Command: 'command' contains arguments with the same configuration key: 'FOO_BAR'",
768
+ );
769
+
770
+ command = getSubCommand("command", [{
771
+ name: "foo1",
772
+ type: ArgumentValueTypeName.STRING,
773
+ configurationKey: "FOO_BAR_1",
774
+ }], [{
775
+ name: "foo2",
776
+ type: ArgumentValueTypeName.STRING,
777
+ configurationKey: "FOO_BAR_2",
778
+ }], true);
779
+
780
+ new CommandValidator(getCLIConfig()).validate(command);
781
+ });
782
+
783
+ test("SubCommand validation fails due to invalid configuration key", () => {
784
+ let command = getSubCommand(
785
+ "command",
786
+ [{
787
+ name: "foo1",
788
+ type: ArgumentValueTypeName.STRING,
789
+ configurationKey: "-FOO_BAR",
790
+ }],
791
+ [],
792
+ true,
793
+ );
794
+
795
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
796
+ .toThrowError(
797
+ "Illegal configuration key: '-FOO_BAR'",
798
+ );
799
+
800
+ command = getSubCommand(
801
+ "command",
802
+ [{
803
+ name: "foo1",
804
+ type: ArgumentValueTypeName.STRING,
805
+ configurationKey: "3_FOO_BAR_1",
806
+ }],
807
+ [],
808
+ true,
809
+ );
810
+
811
+ expect(() => new CommandValidator(getCLIConfig()).validate(command))
812
+ .toThrowError(
813
+ "Illegal configuration key: '3_FOO_BAR_1'",
814
+ );
815
+ });
816
+ });