@flowscripter/dynamic-cli-framework 1.1.6 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/.github/workflows/release-bun-library.yml +1 -0
  2. package/README/core-commands.md +40 -0
  3. package/README/core-service-providers.md +198 -0
  4. package/README/development.md +60 -0
  5. package/README/implementation-details.md +474 -0
  6. package/README/key-concepts.md +751 -0
  7. package/README.md +12 -1413
  8. package/bun.lock +22 -18
  9. package/index.ts +97 -1
  10. package/package.json +8 -7
  11. package/src/api/BaseCLIFeatureOptions.ts +10 -0
  12. package/src/api/CLIConfig.ts +5 -0
  13. package/src/api/RunResult.ts +16 -0
  14. package/src/api/argument/Argument.ts +24 -0
  15. package/src/api/service/ServiceProvider.ts +3 -3
  16. package/src/api/service/core/ArgumentPrompterService.ts +10 -0
  17. package/src/api/service/core/AsciiBannerGeneratorService.ts +44 -7
  18. package/src/api/service/core/CompletionService.ts +36 -0
  19. package/src/api/service/core/DataDumpGeneratorService.ts +27 -0
  20. package/src/api/service/core/ImagePrinterService.ts +26 -0
  21. package/src/api/service/core/KeyValueService.ts +22 -5
  22. package/src/api/service/core/PrinterService.ts +127 -1
  23. package/src/api/service/core/PrompterService.ts +49 -0
  24. package/src/api/service/core/SecretService.ts +27 -0
  25. package/src/api/service/core/ShutdownService.ts +17 -1
  26. package/src/api/service/core/Table.ts +85 -0
  27. package/src/api/service/core/TableGeneratorService.ts +38 -0
  28. package/src/api/service/core/TreePrinterService.ts +11 -0
  29. package/src/cli/BaseCLI.ts +116 -44
  30. package/src/cli/DefaultRuntimeCLI.ts +10 -18
  31. package/src/command/CompletionCommand.ts +179 -0
  32. package/src/command/MultiCommandCliHelpCommand.ts +18 -2
  33. package/src/command/SingleCommandCliHelpCommand.ts +10 -1
  34. package/src/launcher.ts +16 -58
  35. package/src/runtime/command/CommandValidator.ts +3 -3
  36. package/src/runtime/runner.ts +102 -30
  37. package/src/runtime/scanner.ts +18 -15
  38. package/src/runtime/values/argumentValueValidation.ts +49 -5
  39. package/src/runtime/values/globalCommandValuePopulation.ts +1 -1
  40. package/src/runtime/values/subCommandValuePopulation.ts +9 -8
  41. package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +34 -0
  42. package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +330 -0
  43. package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +1 -1
  44. package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +254 -17
  45. package/src/service/banner/BannerServiceProvider.ts +2 -2
  46. package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +85 -0
  47. package/src/service/chiselAsciiBannerGenerator/chisel.flf.json +3 -0
  48. package/src/service/completion/CompletionServiceProvider.ts +212 -0
  49. package/src/service/completion/DefaultCompletionService.ts +364 -0
  50. package/src/service/completion/shell/ShellHandler.ts +16 -0
  51. package/src/service/completion/shell/bash.ts +47 -0
  52. package/src/service/completion/shell/fish.ts +43 -0
  53. package/src/service/completion/shell/powershell.ts +66 -0
  54. package/src/service/completion/shell/zsh.ts +50 -0
  55. package/src/service/configuration/ConfigurationServiceProvider.ts +138 -42
  56. package/src/service/configuration/DefaultKeyValueService.ts +53 -7
  57. package/src/service/configuration/DefaultSecretService.ts +85 -0
  58. package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +41 -0
  59. package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +80 -0
  60. package/src/service/imagePrinter/DefaultImagePrinterService.ts +23 -0
  61. package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +32 -0
  62. package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +1 -1
  63. package/src/service/printer/DefaultPrinterService.ts +147 -27
  64. package/src/service/printer/PrinterServiceProvider.ts +7 -7
  65. package/src/service/printer/command/NoHyperlinksCommand.ts +40 -0
  66. package/src/service/printer/terminal/Progress.ts +21 -4
  67. package/src/service/printer/terminal/Spinner.ts +32 -8
  68. package/src/service/printer/terminal/Theme.ts +1 -1
  69. package/src/service/prompter/DefaultPrompterService.ts +87 -0
  70. package/src/service/prompter/PrompterServiceProvider.ts +36 -0
  71. package/src/service/prompter/command/NoPromptCommand.ts +40 -0
  72. package/src/service/prompter/prompt/PromptContext.ts +47 -0
  73. package/src/service/prompter/prompt/promptAcknowledge.ts +28 -0
  74. package/src/service/prompter/prompt/promptMultiSelect.ts +99 -0
  75. package/src/service/prompter/prompt/promptOpenUrl.ts +97 -0
  76. package/src/service/prompter/prompt/promptSingleSelect.ts +102 -0
  77. package/src/service/prompter/prompt/promptText.ts +107 -0
  78. package/src/service/prompter/prompt/promptToggle.ts +28 -0
  79. package/src/service/shutdown/DefaultShutdownService.ts +13 -0
  80. package/src/service/shutdown/ShutdownServiceProvider.ts +28 -9
  81. package/src/service/shutdown/ShutdownState.ts +5 -0
  82. package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +1 -1
  83. package/src/service/tableGenerator/DefaultTableGeneratorService.ts +415 -0
  84. package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +43 -0
  85. package/src/service/treePrinter/DefaultTreePrinterService.ts +49 -0
  86. package/src/service/treePrinter/TreePrinterServiceProvider.ts +40 -0
  87. package/src/terminal/Ansi.ts +27 -0
  88. package/src/terminal/ImageRenderer.ts +199 -0
  89. package/src/terminal/KeyReader.ts +23 -0
  90. package/src/terminal/PngDecoder.ts +143 -0
  91. package/src/{service/printer/terminal → terminal}/Styler.ts +3 -0
  92. package/src/{service/printer/terminal → terminal}/Terminal.ts +1 -0
  93. package/src/terminal/TtyKeyReader.ts +83 -0
  94. package/src/terminal/TtyStyler.ts +78 -0
  95. package/src/{service/printer/terminal → terminal}/TtyTerminal.ts +9 -1
  96. package/src/terminal/supportsHyperlinks.ts +110 -0
  97. package/src/util/configHelper.ts +2 -2
  98. package/src/util/envVarHelper.ts +2 -2
  99. package/src/util/helpHelper.ts +66 -122
  100. package/src/util/logger.ts +16 -14
  101. package/src/util/runnerHelper.ts +1 -1
  102. package/tests/cli/BaseCLI.test.ts +50 -54
  103. package/tests/command/CompletionCommand.test.ts +68 -0
  104. package/tests/command/UsageCommand.test.ts +3 -2
  105. package/tests/command/VersionCommand.test.ts +3 -2
  106. package/tests/fixtures/Context.ts +9 -2
  107. package/tests/fixtures/util.ts +1 -1
  108. package/tests/runtime/parser.test.ts +9 -7
  109. package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +3 -3
  110. package/tests/runtime/values/argumentValueValidation.test.ts +193 -0
  111. package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +47 -0
  112. package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +754 -0
  113. package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +5 -4
  114. package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +163 -3
  115. package/tests/service/asciiBannerGenerator/__snapshots__/DefaultAsciiBannerGeneratorService.test.ts.snap +1 -1
  116. package/tests/service/banner/BannerServiceProvider.test.ts +8 -4
  117. package/tests/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.test.ts +52 -0
  118. package/tests/service/completion/CompletionServiceProvider.test.ts +404 -0
  119. package/tests/service/completion/DefaultCompletionService.test.ts +278 -0
  120. package/tests/service/completion/shell/bash.test.ts +73 -0
  121. package/tests/service/completion/shell/fish.test.ts +62 -0
  122. package/tests/service/completion/shell/powershell.test.ts +59 -0
  123. package/tests/service/completion/shell/zsh.test.ts +60 -0
  124. package/tests/service/configuration/ConfigurationServiceProvider.test.ts +24 -12
  125. package/tests/service/configuration/DefaultKeyValueService.test.ts +118 -16
  126. package/tests/service/configuration/DefaultSecretService.test.ts +148 -0
  127. package/tests/service/configuration/command/ConfigCommand.test.ts +29 -0
  128. package/tests/service/configuration/command/DumpConfigCommand.test.ts +60 -0
  129. package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +57 -0
  130. package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +217 -0
  131. package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +96 -0
  132. package/tests/service/imagePrinter/ImagePrinterServiceProvider.test.ts +17 -0
  133. package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +2 -2
  134. package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +5 -4
  135. package/tests/service/printer/DefaultPrinterService.test.ts +233 -2
  136. package/tests/service/printer/PrinterServiceProvider.test.ts +6 -5
  137. package/tests/service/printer/command/DarkModeCommand.test.ts +83 -0
  138. package/tests/service/printer/command/LogLevelCommand.test.ts +7 -5
  139. package/tests/service/printer/command/NoColorCommand.test.ts +83 -0
  140. package/tests/service/printer/command/NoHyperlinksCommand.test.ts +89 -0
  141. package/tests/service/printer/terminal/Progress.test.ts +64 -4
  142. package/tests/service/printer/terminal/Spinner.test.ts +44 -3
  143. package/tests/service/prompter/DefaultPrompterService.test.ts +615 -0
  144. package/tests/service/prompter/PrompterServiceProvider.test.ts +47 -0
  145. package/tests/service/prompter/command/NoPromptCommand.test.ts +58 -0
  146. package/tests/service/shutdown/ShutdownServiceProvider.test.ts +4 -2
  147. package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +3 -2
  148. package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +5 -4
  149. package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +363 -0
  150. package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +47 -0
  151. package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +144 -0
  152. package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +55 -0
  153. package/tests/terminal/ImageRenderer.test.ts +161 -0
  154. package/tests/terminal/PngDecoder.test.ts +223 -0
  155. package/tests/terminal/supportsHyperlinks.test.ts +149 -0
  156. package/tests/util/configHelper.test.ts +4 -4
  157. package/tests/util/logger.test.ts +23 -1
  158. package/tsconfig.json +31 -0
  159. package/src/service/printer/terminal/Ansi.ts +0 -10
  160. package/src/service/printer/terminal/TtyStyler.ts +0 -39
@@ -6,8 +6,8 @@ import { PRINTER_SERVICE_ID } from "../../src/api/service/core/PrinterService.ts
6
6
  import DefaultPrinterService from "../../src/service/printer/DefaultPrinterService.ts";
7
7
  import StreamString from "../fixtures/StreamString.ts";
8
8
  import { expectStringEquals } from "../fixtures/util.ts";
9
- import TtyTerminal from "../../src/service/printer/terminal/TtyTerminal.ts";
10
- import TtyStyler from "../../src/service/printer/terminal/TtyStyler.ts";
9
+ import TtyTerminal from "../../src/terminal/TtyTerminal.ts";
10
+ import TtyStyler from "../../src/terminal/TtyStyler.ts";
11
11
 
12
12
  describe("VersionCommand tests", () => {
13
13
  test("Version works", async () => {
@@ -18,6 +18,7 @@ describe("VersionCommand tests", () => {
18
18
  dummyStderr.writableStream,
19
19
  true,
20
20
  true,
21
+ new TtyTerminal(dummyStdout.writeStream),
21
22
  new TtyTerminal(dummyStderr.writeStream),
22
23
  new TtyStyler(3),
23
24
  );
@@ -6,8 +6,10 @@ import DefaultKeyValueService from "../../src/service/configuration/DefaultKeyVa
6
6
  import { KEY_VALUE_SERVICE_ID } from "../../src/api/service/core/KeyValueService.ts";
7
7
  import type Context from "../../src/api/Context.ts";
8
8
  import WritableStreamString from "./StreamString.ts";
9
- import TtyTerminal from "../../src/service/printer/terminal/TtyTerminal.ts";
10
- import TtyStyler from "../../src/service/printer/terminal/TtyStyler.ts";
9
+ import TtyTerminal from "../../src/terminal/TtyTerminal.ts";
10
+ import TtyStyler from "../../src/terminal/TtyStyler.ts";
11
+ import { TABLE_GENERATOR_SERVICE_ID } from "../../src/api/service/core/TableGeneratorService.ts";
12
+ import DefaultTableGeneratorService from "../../src/service/tableGenerator/DefaultTableGeneratorService.ts";
11
13
 
12
14
  export function getContext(
13
15
  streamString: WritableStreamString,
@@ -19,6 +21,7 @@ export function getContext(
19
21
  false,
20
22
  false,
21
23
  new TtyTerminal(streamString.writeStream),
24
+ new TtyTerminal(streamString.writeStream),
22
25
  new TtyStyler(3),
23
26
  );
24
27
 
@@ -28,6 +31,10 @@ export function getContext(
28
31
  KEY_VALUE_SERVICE_ID,
29
32
  new DefaultKeyValueService(),
30
33
  );
34
+ defaultContext.addServiceInstance(
35
+ TABLE_GENERATOR_SERVICE_ID,
36
+ new DefaultTableGeneratorService(),
37
+ );
31
38
 
32
39
  return defaultContext;
33
40
  }
@@ -20,7 +20,7 @@ export function expectStringEquals(actual: string, expected: string) {
20
20
  }
21
21
 
22
22
  export function expectBytesEquals(actual: string, expected: Uint8Array) {
23
- expect(encoder.encode(actual)).toEqual(expected);
23
+ expect(encoder.encode(actual)).toEqual(expected as Uint8Array<ArrayBuffer>);
24
24
  }
25
25
 
26
26
  export function sleep(ms: number) {
@@ -386,7 +386,7 @@ describe("parser tests", () => {
386
386
  },
387
387
  };
388
388
 
389
- ((argumentValues.alpha as Array<PopulatedArgumentValues>)[0].beta as Array<
389
+ ((argumentValues.alpha as Array<PopulatedArgumentValues>)[0]!.beta as Array<
390
390
  PopulatedArgumentValues
391
391
  >)[1] = {
392
392
  gamma: "foo2",
@@ -439,12 +439,14 @@ describe("parser tests", () => {
439
439
  };
440
440
 
441
441
  // these are still stored as strings as the validation (and type conversion) failed fast
442
- (((argumentValues.alpha as Array<PopulatedArgumentValues>)[0].beta as Array<
443
- PopulatedArgumentValues
444
- >)[1].delta as Array<ArgumentValueType>)[0] = "0";
445
- (((argumentValues.alpha as Array<PopulatedArgumentValues>)[0].beta as Array<
446
- PopulatedArgumentValues
447
- >)[1].delta as Array<ArgumentValueType>)[2] = "2";
442
+ (((argumentValues.alpha as Array<PopulatedArgumentValues>)[0]!
443
+ .beta as Array<
444
+ PopulatedArgumentValues
445
+ >)[1]!.delta as Array<ArgumentValueType>)[0] = "0";
446
+ (((argumentValues.alpha as Array<PopulatedArgumentValues>)[0]!
447
+ .beta as Array<
448
+ PopulatedArgumentValues
449
+ >)[1]!.delta as Array<ArgumentValueType>)[2] = "2";
448
450
 
449
451
  expectParseResult(parseResult, {
450
452
  command: subCommand,
@@ -14,7 +14,7 @@ function getServiceProvider(
14
14
  return {
15
15
  serviceId,
16
16
  servicePriority,
17
- provide(_cliConfig: CLIConfig): Promise<ServiceInfo> {
17
+ getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
18
18
  return Promise.resolve({
19
19
  service: {},
20
20
  commands: [],
@@ -36,7 +36,7 @@ describe("DefaultServiceProviderRegistry tests", () => {
36
36
  serviceProviderRegistry.addServiceProvider(serviceProvider2);
37
37
 
38
38
  const orderedServices = serviceProviderRegistry.getServiceProviders();
39
- expect(orderedServices[0].servicePriority).toEqual(2);
40
- expect(orderedServices[1].servicePriority).toEqual(1);
39
+ expect(orderedServices[0]!.servicePriority).toEqual(2);
40
+ expect(orderedServices[1]!.servicePriority).toEqual(1);
41
41
  });
42
42
  });
@@ -994,6 +994,199 @@ describe("argumentValueValidation tests", () => {
994
994
  }]);
995
995
  });
996
996
 
997
+ test("Option with custom validator that passes", () => {
998
+ const option: Option = {
999
+ name: "foo",
1000
+ type: ArgumentValueTypeName.STRING,
1001
+ validate: () => undefined,
1002
+ };
1003
+ const invalidArguments: Array<InvalidArgument> = [];
1004
+ expect(validateOptionValue(option, "hello", invalidArguments)).toEqual(
1005
+ "hello",
1006
+ );
1007
+ expect(invalidArguments).toEqual([]);
1008
+ });
1009
+
1010
+ test("Option with custom validator that fails", () => {
1011
+ const option: Option = {
1012
+ name: "foo",
1013
+ type: ArgumentValueTypeName.STRING,
1014
+ validate: (v) => (v as string).length < 3 ? "min 3 chars" : undefined,
1015
+ };
1016
+ const invalidArguments: Array<InvalidArgument> = [];
1017
+ expect(
1018
+ validateOptionValue(option, "ab", invalidArguments),
1019
+ ).toBeUndefined();
1020
+ expect(invalidArguments).toEqual([{
1021
+ argument: option,
1022
+ name: "foo",
1023
+ value: "ab",
1024
+ reason: InvalidArgumentReason.CUSTOM_VALIDATION,
1025
+ message: "min 3 chars",
1026
+ }]);
1027
+ });
1028
+
1029
+ test("Positional with custom validator that passes and fails", () => {
1030
+ const positional: Positional = {
1031
+ name: "count",
1032
+ type: ArgumentValueTypeName.NUMBER,
1033
+ validate: (v) => (v as number) % 2 !== 0 ? "must be even" : undefined,
1034
+ };
1035
+ let invalidArguments: Array<InvalidArgument> = [];
1036
+ expect(
1037
+ validatePositionalValue(positional, "4", invalidArguments),
1038
+ ).toEqual(4);
1039
+ expect(invalidArguments).toEqual([]);
1040
+
1041
+ invalidArguments = [];
1042
+ expect(
1043
+ validatePositionalValue(positional, "3", invalidArguments),
1044
+ ).toBeUndefined();
1045
+ expect(invalidArguments).toEqual([{
1046
+ argument: positional,
1047
+ name: "count",
1048
+ value: 3,
1049
+ reason: InvalidArgumentReason.CUSTOM_VALIDATION,
1050
+ message: "must be even",
1051
+ }]);
1052
+ });
1053
+
1054
+ test("GlobalCommand argument with custom validator that passes and fails", () => {
1055
+ const globalCommandArgument: GlobalCommandArgument = {
1056
+ type: ArgumentValueTypeName.STRING,
1057
+ validate: (v) =>
1058
+ (v as string).startsWith("x") ? undefined : "must start with x",
1059
+ };
1060
+ const globalCommand = getGlobalCommandWithShortAlias(
1061
+ "globalCommand",
1062
+ "f",
1063
+ globalCommandArgument,
1064
+ );
1065
+ let invalidArguments: Array<InvalidArgument> = [];
1066
+ expect(
1067
+ validateGlobalCommandArgumentValue(
1068
+ globalCommand,
1069
+ "xfoo",
1070
+ invalidArguments,
1071
+ ),
1072
+ ).toEqual("xfoo");
1073
+ expect(invalidArguments).toEqual([]);
1074
+
1075
+ invalidArguments = [];
1076
+ expect(
1077
+ validateGlobalCommandArgumentValue(
1078
+ globalCommand,
1079
+ "bar",
1080
+ invalidArguments,
1081
+ ),
1082
+ ).toBeUndefined();
1083
+ expect(invalidArguments).toEqual([{
1084
+ argument: globalCommandArgument,
1085
+ name: "globalCommand",
1086
+ value: "bar",
1087
+ reason: InvalidArgumentReason.CUSTOM_VALIDATION,
1088
+ message: "must start with x",
1089
+ }]);
1090
+ });
1091
+
1092
+ test("Option isArray with custom validator checking uniqueness", () => {
1093
+ const option: Option = {
1094
+ name: "tags",
1095
+ type: ArgumentValueTypeName.STRING,
1096
+ isArray: true,
1097
+ validate: (v) => {
1098
+ const arr = v as string[];
1099
+ return new Set(arr).size !== arr.length
1100
+ ? "values must be unique"
1101
+ : undefined;
1102
+ },
1103
+ };
1104
+ let invalidArguments: Array<InvalidArgument> = [];
1105
+ expect(
1106
+ validateOptionValue(option, ["a", "b", "c"], invalidArguments),
1107
+ ).toEqual(["a", "b", "c"]);
1108
+ expect(invalidArguments).toEqual([]);
1109
+
1110
+ invalidArguments = [];
1111
+ expect(
1112
+ validateOptionValue(option, ["a", "b", "a"], invalidArguments),
1113
+ ).toBeUndefined();
1114
+ expect(invalidArguments).toEqual([{
1115
+ argument: option,
1116
+ name: "tags",
1117
+ value: ["a", "b", "a"],
1118
+ reason: InvalidArgumentReason.CUSTOM_VALIDATION,
1119
+ message: "values must be unique",
1120
+ }]);
1121
+ });
1122
+
1123
+ test("Positional isVarargMultiple with custom validator checking uniqueness", () => {
1124
+ const positional: Positional = {
1125
+ name: "ids",
1126
+ type: ArgumentValueTypeName.NUMBER,
1127
+ isVarargMultiple: true,
1128
+ validate: (v) => {
1129
+ const arr = v as number[];
1130
+ return new Set(arr).size !== arr.length
1131
+ ? "values must be unique"
1132
+ : undefined;
1133
+ },
1134
+ };
1135
+ let invalidArguments: Array<InvalidArgument> = [];
1136
+ expect(
1137
+ validatePositionalValue(positional, ["1", "2", "3"], invalidArguments),
1138
+ ).toEqual([1, 2, 3]);
1139
+ expect(invalidArguments).toEqual([]);
1140
+
1141
+ invalidArguments = [];
1142
+ expect(
1143
+ validatePositionalValue(positional, ["1", "2", "1"], invalidArguments),
1144
+ ).toBeUndefined();
1145
+ expect(invalidArguments).toEqual([{
1146
+ argument: positional,
1147
+ name: "ids",
1148
+ value: [1, 2, 1],
1149
+ reason: InvalidArgumentReason.CUSTOM_VALIDATION,
1150
+ message: "values must be unique",
1151
+ }]);
1152
+ });
1153
+
1154
+ test("Custom validator not called when built-in validation fails", () => {
1155
+ const option: Option = {
1156
+ name: "foo",
1157
+ type: ArgumentValueTypeName.NUMBER,
1158
+ validate: () => {
1159
+ throw new Error("should not be called");
1160
+ },
1161
+ };
1162
+ const invalidArguments: Array<InvalidArgument> = [];
1163
+ expect(
1164
+ validateOptionValue(option, "notanumber", invalidArguments),
1165
+ ).toBeUndefined();
1166
+ expect(invalidArguments).toEqual([{
1167
+ argument: option,
1168
+ name: "foo",
1169
+ value: "notanumber",
1170
+ reason: InvalidArgumentReason.INCORRECT_VALUE_TYPE,
1171
+ }]);
1172
+ });
1173
+
1174
+ test("Custom validator not called when value is undefined and optional", () => {
1175
+ const option: Option = {
1176
+ name: "foo",
1177
+ type: ArgumentValueTypeName.STRING,
1178
+ isOptional: true,
1179
+ validate: () => {
1180
+ throw new Error("should not be called");
1181
+ },
1182
+ };
1183
+ const invalidArguments: Array<InvalidArgument> = [];
1184
+ expect(
1185
+ validateOptionValue(option, undefined, invalidArguments),
1186
+ ).toBeUndefined();
1187
+ expect(invalidArguments).toEqual([]);
1188
+ });
1189
+
997
1190
  test("Invalid global command argument value", () => {
998
1191
  let globalCommandArgument: GlobalCommandArgument = {
999
1192
  type: ArgumentValueTypeName.STRING,
@@ -0,0 +1,47 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import ArgumentPrompterServiceProvider from "../../../src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts";
3
+ import { ARGUMENT_PROMPTER_SERVICE_ID } from "../../../src/api/service/core/ArgumentPrompterService.ts";
4
+ import type ArgumentPrompterService from "../../../src/api/service/core/ArgumentPrompterService.ts";
5
+ import DefaultContext from "../../../src/runtime/DefaultContext.ts";
6
+ import { getCLIConfig } from "../../fixtures/CLIConfig.ts";
7
+
8
+ function getMockArgumentPrompterService(): ArgumentPrompterService {
9
+ return {
10
+ promptForMissingArguments: (parseResult) => Promise.resolve(parseResult),
11
+ };
12
+ }
13
+
14
+ describe("ArgumentPrompterServiceProvider tests", () => {
15
+ test("ArgumentPrompterServiceProvider has correct serviceId", () => {
16
+ const provider = new ArgumentPrompterServiceProvider(
17
+ 100,
18
+ getMockArgumentPrompterService(),
19
+ );
20
+
21
+ expect(provider.serviceId).toEqual(ARGUMENT_PROMPTER_SERVICE_ID);
22
+ });
23
+
24
+ test("ArgumentPrompterServiceProvider getServiceInfo returns no commands", async () => {
25
+ const argPrompterService = getMockArgumentPrompterService();
26
+ const provider = new ArgumentPrompterServiceProvider(
27
+ 100,
28
+ argPrompterService,
29
+ );
30
+ const cliConfig = getCLIConfig();
31
+
32
+ const serviceInfo = await provider.getServiceInfo(cliConfig);
33
+
34
+ expect(serviceInfo.service).toBe(argPrompterService);
35
+ expect(serviceInfo.commands.length).toEqual(0);
36
+ });
37
+
38
+ test("ArgumentPrompterServiceProvider initService resolves", async () => {
39
+ const provider = new ArgumentPrompterServiceProvider(
40
+ 100,
41
+ getMockArgumentPrompterService(),
42
+ );
43
+ const context = new DefaultContext(getCLIConfig());
44
+
45
+ await expect(provider.initService(context)).resolves.toBeUndefined();
46
+ });
47
+ });