@flowscripter/dynamic-cli-framework 1.2.1 → 1.3.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/README/core-service-providers.md +2 -2
- package/README/development.md +3 -6
- package/README/implementation-details.md +17 -17
- package/README/key-concepts.md +17 -17
- package/README.md +4 -4
- package/bun.lock +0 -2
- package/index.ts +22 -30
- package/package.json +19 -19
- package/src/api/argument/Argument.ts +1 -1
- package/src/api/argument/ArgumentValueTypes.ts +3 -10
- package/src/api/argument/ComplexOption.ts +5 -9
- package/src/api/command/GlobalCommand.ts +1 -4
- package/src/api/service/core/ArgumentPrompterService.ts +1 -3
- package/src/api/service/core/AsciiBannerGeneratorService.ts +1 -4
- package/src/api/service/core/CompletionService.ts +2 -6
- package/src/api/service/core/ImagePrinterService.ts +1 -2
- package/src/api/service/core/KeyValueService.ts +1 -2
- package/src/api/service/core/PrettyPrinterService.ts +1 -4
- package/src/api/service/core/PrinterService.ts +8 -9
- package/src/api/service/core/PrompterService.ts +4 -11
- package/src/api/service/core/ShutdownService.ts +1 -2
- package/src/api/service/core/SyntaxHighlighterService.ts +1 -5
- package/src/api/service/core/Table.ts +7 -25
- package/src/api/service/core/TreePrinterService.ts +1 -2
- package/src/cli/BaseCLI.ts +17 -47
- package/src/cli/DefaultRuntimeCLI.ts +1 -4
- package/src/command/CompletionCommand.ts +19 -45
- package/src/command/MultiCommandCliHelpCommand.ts +45 -92
- package/src/command/SingleCommandCliHelpCommand.ts +17 -28
- package/src/command/UsageCommand.ts +6 -12
- package/src/command/VersionCommand.ts +2 -6
- package/src/launcher.ts +4 -2
- package/src/runtime/DefaultContext.ts +2 -5
- package/src/runtime/argument/ArgumentTypeGuards.ts +1 -3
- package/src/runtime/command/CommandTypeGuards.ts +5 -14
- package/src/runtime/command/CommandValidator.ts +56 -118
- package/src/runtime/parser.ts +13 -17
- package/src/runtime/registry/CommandRegistry.ts +2 -7
- package/src/runtime/registry/DefaultCommandRegistry.ts +32 -84
- package/src/runtime/registry/DefaultServiceProviderRegistry.ts +3 -9
- package/src/runtime/runner.ts +103 -142
- package/src/runtime/scanner.ts +28 -46
- package/src/runtime/values/ValuePopulationResult.ts +1 -2
- package/src/runtime/values/argumentValueMerge.ts +16 -28
- package/src/runtime/values/argumentValueValidation.ts +21 -67
- package/src/runtime/values/globalCommandValuePopulation.ts +9 -18
- package/src/runtime/values/subCommandValuePopulation.ts +42 -65
- package/src/service/argumentPrompter/ArgumentPrompterServiceProvider.ts +3 -10
- package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +22 -59
- package/src/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.ts +5 -14
- package/src/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.ts +59 -77
- package/src/service/banner/BannerServiceProvider.ts +13 -35
- package/src/service/banner/command/NoBannerCommand.ts +2 -8
- package/src/service/chiselAsciiBannerGenerator/ChiselFontAsciiBannerGeneratorService.ts +5 -10
- package/src/service/completion/CompletionServiceProvider.ts +20 -48
- package/src/service/completion/DefaultCompletionService.ts +17 -56
- package/src/service/completion/shell/ShellHandler.ts +1 -3
- package/src/service/completion/shell/fish.ts +1 -1
- package/src/service/completion/shell/powershell.ts +2 -12
- package/src/service/completion/shell/zsh.ts +1 -1
- package/src/service/configuration/ConfigurationServiceProvider.ts +40 -133
- package/src/service/configuration/DefaultKeyValueService.ts +6 -20
- package/src/service/configuration/DefaultSecretService.ts +10 -14
- package/src/service/configuration/command/ConfigCommand.ts +1 -4
- package/src/service/configuration/command/DumpConfigCommand.ts +9 -21
- package/src/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.ts +5 -14
- package/src/service/dataDumpGenerator/DefaultDataDumpGeneratorService.ts +5 -12
- package/src/service/imagePrinter/DefaultImagePrinterService.ts +1 -5
- package/src/service/imagePrinter/ImagePrinterServiceProvider.ts +1 -4
- package/src/service/prettyPrinter/DefaultPrettyPrinterService.ts +4 -12
- package/src/service/prettyPrinter/PrettyPrinterServiceProvider.ts +3 -10
- package/src/service/printer/DefaultPrinterService.ts +20 -83
- package/src/service/printer/PrinterServiceProvider.ts +3 -11
- package/src/service/printer/command/DarkModeCommand.ts +3 -10
- package/src/service/printer/command/LogLevelCommand.ts +7 -26
- package/src/service/printer/command/NoColorCommand.ts +3 -10
- package/src/service/printer/command/NoHyperlinksCommand.ts +3 -10
- package/src/service/printer/terminal/Progress.ts +99 -90
- package/src/service/printer/terminal/Spinner.ts +7 -26
- package/src/service/prompter/DefaultPrompterService.ts +2 -6
- package/src/service/prompter/PrompterServiceProvider.ts +3 -11
- package/src/service/prompter/command/NoPromptCommand.ts +3 -10
- package/src/service/prompter/prompt/PromptContext.ts +5 -18
- package/src/service/prompter/prompt/promptMultiSelect.ts +6 -21
- package/src/service/prompter/prompt/promptOpenUrl.ts +7 -22
- package/src/service/prompter/prompt/promptSingleSelect.ts +6 -23
- package/src/service/prompter/prompt/promptText.ts +10 -27
- package/src/service/prompter/prompt/promptToggle.ts +8 -8
- package/src/service/shutdown/ShutdownServiceProvider.ts +3 -10
- package/src/service/syntaxHighlighter/DefaultSyntaxHighlighterService.ts +13 -26
- package/src/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.ts +8 -21
- package/src/service/tableGenerator/DefaultTableGeneratorService.ts +44 -68
- package/src/service/tableGenerator/TableGeneratorServiceProvider.ts +7 -16
- package/src/service/treePrinter/DefaultTreePrinterService.ts +2 -7
- package/src/service/treePrinter/TreePrinterServiceProvider.ts +4 -12
- package/src/terminal/ImageRenderer.ts +35 -54
- package/src/terminal/PngDecoder.ts +10 -19
- package/src/terminal/TtyStyler.ts +11 -9
- package/src/terminal/TtyTerminal.ts +2 -10
- package/src/terminal/supportsHyperlinks.ts +4 -10
- package/src/util/configHelper.ts +3 -10
- package/src/util/envVarHelper.ts +50 -88
- package/src/util/helpHelper.ts +123 -193
- package/src/util/logger.ts +12 -42
- package/src/util/runnerHelper.ts +20 -61
- package/tests/cli/BaseCLI.test.ts +23 -80
- package/tests/command/CompletionCommand.test.ts +1 -6
- package/tests/command/MultiCommandCliHelpCommand.test.ts +51 -205
- package/tests/command/SingleCommandCliHelpCommand.test.ts +21 -103
- package/tests/command/UsageCommand.test.ts +4 -10
- package/tests/fixtures/Command.ts +87 -68
- package/tests/fixtures/CommandRegistry.ts +1 -3
- package/tests/fixtures/Context.ts +3 -11
- package/tests/fixtures/ServiceProviderRegistry.ts +1 -1
- package/tests/fixtures/prettierPluginFoo.ts +1 -1
- package/tests/fixtures/util.ts +2 -8
- package/tests/runtime/argument/ArgumentTypeGuards.test.ts +1 -3
- package/tests/runtime/command/CommandValidator.test.ts +881 -604
- package/tests/runtime/parser.test.ts +222 -246
- package/tests/runtime/registry/DefaultCommandRegistry.test.ts +15 -37
- package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +2 -8
- package/tests/runtime/runner.test.ts +231 -281
- package/tests/runtime/scanner.test.ts +277 -475
- package/tests/runtime/values/argumentValueMerge.test.ts +133 -81
- package/tests/runtime/values/argumentValueValidation.test.ts +444 -588
- package/tests/runtime/values/globalCommandValuePopulation.test.ts +71 -253
- package/tests/runtime/values/subCommandValuePopulation.test.ts +1342 -1570
- package/tests/service/argumentPrompter/ArgumentPrompterServiceProvider.test.ts +3 -12
- package/tests/service/argumentPrompter/DefaultArgumentPrompterService.test.ts +36 -45
- package/tests/service/asciiBannerGenerator/AsciiBannerGeneratorServiceProvider.test.ts +2 -8
- package/tests/service/asciiBannerGenerator/DefaultAsciiBannerGeneratorService.test.ts +40 -62
- package/tests/service/banner/BannerServiceProvider.test.ts +5 -18
- package/tests/service/banner/command/NoBannerCommand.test.ts +1 -4
- package/tests/service/completion/CompletionServiceProvider.test.ts +145 -214
- package/tests/service/completion/DefaultCompletionService.test.ts +17 -79
- package/tests/service/completion/shell/fish.test.ts +1 -3
- package/tests/service/configuration/ConfigurationServiceProvider.test.ts +26 -75
- package/tests/service/configuration/DefaultKeyValueService.test.ts +9 -21
- package/tests/service/configuration/DefaultSecretService.test.ts +7 -15
- package/tests/service/configuration/command/DumpConfigCommand.test.ts +4 -13
- package/tests/service/dataDumpGenerator/DataDumpGeneratorServiceProvider.test.ts +6 -12
- package/tests/service/dataDumpGenerator/DefaultDataDumpGeneratorService.test.ts +1 -10
- package/tests/service/imagePrinter/DefaultImagePrinterService.test.ts +5 -70
- package/tests/service/prettyPrinter/DefaultPrettyPrinterService.test.ts +4 -11
- package/tests/service/prettyPrinter/PrettyPrinterServiceProvider.test.ts +2 -6
- package/tests/service/printer/DefaultPrinterService.test.ts +57 -255
- package/tests/service/printer/PrinterServiceProvider.test.ts +2 -8
- package/tests/service/printer/command/DarkModeCommand.test.ts +4 -12
- package/tests/service/printer/command/LogLevelCommand.test.ts +4 -17
- package/tests/service/printer/command/NoColorCommand.test.ts +4 -12
- package/tests/service/printer/command/NoHyperlinksCommand.test.ts +7 -21
- package/tests/service/printer/terminal/Progress.test.ts +1 -3
- package/tests/service/printer/terminal/Spinner.test.ts +2 -8
- package/tests/service/prompter/DefaultPrompterService.test.ts +52 -69
- package/tests/service/prompter/PrompterServiceProvider.test.ts +2 -8
- package/tests/service/shutdown/ShutdownServiceProvider.test.ts +1 -3
- package/tests/service/syntaxHighlighter/DefaultSyntaxHighlighterService.test.ts +13 -99
- package/tests/service/syntaxHighlighter/SyntaxHighlighterServiceProvider.test.ts +2 -7
- package/tests/service/tableGenerator/DefaultTableGeneratorService.test.ts +12 -33
- package/tests/service/tableGenerator/TableGeneratorServiceProvider.test.ts +2 -2
- package/tests/service/treePrinter/DefaultTreePrinterService.test.ts +4 -6
- package/tests/service/treePrinter/TreePrinterServiceProvider.test.ts +4 -8
- package/tests/terminal/ImageRenderer.test.ts +2 -11
- package/tests/terminal/PngDecoder.test.ts +2 -6
- package/tests/util/configHelper.test.ts +55 -137
- package/tests/util/envVarHelper.test.ts +46 -110
|
@@ -107,23 +107,21 @@ abstract class SingleCommandCliAbstractHelpCommand {
|
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
|
-
helpSection.helpEntries.sort((a: HelpEntry, b: HelpEntry) =>
|
|
111
|
-
a.syntax.localeCompare(b.syntax)
|
|
112
|
-
);
|
|
110
|
+
helpSection.helpEntries.sort((a: HelpEntry, b: HelpEntry) => a.syntax.localeCompare(b.syntax));
|
|
113
111
|
return helpSection;
|
|
114
112
|
}
|
|
115
113
|
|
|
116
|
-
public async execute(
|
|
117
|
-
context: Context,
|
|
118
|
-
): Promise<void> {
|
|
114
|
+
public async execute(context: Context): Promise<void> {
|
|
119
115
|
const helpSections: Array<HelpSection> = [];
|
|
120
116
|
helpSections.push({
|
|
121
117
|
title: "Usage",
|
|
122
|
-
helpEntries: [
|
|
123
|
-
|
|
124
|
-
getSubCommandArgumentsSyntax(
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
helpEntries: [
|
|
119
|
+
{
|
|
120
|
+
syntax: `${context.cliConfig.name || ""}${getSubCommandArgumentsSyntax(
|
|
121
|
+
this.#defaultCommand,
|
|
122
|
+
)}`,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
127
125
|
});
|
|
128
126
|
|
|
129
127
|
helpSections.push(
|
|
@@ -135,8 +133,7 @@ abstract class SingleCommandCliAbstractHelpCommand {
|
|
|
135
133
|
),
|
|
136
134
|
);
|
|
137
135
|
|
|
138
|
-
const globalModifierCommands = this.#commandRegistry
|
|
139
|
-
.getGlobalModifierCommands();
|
|
136
|
+
const globalModifierCommands = this.#commandRegistry.getGlobalModifierCommands();
|
|
140
137
|
const globalCommands = this.#commandRegistry.getGlobalCommands();
|
|
141
138
|
helpSections.push(
|
|
142
139
|
this.#getAmalgamatedGenericHelpSection(
|
|
@@ -148,26 +145,16 @@ abstract class SingleCommandCliAbstractHelpCommand {
|
|
|
148
145
|
),
|
|
149
146
|
);
|
|
150
147
|
|
|
151
|
-
const printerService = context.getServiceById(
|
|
152
|
-
PRINTER_SERVICE_ID,
|
|
153
|
-
) as PrinterService;
|
|
148
|
+
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
154
149
|
const tableGeneratorService = context.getServiceById(
|
|
155
150
|
TABLE_GENERATOR_SERVICE_ID,
|
|
156
151
|
) as TableGeneratorService;
|
|
157
152
|
|
|
158
153
|
helpSections.push(
|
|
159
|
-
...getCommandExamplesHelpSections(
|
|
160
|
-
printerService,
|
|
161
|
-
context,
|
|
162
|
-
this.#defaultCommand,
|
|
163
|
-
),
|
|
154
|
+
...getCommandExamplesHelpSections(printerService, context, this.#defaultCommand),
|
|
164
155
|
);
|
|
165
156
|
|
|
166
|
-
await printHelpSections(
|
|
167
|
-
printerService,
|
|
168
|
-
tableGeneratorService,
|
|
169
|
-
helpSections,
|
|
170
|
-
);
|
|
157
|
+
await printHelpSections(printerService, tableGeneratorService, helpSections);
|
|
171
158
|
}
|
|
172
159
|
}
|
|
173
160
|
|
|
@@ -176,7 +163,8 @@ abstract class SingleCommandCliAbstractHelpCommand {
|
|
|
176
163
|
*/
|
|
177
164
|
export class SingleCommandCliHelpGlobalCommand
|
|
178
165
|
extends SingleCommandCliAbstractHelpCommand
|
|
179
|
-
implements GlobalCommand
|
|
166
|
+
implements GlobalCommand
|
|
167
|
+
{
|
|
180
168
|
readonly shortAlias = "h";
|
|
181
169
|
}
|
|
182
170
|
|
|
@@ -185,7 +173,8 @@ export class SingleCommandCliHelpGlobalCommand
|
|
|
185
173
|
*/
|
|
186
174
|
export class SingleCommandCliHelpSubCommand
|
|
187
175
|
extends SingleCommandCliAbstractHelpCommand
|
|
188
|
-
implements SubCommand
|
|
176
|
+
implements SubCommand
|
|
177
|
+
{
|
|
189
178
|
public readonly options: ReadonlyArray<Option> = [];
|
|
190
179
|
|
|
191
180
|
public readonly positionals: ReadonlyArray<Positional> = [];
|
|
@@ -13,23 +13,17 @@ export default class UsageCommand implements GlobalCommand {
|
|
|
13
13
|
|
|
14
14
|
readonly #helpCommand: Command;
|
|
15
15
|
|
|
16
|
-
public constructor(
|
|
17
|
-
helpCommand: Command,
|
|
18
|
-
) {
|
|
16
|
+
public constructor(helpCommand: Command) {
|
|
19
17
|
this.#helpCommand = helpCommand;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
public async execute(
|
|
23
|
-
context
|
|
24
|
-
): Promise<void> {
|
|
25
|
-
const printerService = context.getServiceById(
|
|
26
|
-
PRINTER_SERVICE_ID,
|
|
27
|
-
) as PrinterService;
|
|
20
|
+
public async execute(context: Context): Promise<void> {
|
|
21
|
+
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
28
22
|
|
|
29
23
|
await printerService.print(
|
|
30
|
-
`${printerService.secondary("Try running:")}\n\n ${
|
|
31
|
-
|
|
32
|
-
} --${printerService.primary(this.#helpCommand.name)}\n\n`,
|
|
24
|
+
`${printerService.secondary("Try running:")}\n\n ${printerService.primary(
|
|
25
|
+
context.cliConfig.name,
|
|
26
|
+
)} --${printerService.primary(this.#helpCommand.name)}\n\n`,
|
|
33
27
|
);
|
|
34
28
|
}
|
|
35
29
|
}
|
|
@@ -11,12 +11,8 @@ export default class VersionCommand implements GlobalCommand {
|
|
|
11
11
|
readonly description = "Show version information";
|
|
12
12
|
readonly shortAlias = "v";
|
|
13
13
|
|
|
14
|
-
public async execute(
|
|
15
|
-
context
|
|
16
|
-
): Promise<void> {
|
|
17
|
-
const printerService = context.getServiceById(
|
|
18
|
-
PRINTER_SERVICE_ID,
|
|
19
|
-
) as PrinterService;
|
|
14
|
+
public async execute(context: Context): Promise<void> {
|
|
15
|
+
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
20
16
|
await printerService.print(`${context.cliConfig.version}\n`);
|
|
21
17
|
}
|
|
22
18
|
}
|
package/src/launcher.ts
CHANGED
|
@@ -27,7 +27,8 @@ export async function launchSingleCommandCLI(
|
|
|
27
27
|
|
|
28
28
|
const mergedOptions: BaseCLIFeatureOptions = {
|
|
29
29
|
...options,
|
|
30
|
-
validateAllCommands:
|
|
30
|
+
validateAllCommands:
|
|
31
|
+
(options?.validateAllCommands ?? false) ||
|
|
31
32
|
process.env.DYNAMIC_CLI_FRAMEWORK_VALIDATE_ALL !== undefined,
|
|
32
33
|
};
|
|
33
34
|
const cli = new DefaultRuntimeCLI(cliConfig, mergedOptions);
|
|
@@ -58,7 +59,8 @@ export async function launchMultiCommandCLI(
|
|
|
58
59
|
|
|
59
60
|
const mergedOptions: BaseCLIFeatureOptions = {
|
|
60
61
|
...options,
|
|
61
|
-
validateAllCommands:
|
|
62
|
+
validateAllCommands:
|
|
63
|
+
(options?.validateAllCommands ?? false) ||
|
|
62
64
|
process.env.DYNAMIC_CLI_FRAMEWORK_VALIDATE_ALL !== undefined,
|
|
63
65
|
};
|
|
64
66
|
const cli = new DefaultRuntimeCLI(cliConfig, mergedOptions);
|
|
@@ -7,14 +7,11 @@ import type CLIConfig from "../api/CLIConfig.ts";
|
|
|
7
7
|
export default class DefaultContext implements Context {
|
|
8
8
|
readonly #serviceInstancesById: Map<string, unknown> = new Map();
|
|
9
9
|
|
|
10
|
-
public constructor(readonly cliConfig: CLIConfig) {
|
|
11
|
-
}
|
|
10
|
+
public constructor(readonly cliConfig: CLIConfig) {}
|
|
12
11
|
|
|
13
12
|
public addServiceInstance(id: string, serviceInstance: unknown) {
|
|
14
13
|
if (this.#serviceInstancesById.has(id)) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
`Service ID: ${id} duplicates the ID of an existing service`,
|
|
17
|
-
);
|
|
14
|
+
throw new Error(`Service ID: ${id} duplicates the ID of an existing service`);
|
|
18
15
|
}
|
|
19
16
|
this.#serviceInstancesById.set(id, serviceInstance);
|
|
20
17
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type Argument from "../../api/argument/Argument.ts";
|
|
2
2
|
import type ComplexOption from "../../api/argument/ComplexOption.ts";
|
|
3
3
|
|
|
4
|
-
export function isComplexOption(
|
|
5
|
-
argument: Argument | ComplexOption,
|
|
6
|
-
): argument is ComplexOption {
|
|
4
|
+
export function isComplexOption(argument: Argument | ComplexOption): argument is ComplexOption {
|
|
7
5
|
return (argument as ComplexOption).properties !== undefined;
|
|
8
6
|
}
|
|
@@ -4,27 +4,18 @@ import type GlobalCommand from "../../api/command/GlobalCommand.ts";
|
|
|
4
4
|
import type GlobalModifierCommand from "../../api/command/GlobalModifierCommand.ts";
|
|
5
5
|
import type Command from "../../api/command/Command.ts";
|
|
6
6
|
|
|
7
|
-
export function isGroupCommand(
|
|
8
|
-
command: Command,
|
|
9
|
-
): command is GroupCommand {
|
|
7
|
+
export function isGroupCommand(command: Command): command is GroupCommand {
|
|
10
8
|
return (command as GroupCommand).memberSubCommands !== undefined;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
export function isSubCommand(
|
|
14
|
-
command: Command,
|
|
15
|
-
): command is SubCommand {
|
|
11
|
+
export function isSubCommand(command: Command): command is SubCommand {
|
|
16
12
|
return (command as SubCommand).options !== undefined;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
|
-
export function isGlobalModifierCommand(
|
|
20
|
-
command: Command,
|
|
21
|
-
): command is GlobalModifierCommand {
|
|
15
|
+
export function isGlobalModifierCommand(command: Command): command is GlobalModifierCommand {
|
|
22
16
|
return (command as GlobalModifierCommand).executePriority !== undefined;
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
export function isGlobalCommand(
|
|
26
|
-
command
|
|
27
|
-
): command is GlobalCommand {
|
|
28
|
-
return !isGroupCommand(command) && !isSubCommand(command) &&
|
|
29
|
-
!isGlobalModifierCommand(command);
|
|
19
|
+
export function isGlobalCommand(command: Command): command is GlobalCommand {
|
|
20
|
+
return !isGroupCommand(command) && !isSubCommand(command) && !isGlobalModifierCommand(command);
|
|
30
21
|
}
|
|
@@ -4,9 +4,7 @@ import type GlobalCommand from "../../api/command/GlobalCommand.ts";
|
|
|
4
4
|
import type Argument from "../../api/argument/Argument.ts";
|
|
5
5
|
import type GroupCommand from "../../api/command/GroupCommand.ts";
|
|
6
6
|
import type SubCommand from "../../api/command/SubCommand.ts";
|
|
7
|
-
import type {
|
|
8
|
-
ArgumentSingleValueType,
|
|
9
|
-
} from "../../api/argument/ArgumentValueTypes.ts";
|
|
7
|
+
import type { ArgumentSingleValueType } from "../../api/argument/ArgumentValueTypes.ts";
|
|
10
8
|
import {
|
|
11
9
|
ArgumentValueTypeName,
|
|
12
10
|
ComplexValueTypeName,
|
|
@@ -49,7 +47,7 @@ function validateValueType(
|
|
|
49
47
|
}
|
|
50
48
|
break;
|
|
51
49
|
case ArgumentValueTypeName.NUMBER:
|
|
52
|
-
if (
|
|
50
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
53
51
|
throw new Error(
|
|
54
52
|
`Specified ${
|
|
55
53
|
isDefaultValue ? "default" : isRangeValue ? "range" : "allowable"
|
|
@@ -58,7 +56,7 @@ function validateValueType(
|
|
|
58
56
|
}
|
|
59
57
|
break;
|
|
60
58
|
case ArgumentValueTypeName.INTEGER:
|
|
61
|
-
if (
|
|
59
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
62
60
|
throw new Error(
|
|
63
61
|
`Specified ${
|
|
64
62
|
isDefaultValue ? "default" : isRangeValue ? "range" : "allowable"
|
|
@@ -91,26 +89,25 @@ function isUppercaseAlphaNumericOrUnderscore(value: string): boolean {
|
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
function isNameLegal(name: string): boolean {
|
|
94
|
-
return
|
|
95
|
-
(name[0] !== "-");
|
|
92
|
+
return name.length > 0 && isAlphaNumericOrDashOrUnderscore(name) && name[0] !== "-";
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
function isConfigurationKeyLegal(configurationKey: string): boolean {
|
|
99
|
-
return (
|
|
96
|
+
return (
|
|
97
|
+
configurationKey.length > 0 &&
|
|
100
98
|
isUppercaseAlphaNumericOrUnderscore(configurationKey) &&
|
|
101
|
-
!configurationKey[0]!.match(/[0-9]/)
|
|
99
|
+
!configurationKey[0]!.match(/[0-9]/)
|
|
100
|
+
);
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
function validateArgument(argument: Argument, name: string): void {
|
|
105
104
|
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
argument.type !== ArgumentValueTypeName.NUMBER &&
|
|
106
|
+
argument.type !== ArgumentValueTypeName.INTEGER &&
|
|
107
|
+
argument.type !== ArgumentValueTypeName.STRING &&
|
|
108
|
+
argument.type !== ArgumentValueTypeName.BOOLEAN
|
|
110
109
|
) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`Illegal type: '${argument.type}' for argument: '${name}'`,
|
|
113
|
-
);
|
|
110
|
+
throw new Error(`Illegal type: '${argument.type}' for argument: '${name}'`);
|
|
114
111
|
}
|
|
115
112
|
if (argument.allowableValues) {
|
|
116
113
|
if (argument.type === ArgumentValueTypeName.BOOLEAN) {
|
|
@@ -123,10 +120,7 @@ function validateArgument(argument: Argument, name: string): void {
|
|
|
123
120
|
});
|
|
124
121
|
}
|
|
125
122
|
if (argument.isCaseInsensitive !== undefined) {
|
|
126
|
-
if (
|
|
127
|
-
(argument.type === ArgumentValueTypeName.BOOLEAN) &&
|
|
128
|
-
(argument.isCaseInsensitive === false)
|
|
129
|
-
) {
|
|
123
|
+
if (argument.type === ArgumentValueTypeName.BOOLEAN && argument.isCaseInsensitive === false) {
|
|
130
124
|
throw new Error(
|
|
131
125
|
`Illegal type: '${argument.type}' for argument: '${name}' must always be case insensitive`,
|
|
132
126
|
);
|
|
@@ -138,8 +132,8 @@ function validateArgument(argument: Argument, name: string): void {
|
|
|
138
132
|
}
|
|
139
133
|
if (argument.minValueInclusive !== undefined) {
|
|
140
134
|
if (
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
argument.type !== ArgumentValueTypeName.NUMBER &&
|
|
136
|
+
argument.type !== ArgumentValueTypeName.INTEGER
|
|
143
137
|
) {
|
|
144
138
|
throw new Error(
|
|
145
139
|
`Illegal type: '${argument.type}' for argument: '${name}' with min value specified`,
|
|
@@ -150,18 +144,12 @@ function validateArgument(argument: Argument, name: string): void {
|
|
|
150
144
|
`Illegal combination of allowable values and min value for argument: '${name}'`,
|
|
151
145
|
);
|
|
152
146
|
}
|
|
153
|
-
validateValueType(
|
|
154
|
-
argument.type,
|
|
155
|
-
argument.minValueInclusive,
|
|
156
|
-
name,
|
|
157
|
-
false,
|
|
158
|
-
true,
|
|
159
|
-
);
|
|
147
|
+
validateValueType(argument.type, argument.minValueInclusive, name, false, true);
|
|
160
148
|
}
|
|
161
149
|
if (argument.maxValueInclusive !== undefined) {
|
|
162
150
|
if (
|
|
163
|
-
|
|
164
|
-
|
|
151
|
+
argument.type !== ArgumentValueTypeName.NUMBER &&
|
|
152
|
+
argument.type !== ArgumentValueTypeName.INTEGER
|
|
165
153
|
) {
|
|
166
154
|
throw new Error(
|
|
167
155
|
`Illegal type: '${argument.type}' for argument: '${name}' with max value specified`,
|
|
@@ -172,19 +160,11 @@ function validateArgument(argument: Argument, name: string): void {
|
|
|
172
160
|
`Illegal combination of allowable values and max value for argument: '${name}'`,
|
|
173
161
|
);
|
|
174
162
|
}
|
|
175
|
-
validateValueType(
|
|
176
|
-
argument.type,
|
|
177
|
-
argument.maxValueInclusive,
|
|
178
|
-
name,
|
|
179
|
-
false,
|
|
180
|
-
true,
|
|
181
|
-
);
|
|
163
|
+
validateValueType(argument.type, argument.maxValueInclusive, name, false, true);
|
|
182
164
|
}
|
|
183
165
|
}
|
|
184
166
|
|
|
185
|
-
function validateSubCommandArgument(
|
|
186
|
-
subCommandArgument: SubCommandArgument,
|
|
187
|
-
): void {
|
|
167
|
+
function validateSubCommandArgument(subCommandArgument: SubCommandArgument): void {
|
|
188
168
|
if (!isNameLegal(subCommandArgument.name)) {
|
|
189
169
|
throw new Error(`Illegal argument name: '${subCommandArgument.name}'`);
|
|
190
170
|
}
|
|
@@ -236,8 +216,7 @@ export default class CommandValidator {
|
|
|
236
216
|
}
|
|
237
217
|
if (
|
|
238
218
|
globalCommand.shortAlias &&
|
|
239
|
-
(globalCommand.shortAlias.length !== 1 ||
|
|
240
|
-
!isAlphaNumeric(globalCommand.shortAlias))
|
|
219
|
+
(globalCommand.shortAlias.length !== 1 || !isAlphaNumeric(globalCommand.shortAlias))
|
|
241
220
|
) {
|
|
242
221
|
throw new Error(
|
|
243
222
|
`Illegal short alias: '${globalCommand.shortAlias}' for global command: '${globalCommand.name}'`,
|
|
@@ -248,25 +227,16 @@ export default class CommandValidator {
|
|
|
248
227
|
validateArgument(argument, globalCommand.name);
|
|
249
228
|
if (argument.defaultValue) {
|
|
250
229
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
251
|
-
validateGlobalCommandArgumentValue(
|
|
252
|
-
globalCommand,
|
|
253
|
-
argument.defaultValue,
|
|
254
|
-
invalidArguments,
|
|
255
|
-
);
|
|
230
|
+
validateGlobalCommandArgumentValue(globalCommand, argument.defaultValue, invalidArguments);
|
|
256
231
|
if (invalidArguments.length > 0) {
|
|
257
232
|
throw new Error(
|
|
258
|
-
`Illegal default value for global command: '${globalCommand.name}' => ${
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
).join(", ")
|
|
262
|
-
}`,
|
|
233
|
+
`Illegal default value for global command: '${globalCommand.name}' => ${invalidArguments
|
|
234
|
+
.map((invalidArgument) => getInvalidArgumentString(invalidArgument, true))
|
|
235
|
+
.join(", ")}`,
|
|
263
236
|
);
|
|
264
237
|
}
|
|
265
238
|
}
|
|
266
|
-
this.#validateGlobalCommandArgumentConfigurationKey(
|
|
267
|
-
globalCommand,
|
|
268
|
-
argument,
|
|
269
|
-
);
|
|
239
|
+
this.#validateGlobalCommandArgumentConfigurationKey(globalCommand, argument);
|
|
270
240
|
}
|
|
271
241
|
}
|
|
272
242
|
|
|
@@ -289,9 +259,7 @@ export default class CommandValidator {
|
|
|
289
259
|
throw new Error(`Illegal group command name: '${groupCommand.name}'`);
|
|
290
260
|
}
|
|
291
261
|
if (groupCommand.memberSubCommands.length === 0) {
|
|
292
|
-
throw new Error(
|
|
293
|
-
`Group command: '${groupCommand.name}' has no member sub-commands`,
|
|
294
|
-
);
|
|
262
|
+
throw new Error(`Group command: '${groupCommand.name}' has no member sub-commands`);
|
|
295
263
|
}
|
|
296
264
|
const subCommandNames: Array<string> = [];
|
|
297
265
|
groupCommand.memberSubCommands.forEach((subCommand) => {
|
|
@@ -378,16 +346,14 @@ export default class CommandValidator {
|
|
|
378
346
|
argumentNames.push(positional.name);
|
|
379
347
|
|
|
380
348
|
if (
|
|
381
|
-
|
|
349
|
+
i < subCommand.positionals.length - 1 &&
|
|
382
350
|
(positional.isVarargOptional || positional.isVarargMultiple)
|
|
383
351
|
) {
|
|
384
352
|
throw new Error(
|
|
385
353
|
`Positional: '${positional.name}' for the command: '${subCommand.name}' is defined as a vararg but it is not the last positional argument`,
|
|
386
354
|
);
|
|
387
355
|
}
|
|
388
|
-
this.#validateSubCommandArgumentConfigurationKey(subCommand, [
|
|
389
|
-
positional,
|
|
390
|
-
]);
|
|
356
|
+
this.#validateSubCommandArgumentConfigurationKey(subCommand, [positional]);
|
|
391
357
|
}
|
|
392
358
|
}
|
|
393
359
|
}
|
|
@@ -399,12 +365,10 @@ export default class CommandValidator {
|
|
|
399
365
|
const argument = argumentAncestry[argumentAncestry.length - 1]!;
|
|
400
366
|
if (command.enableConfiguration === true) {
|
|
401
367
|
if (
|
|
402
|
-
|
|
368
|
+
argument.configurationKey !== undefined &&
|
|
403
369
|
!isConfigurationKeyLegal(argument.configurationKey)
|
|
404
370
|
) {
|
|
405
|
-
throw new Error(
|
|
406
|
-
`Illegal configuration key: '${argument.configurationKey}'`,
|
|
407
|
-
);
|
|
371
|
+
throw new Error(`Illegal configuration key: '${argument.configurationKey}'`);
|
|
408
372
|
}
|
|
409
373
|
const configurationKey = getSubCommandArgumentConfigurationKey(
|
|
410
374
|
this.#cliConfig,
|
|
@@ -433,12 +397,10 @@ export default class CommandValidator {
|
|
|
433
397
|
) {
|
|
434
398
|
if (command.enableConfiguration === true) {
|
|
435
399
|
if (
|
|
436
|
-
|
|
400
|
+
globalCommandArgument.configurationKey !== undefined &&
|
|
437
401
|
!isConfigurationKeyLegal(globalCommandArgument.configurationKey)
|
|
438
402
|
) {
|
|
439
|
-
throw new Error(
|
|
440
|
-
`Illegal configuration key: '${globalCommandArgument.configurationKey}'`,
|
|
441
|
-
);
|
|
403
|
+
throw new Error(`Illegal configuration key: '${globalCommandArgument.configurationKey}'`);
|
|
442
404
|
}
|
|
443
405
|
const configurationKey = getGlobalCommandArgumentConfigurationKey(
|
|
444
406
|
this.#cliConfig,
|
|
@@ -472,24 +434,16 @@ export default class CommandValidator {
|
|
|
472
434
|
option.shortAlias &&
|
|
473
435
|
(option.shortAlias.length !== 1 || !isAlphaNumeric(option.shortAlias))
|
|
474
436
|
) {
|
|
475
|
-
throw new Error(
|
|
476
|
-
`Illegal short alias: '${option.shortAlias}' for option: '${option.name}'`,
|
|
477
|
-
);
|
|
437
|
+
throw new Error(`Illegal short alias: '${option.shortAlias}' for option: '${option.name}'`);
|
|
478
438
|
}
|
|
479
439
|
if (isComplexOption(option)) {
|
|
480
|
-
this.#validateComplexOption(
|
|
481
|
-
subCommand,
|
|
482
|
-
option,
|
|
483
|
-
currentOptionPaths,
|
|
484
|
-
allOptionPaths,
|
|
485
|
-
[...argumentAncestry, option as unknown as SubCommandArgument],
|
|
486
|
-
);
|
|
487
|
-
} else {
|
|
488
|
-
this.#validateOption(option, currentOptionPaths, allOptionPaths);
|
|
489
|
-
this.#validateSubCommandArgumentConfigurationKey(subCommand, [
|
|
440
|
+
this.#validateComplexOption(subCommand, option, currentOptionPaths, allOptionPaths, [
|
|
490
441
|
...argumentAncestry,
|
|
491
|
-
option,
|
|
442
|
+
option as unknown as SubCommandArgument,
|
|
492
443
|
]);
|
|
444
|
+
} else {
|
|
445
|
+
this.#validateOption(option, currentOptionPaths, allOptionPaths);
|
|
446
|
+
this.#validateSubCommandArgumentConfigurationKey(subCommand, [...argumentAncestry, option]);
|
|
493
447
|
}
|
|
494
448
|
}
|
|
495
449
|
|
|
@@ -501,25 +455,19 @@ export default class CommandValidator {
|
|
|
501
455
|
validateSubCommandArgument(option);
|
|
502
456
|
if (Array.isArray(option.defaultValue) && !option.isArray) {
|
|
503
457
|
throw new Error(
|
|
504
|
-
`Illegal array default value: '${
|
|
505
|
-
|
|
506
|
-
}' for non-array option: '${option.name}'`,
|
|
458
|
+
`Illegal array default value: '${option.defaultValue.join(
|
|
459
|
+
",",
|
|
460
|
+
)}' for non-array option: '${option.name}'`,
|
|
507
461
|
);
|
|
508
462
|
}
|
|
509
463
|
if (option.defaultValue) {
|
|
510
464
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
511
|
-
validateOptionValue(
|
|
512
|
-
option,
|
|
513
|
-
option.defaultValue,
|
|
514
|
-
invalidArguments,
|
|
515
|
-
);
|
|
465
|
+
validateOptionValue(option, option.defaultValue, invalidArguments);
|
|
516
466
|
if (invalidArguments.length > 0) {
|
|
517
467
|
throw new Error(
|
|
518
|
-
`Illegal default value for option: '${option.name}' => ${
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
).join(", ")
|
|
522
|
-
}`,
|
|
468
|
+
`Illegal default value for option: '${option.name}' => ${invalidArguments
|
|
469
|
+
.map((invalidArgument) => getInvalidArgumentString(invalidArgument, true))
|
|
470
|
+
.join(", ")}`,
|
|
523
471
|
);
|
|
524
472
|
}
|
|
525
473
|
}
|
|
@@ -562,32 +510,24 @@ export default class CommandValidator {
|
|
|
562
510
|
}
|
|
563
511
|
if (Array.isArray(complexOption.defaultValue) && !complexOption.isArray) {
|
|
564
512
|
throw new Error(
|
|
565
|
-
`Illegal array default value: '${
|
|
566
|
-
|
|
567
|
-
}' for non-array option: '${complexOption.name}'`,
|
|
513
|
+
`Illegal array default value: '${JSON.stringify(
|
|
514
|
+
complexOption.defaultValue,
|
|
515
|
+
)}' for non-array option: '${complexOption.name}'`,
|
|
568
516
|
);
|
|
569
517
|
}
|
|
570
518
|
if (complexOption.defaultValue) {
|
|
571
519
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
572
|
-
validateOptionValue(
|
|
573
|
-
complexOption,
|
|
574
|
-
complexOption.defaultValue,
|
|
575
|
-
invalidArguments,
|
|
576
|
-
);
|
|
520
|
+
validateOptionValue(complexOption, complexOption.defaultValue, invalidArguments);
|
|
577
521
|
if (invalidArguments.length > 0) {
|
|
578
522
|
throw new Error(
|
|
579
|
-
`Illegal default value for option: '${complexOption.name}' => ${
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
).join(", ")
|
|
583
|
-
}`,
|
|
523
|
+
`Illegal default value for option: '${complexOption.name}' => ${invalidArguments
|
|
524
|
+
.map((invalidArgument) => getInvalidArgumentString(invalidArgument, true))
|
|
525
|
+
.join(", ")}`,
|
|
584
526
|
);
|
|
585
527
|
}
|
|
586
528
|
}
|
|
587
529
|
if (complexOption.properties.length === 0) {
|
|
588
|
-
throw new Error(
|
|
589
|
-
`Complex option: '${complexOption.name}' has no properties`,
|
|
590
|
-
);
|
|
530
|
+
throw new Error(`Complex option: '${complexOption.name}' has no properties`);
|
|
591
531
|
}
|
|
592
532
|
complexOption.properties.forEach((property) => {
|
|
593
533
|
const newCurrentOptionPaths: Array<string> = [];
|
|
@@ -596,9 +536,7 @@ export default class CommandValidator {
|
|
|
596
536
|
});
|
|
597
537
|
if (property.shortAlias) {
|
|
598
538
|
currentOptionPaths.forEach((currentOptionPath) => {
|
|
599
|
-
newCurrentOptionPaths.push(
|
|
600
|
-
`${currentOptionPath}.${property.shortAlias}`,
|
|
601
|
-
);
|
|
539
|
+
newCurrentOptionPaths.push(`${currentOptionPath}.${property.shortAlias}`);
|
|
602
540
|
});
|
|
603
541
|
}
|
|
604
542
|
this.#validateOptionOrComplexOption(
|
package/src/runtime/parser.ts
CHANGED
|
@@ -21,7 +21,7 @@ import type SubCommand from "../api/command/SubCommand.ts";
|
|
|
21
21
|
const logger = getLogger("parser");
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* A container holding the result of a
|
|
24
|
+
* A container holding the result of a command clause parsing operation.
|
|
25
25
|
*/
|
|
26
26
|
export interface ParseResult {
|
|
27
27
|
/**
|
|
@@ -40,9 +40,7 @@ export interface ParseResult {
|
|
|
40
40
|
* {@link PopulatedArgumentSingleValueType} is for {@link GlobalCommand} values, {@link PopulatedArgumentValues} is for
|
|
41
41
|
* {@link SubCommand} values.
|
|
42
42
|
*/
|
|
43
|
-
readonly populatedArgumentValues:
|
|
44
|
-
| PopulatedArgumentValues
|
|
45
|
-
| PopulatedArgumentSingleValueType;
|
|
43
|
+
readonly populatedArgumentValues: PopulatedArgumentValues | PopulatedArgumentSingleValueType;
|
|
46
44
|
|
|
47
45
|
/**
|
|
48
46
|
* Any arguments which were invalid.
|
|
@@ -72,7 +70,7 @@ export function parseSubCommandClause(
|
|
|
72
70
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
73
71
|
|
|
74
72
|
// check if we need to process any arguments at all
|
|
75
|
-
if (
|
|
73
|
+
if (command.options.length === 0 && command.positionals.length === 0) {
|
|
76
74
|
return {
|
|
77
75
|
command,
|
|
78
76
|
groupCommand,
|
|
@@ -82,12 +80,11 @@ export function parseSubCommandClause(
|
|
|
82
80
|
};
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
const { populatedArgumentValues, unusedArgs, invalidArgument } =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
83
|
+
const { populatedArgumentValues, unusedArgs, invalidArgument } = populateSubCommandValues(
|
|
84
|
+
command,
|
|
85
|
+
potentialArgs,
|
|
86
|
+
defaultValues,
|
|
87
|
+
);
|
|
91
88
|
|
|
92
89
|
if (invalidArgument) {
|
|
93
90
|
invalidArguments.push(invalidArgument);
|
|
@@ -172,12 +169,11 @@ export function parseGlobalCommandClause(
|
|
|
172
169
|
};
|
|
173
170
|
}
|
|
174
171
|
|
|
175
|
-
let { populatedArgumentValue, unusedArgs, invalidArgument } =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
);
|
|
172
|
+
let { populatedArgumentValue, unusedArgs, invalidArgument } = populateGlobalCommandValue(
|
|
173
|
+
command,
|
|
174
|
+
potentialArgs,
|
|
175
|
+
defaultValue,
|
|
176
|
+
);
|
|
181
177
|
|
|
182
178
|
if (invalidArgument) {
|
|
183
179
|
invalidArguments.push(invalidArgument);
|
|
@@ -59,9 +59,7 @@ export default interface CommandRegistry {
|
|
|
59
59
|
/**
|
|
60
60
|
* Get a registered {@link GlobalModifierCommand} by name.
|
|
61
61
|
*/
|
|
62
|
-
getGlobalModifierCommandByName(
|
|
63
|
-
name: string,
|
|
64
|
-
): GlobalModifierCommand | undefined;
|
|
62
|
+
getGlobalModifierCommandByName(name: string): GlobalModifierCommand | undefined;
|
|
65
63
|
|
|
66
64
|
/**
|
|
67
65
|
* Get a registered {@link GlobalModifierCommand} by short alias.
|
|
@@ -96,10 +94,7 @@ export default interface CommandRegistry {
|
|
|
96
94
|
/**
|
|
97
95
|
* Get a map of all registered {@link GlobalModifierCommand} instances by name not provided by a service.
|
|
98
96
|
*/
|
|
99
|
-
getGlobalModifierCommandsByNameNotProvidedByService(): ReadonlyMap<
|
|
100
|
-
string,
|
|
101
|
-
GlobalModifierCommand
|
|
102
|
-
>;
|
|
97
|
+
getGlobalModifierCommandsByNameNotProvidedByService(): ReadonlyMap<string, GlobalModifierCommand>;
|
|
103
98
|
|
|
104
99
|
/**
|
|
105
100
|
* Get a map of all registered {@link GlobalModifierCommand} instances by short alias not provided by a service.
|