@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,123 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { expectBytesEquals } from "../../fixtures/util.ts";
3
+ import DefaultSyntaxHighlighterService from "../../../src/service/syntaxHighlighter/DefaultSyntaxHighlighterService.ts";
4
+ import yaml from "highlight.js/lib/languages/yaml";
5
+
6
+ describe("DefaultSyntaxHighlighterService Tests", () => {
7
+ test("JSON registered by default", () => {
8
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
9
+
10
+ expect(syntaxHighlighterService.getRegisteredSyntaxes()).toEqual(["json"]);
11
+ });
12
+
13
+ test("Cannot register a syntax if already registered", () => {
14
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
15
+
16
+ expect(() => syntaxHighlighterService.registerSyntax("jSon", yaml))
17
+ .toThrow();
18
+ });
19
+
20
+ test("Can register new syntax", () => {
21
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
22
+
23
+ syntaxHighlighterService.registerSyntax("yaml", yaml);
24
+ expect(syntaxHighlighterService.getRegisteredSyntaxes()).toEqual([
25
+ "json",
26
+ "yaml",
27
+ ]);
28
+ });
29
+
30
+ test("Cannot highlight with unknown syntax", () => {
31
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
32
+
33
+ expect(() => syntaxHighlighterService.highlight("foo: 1", "yaml"))
34
+ .toThrow();
35
+ });
36
+
37
+ test("Can highlight with JSON syntax", () => {
38
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
39
+
40
+ syntaxHighlighterService.registerSyntax("yaml", yaml);
41
+
42
+ const highlighted = syntaxHighlighterService.highlight(
43
+ "{ foo: 1 }",
44
+ "json",
45
+ );
46
+ expectBytesEquals(
47
+ highlighted,
48
+ new Uint8Array([
49
+ 123,
50
+ 32,
51
+ 102,
52
+ 111,
53
+ 111,
54
+ 58,
55
+ 32,
56
+ 27,
57
+ 91,
58
+ 51,
59
+ 54,
60
+ 109,
61
+ 49,
62
+ 27,
63
+ 91,
64
+ 51,
65
+ 57,
66
+ 109,
67
+ 32,
68
+ 125,
69
+ ]),
70
+ );
71
+ });
72
+
73
+ test("Can highlight with newly registered syntax", () => {
74
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
75
+
76
+ syntaxHighlighterService.registerSyntax("yaml", yaml);
77
+
78
+ const highlighted = syntaxHighlighterService.highlight("foo: 1", "yaml");
79
+ expectBytesEquals(
80
+ highlighted,
81
+ new Uint8Array([
82
+ 27,
83
+ 91,
84
+ 51,
85
+ 51,
86
+ 109,
87
+ 102,
88
+ 111,
89
+ 111,
90
+ 58,
91
+ 27,
92
+ 91,
93
+ 51,
94
+ 57,
95
+ 109,
96
+ 32,
97
+ 27,
98
+ 91,
99
+ 51,
100
+ 54,
101
+ 109,
102
+ 49,
103
+ 27,
104
+ 91,
105
+ 51,
106
+ 57,
107
+ 109,
108
+ ]),
109
+ );
110
+ });
111
+
112
+ test("Skipped if color disabled", () => {
113
+ const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
114
+ syntaxHighlighterService.colorEnabled = false;
115
+
116
+ const highlighted = syntaxHighlighterService.highlight(
117
+ "{ foo: 1 }",
118
+ "json",
119
+ );
120
+
121
+ expect(highlighted).toEqual("{ foo: 1 }");
122
+ });
123
+ });
@@ -0,0 +1,41 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import DefaultContext from "../../../src/runtime/DefaultContext.ts";
3
+ import { getCLIConfig } from "../../fixtures/CLIConfig.ts";
4
+ import SyntaxHighlighterServiceProvider from "../../../src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts";
5
+ import { PRINTER_SERVICE_ID } from "../../../src/api/service/core/PrinterService.ts";
6
+ import DefaultPrinterService from "../../../src/service/printer/DefaultPrinterService.ts";
7
+ import StreamString from "../../fixtures/StreamString.ts";
8
+ import TtyTerminal from "../../../src/service/printer/terminal/TtyTerminal.ts";
9
+ import TtyStyler from "../../../src/service/printer/terminal/TtyStyler.ts";
10
+
11
+ describe("SyntaxHighlighterServiceProvider Tests", () => {
12
+ test("SyntaxHighlighterServiceProvider provide and initService works", async () => {
13
+ const dummyStdout = new StreamString();
14
+ const dummyStderr = new StreamString();
15
+ const syntaxHighlighterServiceProvider =
16
+ new SyntaxHighlighterServiceProvider(
17
+ 100,
18
+ );
19
+ const cliConfig = getCLIConfig();
20
+ const context = new DefaultContext(cliConfig);
21
+
22
+ context.addServiceInstance(
23
+ PRINTER_SERVICE_ID,
24
+ new DefaultPrinterService(
25
+ dummyStdout.writableStream,
26
+ dummyStderr.writableStream,
27
+ true,
28
+ true,
29
+ new TtyTerminal(dummyStderr.writeStream),
30
+ new TtyStyler(3),
31
+ ),
32
+ );
33
+
34
+ const serviceInfo = await syntaxHighlighterServiceProvider.provide(
35
+ cliConfig,
36
+ );
37
+ expect(serviceInfo.commands.length).toEqual(0);
38
+
39
+ await syntaxHighlighterServiceProvider.initService(context);
40
+ });
41
+ });
@@ -0,0 +1,275 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ getGlobalCommandArgumentConfigurationKey,
4
+ getSubCommandArgumentConfigurationKey,
5
+ } from "../../src/util/configHelper.ts";
6
+ import { getCLIConfig } from "../fixtures/CLIConfig.ts";
7
+ import {
8
+ getGlobalCommand,
9
+ getSubCommandWithComplexOptions,
10
+ getSubCommandWithOption,
11
+ getSubCommandWithPositional,
12
+ } from "../fixtures/Command.ts";
13
+ import { ArgumentValueTypeName } from "../../src/api/argument/ArgumentValueTypes.ts";
14
+ import type ComplexOption from "../../src/api/argument/ComplexOption.ts";
15
+ import type Option from "../../src/api/argument/Option.ts";
16
+ import type SubCommandArgument from "../../src/api/argument/SubCommandArgument.ts";
17
+
18
+ describe("configHelper Tests", () => {
19
+ test("getConfigurationKey works for global argument", () => {
20
+ let command = getGlobalCommand("blah", true);
21
+
22
+ expect(
23
+ getGlobalCommandArgumentConfigurationKey(
24
+ getCLIConfig(),
25
+ command,
26
+ command.argument!,
27
+ ),
28
+ ).toBeUndefined();
29
+
30
+ command = getGlobalCommand("blah", true, false, true);
31
+
32
+ expect(
33
+ getGlobalCommandArgumentConfigurationKey(
34
+ getCLIConfig(),
35
+ command,
36
+ command.argument!,
37
+ ),
38
+ ).toEqual(
39
+ "FOO_BLAH",
40
+ );
41
+
42
+ command = getGlobalCommand("blah", true, false, true, "FOO_BAR");
43
+
44
+ expect(
45
+ getGlobalCommandArgumentConfigurationKey(
46
+ getCLIConfig(),
47
+ command,
48
+ command.argument!,
49
+ ),
50
+ "FOO_BAR",
51
+ );
52
+ });
53
+
54
+ test("getConfigurationKey works for positional argument", () => {
55
+ let command = getSubCommandWithPositional("blah", true, true);
56
+
57
+ expect(
58
+ getSubCommandArgumentConfigurationKey(getCLIConfig(), command, [
59
+ command.positionals![0],
60
+ ]),
61
+ ).toBeUndefined();
62
+
63
+ command = getSubCommandWithPositional(
64
+ "blah",
65
+ true,
66
+ false,
67
+ ArgumentValueTypeName.BOOLEAN,
68
+ true,
69
+ );
70
+
71
+ expect(
72
+ getSubCommandArgumentConfigurationKey(getCLIConfig(), command, [
73
+ command.positionals![0],
74
+ ]),
75
+ ).toEqual(
76
+ "FOO_BLAH_FOO",
77
+ );
78
+
79
+ command = getSubCommandWithPositional(
80
+ "blah",
81
+ true,
82
+ true,
83
+ ArgumentValueTypeName.BOOLEAN,
84
+ true,
85
+ );
86
+
87
+ expect(
88
+ getSubCommandArgumentConfigurationKey(getCLIConfig(), command, [
89
+ command.positionals![0],
90
+ ]),
91
+ ).toEqual(
92
+ "FOO_BLAH_FOO[_<index>]",
93
+ );
94
+
95
+ command = getSubCommandWithPositional(
96
+ "blah",
97
+ true,
98
+ true,
99
+ ArgumentValueTypeName.BOOLEAN,
100
+ true,
101
+ "FOO_BAR",
102
+ );
103
+
104
+ expect(
105
+ getSubCommandArgumentConfigurationKey(getCLIConfig(), command, [
106
+ command.positionals![0],
107
+ ]),
108
+ ).toEqual(
109
+ "FOO_BAR[_<index>]",
110
+ );
111
+ });
112
+
113
+ test("getConfigurationKey works for simple option argument", () => {
114
+ let command = getSubCommandWithOption("blah", true, false, true);
115
+
116
+ expect(
117
+ getSubCommandArgumentConfigurationKey(
118
+ getCLIConfig(),
119
+ command,
120
+ [command.options![0] as Option],
121
+ ),
122
+ ).toBeUndefined();
123
+
124
+ command = getSubCommandWithOption(
125
+ "blah",
126
+ true,
127
+ false,
128
+ false,
129
+ ArgumentValueTypeName.BOOLEAN,
130
+ undefined,
131
+ true,
132
+ );
133
+
134
+ expect(
135
+ getSubCommandArgumentConfigurationKey(
136
+ getCLIConfig(),
137
+ command,
138
+ [command.options![0] as Option],
139
+ ),
140
+ ).toEqual(
141
+ "FOO_BLAH_FOO",
142
+ );
143
+
144
+ command = getSubCommandWithOption(
145
+ "blah",
146
+ true,
147
+ false,
148
+ true,
149
+ ArgumentValueTypeName.BOOLEAN,
150
+ undefined,
151
+ true,
152
+ );
153
+
154
+ expect(
155
+ getSubCommandArgumentConfigurationKey(
156
+ getCLIConfig(),
157
+ command,
158
+ [command.options![0] as Option],
159
+ ),
160
+ ).toEqual(
161
+ "FOO_BLAH_FOO[_<index>]",
162
+ );
163
+
164
+ command = getSubCommandWithOption(
165
+ "blah",
166
+ true,
167
+ false,
168
+ true,
169
+ ArgumentValueTypeName.BOOLEAN,
170
+ undefined,
171
+ true,
172
+ "FOO_BAR",
173
+ );
174
+
175
+ expect(
176
+ getSubCommandArgumentConfigurationKey(
177
+ getCLIConfig(),
178
+ command,
179
+ [command.options![0] as Option],
180
+ ),
181
+ ).toEqual(
182
+ "FOO_BAR[_<index>]",
183
+ );
184
+ });
185
+
186
+ test("getConfigurationKey works for complex option argument", () => {
187
+ let command = getSubCommandWithComplexOptions();
188
+
189
+ let arg0 = command.options![0] as ComplexOption;
190
+ let arg1 = arg0.properties[0] as ComplexOption;
191
+ let arg2 = arg1.properties[0] as Option;
192
+
193
+ expect(
194
+ getSubCommandArgumentConfigurationKey(
195
+ getCLIConfig(),
196
+ command,
197
+ [
198
+ arg0 as unknown as SubCommandArgument,
199
+ arg1 as unknown as SubCommandArgument,
200
+ arg2 as unknown as SubCommandArgument,
201
+ ],
202
+ ),
203
+ ).toBeUndefined();
204
+
205
+ command = getSubCommandWithComplexOptions(true, true);
206
+
207
+ arg0 = command.options![0] as ComplexOption;
208
+ arg1 = arg0.properties[0] as ComplexOption;
209
+ arg2 = arg1.properties[0] as Option;
210
+
211
+ expect(
212
+ getSubCommandArgumentConfigurationKey(
213
+ getCLIConfig(),
214
+ command,
215
+ [
216
+ arg0 as unknown as SubCommandArgument,
217
+ arg1 as unknown as SubCommandArgument,
218
+ arg2 as unknown as SubCommandArgument,
219
+ ],
220
+ ),
221
+ ).toEqual(
222
+ "FOO_SUBCOMMAND_ALPHA[_<index>]_BETA[_<index>]_GAMMA",
223
+ );
224
+
225
+ arg2 = arg1.properties[1] as Option;
226
+
227
+ expect(
228
+ getSubCommandArgumentConfigurationKey(
229
+ getCLIConfig(),
230
+ command,
231
+ [
232
+ arg0 as unknown as SubCommandArgument,
233
+ arg1 as unknown as SubCommandArgument,
234
+ arg2 as unknown as SubCommandArgument,
235
+ ],
236
+ ),
237
+ ).toEqual(
238
+ "FOO_SUBCOMMAND_ALPHA[_<index>]_BETA[_<index>]_DELTA[_<index>]",
239
+ );
240
+
241
+ arg0 = command.options![1] as ComplexOption;
242
+ arg1 = arg0.properties[0] as ComplexOption;
243
+
244
+ expect(
245
+ getSubCommandArgumentConfigurationKey(
246
+ getCLIConfig(),
247
+ command,
248
+ [
249
+ arg0 as unknown as SubCommandArgument,
250
+ arg1 as unknown as SubCommandArgument,
251
+ ],
252
+ ),
253
+ ).toEqual(
254
+ "FOO_SUBCOMMAND_EPSILON_FOO_BAR_A",
255
+ );
256
+
257
+ command = getSubCommandWithComplexOptions(true, true, true);
258
+
259
+ arg0 = command.options![1] as ComplexOption;
260
+ arg1 = arg0.properties[1] as ComplexOption;
261
+
262
+ expect(
263
+ getSubCommandArgumentConfigurationKey(
264
+ getCLIConfig(),
265
+ command,
266
+ [
267
+ arg0 as unknown as SubCommandArgument,
268
+ arg1 as unknown as SubCommandArgument,
269
+ ],
270
+ ),
271
+ ).toEqual(
272
+ "FOO_SUBCOMMAND_EPSILON_FOO_BAR_B[_<index>]",
273
+ );
274
+ });
275
+ });