@flowscripter/dynamic-cli-framework 1.1.6 → 1.2.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.
- package/.github/workflows/release-bun-library.yml +1 -0
- package/README/core-commands.md +40 -0
- package/README/core-service-providers.md +198 -0
- package/README/development.md +60 -0
- package/README/implementation-details.md +474 -0
- package/README/key-concepts.md +751 -0
- package/README.md +12 -1413
- package/bun.lock +20 -18
- package/index.ts +97 -1
- package/package.json +8 -7
- package/src/api/BaseCLIFeatureOptions.ts +10 -0
- package/src/api/CLIConfig.ts +5 -0
- package/src/api/RunResult.ts +16 -0
- package/src/api/argument/Argument.ts +24 -0
- package/src/api/service/ServiceProvider.ts +3 -3
- package/src/api/service/core/ArgumentPrompterService.ts +10 -0
- package/src/api/service/core/AsciiBannerGeneratorService.ts +44 -7
- package/src/api/service/core/CompletionService.ts +36 -0
- package/src/api/service/core/DataDumpGeneratorService.ts +27 -0
- package/src/api/service/core/ImagePrinterService.ts +26 -0
- package/src/api/service/core/KeyValueService.ts +22 -5
- package/src/api/service/core/PrinterService.ts +127 -1
- package/src/api/service/core/PrompterService.ts +49 -0
- package/src/api/service/core/SecretService.ts +27 -0
- package/src/api/service/core/ShutdownService.ts +17 -1
- package/src/api/service/core/Table.ts +85 -0
- package/src/api/service/core/TableGeneratorService.ts +38 -0
- package/src/api/service/core/TreePrinterService.ts +11 -0
- package/src/cli/BaseCLI.ts +116 -44
- package/src/cli/DefaultRuntimeCLI.ts +10 -18
- package/src/command/CompletionCommand.ts +179 -0
- package/src/command/MultiCommandCliHelpCommand.ts +18 -2
- package/src/command/SingleCommandCliHelpCommand.ts +10 -1
- package/src/launcher.ts +16 -58
- package/src/runtime/command/CommandValidator.ts +3 -3
- package/src/runtime/runner.ts +102 -30
- package/src/runtime/scanner.ts +18 -15
- package/src/runtime/values/argumentValueValidation.ts +49 -5
- package/src/runtime/values/globalCommandValuePopulation.ts +1 -1
- package/src/runtime/values/subCommandValuePopulation.ts +9 -8
- package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +34 -0
- package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +330 -0
- package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +1 -1
- package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +254 -17
- package/src/service/banner/BannerServiceProvider.ts +2 -2
- package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +85 -0
- package/src/service/chiselAsciiBannerGenerator/chisel.flf.json +3 -0
- package/src/service/completion/CompletionServiceProvider.ts +212 -0
- package/src/service/completion/DefaultCompletionService.ts +364 -0
- package/src/service/completion/shell/ShellHandler.ts +16 -0
- package/src/service/completion/shell/bash.ts +47 -0
- package/src/service/completion/shell/fish.ts +43 -0
- package/src/service/completion/shell/powershell.ts +66 -0
- package/src/service/completion/shell/zsh.ts +50 -0
- package/src/service/configuration/ConfigurationServiceProvider.ts +138 -42
- package/src/service/configuration/DefaultKeyValueService.ts +53 -7
- package/src/service/configuration/DefaultSecretService.ts +85 -0
- package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +41 -0
- package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +80 -0
- package/src/service/imagePrinter/DefaultImagePrinterService.ts +23 -0
- package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +32 -0
- package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +1 -1
- package/src/service/printer/DefaultPrinterService.ts +147 -27
- package/src/service/printer/PrinterServiceProvider.ts +7 -7
- package/src/service/printer/command/NoHyperlinksCommand.ts +40 -0
- package/src/service/printer/terminal/Progress.ts +21 -4
- package/src/service/printer/terminal/Spinner.ts +32 -8
- package/src/service/printer/terminal/Theme.ts +1 -1
- package/src/service/prompter/DefaultPrompterService.ts +87 -0
- package/src/service/prompter/PrompterServiceProvider.ts +36 -0
- package/src/service/prompter/command/NoPromptCommand.ts +40 -0
- package/src/service/prompter/prompt/PromptContext.ts +47 -0
- package/src/service/prompter/prompt/promptAcknowledge.ts +28 -0
- package/src/service/prompter/prompt/promptMultiSelect.ts +99 -0
- package/src/service/prompter/prompt/promptOpenUrl.ts +97 -0
- package/src/service/prompter/prompt/promptSingleSelect.ts +102 -0
- package/src/service/prompter/prompt/promptText.ts +107 -0
- package/src/service/prompter/prompt/promptToggle.ts +28 -0
- package/src/service/shutdown/DefaultShutdownService.ts +13 -0
- package/src/service/shutdown/ShutdownServiceProvider.ts +28 -9
- package/src/service/shutdown/ShutdownState.ts +5 -0
- package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +1 -1
- package/src/service/tableGenerator/DefaultTableGeneratorService.ts +415 -0
- package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +43 -0
- package/src/service/treePrinter/DefaultTreePrinterService.ts +49 -0
- package/src/service/treePrinter/TreePrinterServiceProvider.ts +40 -0
- package/src/terminal/Ansi.ts +27 -0
- package/src/terminal/ImageRenderer.ts +199 -0
- package/src/terminal/KeyReader.ts +23 -0
- package/src/terminal/PngDecoder.ts +143 -0
- package/src/{service/printer/terminal → terminal}/Styler.ts +3 -0
- package/src/{service/printer/terminal → terminal}/Terminal.ts +1 -0
- package/src/terminal/TtyKeyReader.ts +83 -0
- package/src/terminal/TtyStyler.ts +78 -0
- package/src/{service/printer/terminal → terminal}/TtyTerminal.ts +9 -1
- package/src/terminal/supportsHyperlinks.ts +110 -0
- package/src/util/configHelper.ts +2 -2
- package/src/util/envVarHelper.ts +2 -2
- package/src/util/helpHelper.ts +66 -122
- package/src/util/logger.ts +16 -14
- package/src/util/runnerHelper.ts +1 -1
- package/tests/cli/BaseCLI.test.ts +50 -54
- package/tests/command/CompletionCommand.test.ts +68 -0
- package/tests/command/UsageCommand.test.ts +3 -2
- package/tests/command/VersionCommand.test.ts +3 -2
- package/tests/fixtures/Context.ts +9 -2
- package/tests/fixtures/util.ts +1 -1
- package/tests/runtime/parser.test.ts +9 -7
- package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +3 -3
- package/tests/runtime/values/argumentValueValidation.test.ts +193 -0
- package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +47 -0
- package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +754 -0
- package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +5 -4
- package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +163 -3
- package/tests/service/asciiBannerGenerator/__snapshots__/DefaultAsciiBannerGeneratorService.test.ts.snap +1 -1
- package/tests/service/banner/BannerServiceProvider.test.ts +8 -4
- package/tests/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.test.ts +52 -0
- package/tests/service/completion/CompletionServiceProvider.test.ts +404 -0
- package/tests/service/completion/DefaultCompletionService.test.ts +278 -0
- package/tests/service/completion/shell/bash.test.ts +73 -0
- package/tests/service/completion/shell/fish.test.ts +62 -0
- package/tests/service/completion/shell/powershell.test.ts +59 -0
- package/tests/service/completion/shell/zsh.test.ts +60 -0
- package/tests/service/configuration/ConfigurationServiceProvider.test.ts +24 -12
- package/tests/service/configuration/DefaultKeyValueService.test.ts +118 -16
- package/tests/service/configuration/DefaultSecretService.test.ts +148 -0
- package/tests/service/configuration/command/ConfigCommand.test.ts +29 -0
- package/tests/service/configuration/command/DumpConfigCommand.test.ts +60 -0
- package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +57 -0
- package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +217 -0
- package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +96 -0
- package/tests/service/imagePrinter/ImagePrinterServiceProvider.test.ts +17 -0
- package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +2 -2
- package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +5 -4
- package/tests/service/printer/DefaultPrinterService.test.ts +233 -2
- package/tests/service/printer/PrinterServiceProvider.test.ts +6 -5
- package/tests/service/printer/command/DarkModeCommand.test.ts +83 -0
- package/tests/service/printer/command/LogLevelCommand.test.ts +7 -5
- package/tests/service/printer/command/NoColorCommand.test.ts +83 -0
- package/tests/service/printer/command/NoHyperlinksCommand.test.ts +89 -0
- package/tests/service/printer/terminal/Progress.test.ts +64 -4
- package/tests/service/printer/terminal/Spinner.test.ts +44 -3
- package/tests/service/prompter/DefaultPrompterService.test.ts +615 -0
- package/tests/service/prompter/PrompterServiceProvider.test.ts +47 -0
- package/tests/service/prompter/command/NoPromptCommand.test.ts +58 -0
- package/tests/service/shutdown/ShutdownServiceProvider.test.ts +4 -2
- package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +3 -2
- package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +5 -4
- package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +363 -0
- package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +47 -0
- package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +144 -0
- package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +55 -0
- package/tests/terminal/ImageRenderer.test.ts +161 -0
- package/tests/terminal/PngDecoder.test.ts +223 -0
- package/tests/terminal/supportsHyperlinks.test.ts +149 -0
- package/tests/util/configHelper.test.ts +4 -4
- package/tests/util/logger.test.ts +23 -1
- package/tsconfig.json +31 -0
- package/src/service/printer/terminal/Ansi.ts +0 -10
- 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/
|
|
10
|
-
import TtyStyler from "../../src/
|
|
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/
|
|
10
|
-
import TtyStyler from "../../src/
|
|
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
|
}
|
package/tests/fixtures/util.ts
CHANGED
|
@@ -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]
|
|
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]
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
-
|
|
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]
|
|
40
|
-
expect(orderedServices[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
|
+
});
|