@flowscripter/dynamic-cli-framework 1.1.5 → 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 +98 -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 +40 -1
- package/src/api/argument/ArgumentValueTypes.ts +1 -1
- package/src/api/command/SubCommand.ts +1 -1
- 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 +20 -32
- package/src/command/SingleCommandCliHelpCommand.ts +10 -1
- package/src/launcher.ts +16 -58
- package/src/runtime/command/CommandValidator.ts +70 -6
- package/src/runtime/runner.ts +112 -31
- package/src/runtime/scanner.ts +18 -15
- package/src/runtime/values/argumentValueValidation.ts +93 -10
- 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/LogLevelCommand.ts +2 -1
- 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 +139 -123
- package/src/util/logger.ts +16 -14
- package/src/util/runnerHelper.ts +41 -0
- 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/command/CommandValidator.test.ts +103 -0
- package/tests/runtime/parser.test.ts +9 -7
- package/tests/runtime/registry/DefaultServiceProviderRegistry.test.ts +3 -3
- package/tests/runtime/runner.test.ts +36 -0
- package/tests/runtime/values/argumentValueValidation.test.ts +215 -1
- 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 +8 -6
- 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
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# Implementation
|
|
2
|
+
|
|
3
|
+
The following diagram provides an overview of the main internal modules and
|
|
4
|
+
classes:
|
|
5
|
+
|
|
6
|
+
```mermaid
|
|
7
|
+
classDiagram
|
|
8
|
+
|
|
9
|
+
class parser {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class scanner {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class Context {
|
|
16
|
+
<<interface>>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class CLI {
|
|
20
|
+
<<interface>>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class runner {
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class BaseCLI {
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class Command {
|
|
30
|
+
<<interface>>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class DefaultCommandRegistry {
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class launcher {
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class DefaultServiceProviderRegistry {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class ServiceProvider {
|
|
43
|
+
<<interface>>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class DefaultContext {
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class CommandRegistry {
|
|
50
|
+
<<interface>>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class ServiceProviderRegistry {
|
|
54
|
+
<<interface>>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class DefaultRuntimeCLI {
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class CLIConfig {
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class ServiceXYZ {
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
runner --> scanner
|
|
67
|
+
|
|
68
|
+
runner --> parser
|
|
69
|
+
|
|
70
|
+
CLI <|.. BaseCLI
|
|
71
|
+
|
|
72
|
+
BaseCLI <|-- DefaultRuntimeCLI
|
|
73
|
+
|
|
74
|
+
runner --> Context
|
|
75
|
+
|
|
76
|
+
runner --> CommandRegistry
|
|
77
|
+
|
|
78
|
+
runner --> ServiceProviderRegistry
|
|
79
|
+
|
|
80
|
+
ServiceProviderRegistry <|.. DefaultServiceProviderRegistry
|
|
81
|
+
|
|
82
|
+
ServiceProviderRegistry --> "0..*" ServiceProvider : registers
|
|
83
|
+
|
|
84
|
+
BaseCLI --> DefaultCommandRegistry
|
|
85
|
+
|
|
86
|
+
CommandRegistry <|.. DefaultCommandRegistry
|
|
87
|
+
|
|
88
|
+
CommandRegistry --> "0..*" Command : registers
|
|
89
|
+
|
|
90
|
+
runner --> "0..1" Command : defaultCommand
|
|
91
|
+
|
|
92
|
+
Context <|.. DefaultContext
|
|
93
|
+
|
|
94
|
+
BaseCLI --> DefaultContext
|
|
95
|
+
|
|
96
|
+
BaseCLI --> DefaultServiceProviderRegistry
|
|
97
|
+
|
|
98
|
+
Context --> CLIConfig
|
|
99
|
+
|
|
100
|
+
BaseCLI --> CLIConfig
|
|
101
|
+
|
|
102
|
+
Context --> ServiceProviderRegistry
|
|
103
|
+
|
|
104
|
+
ServiceProvider --> ServiceXYZ : provides
|
|
105
|
+
|
|
106
|
+
Context --> ServiceXYZ : access to
|
|
107
|
+
|
|
108
|
+
DefaultRuntimeCLI <-- launcher
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `launcher`
|
|
112
|
+
|
|
113
|
+
The standard way to make use of the framework is to import `launcher` and use
|
|
114
|
+
one of the two helper functions it provides:
|
|
115
|
+
|
|
116
|
+
- `launchSingleCommandCLI`
|
|
117
|
+
- `launchMultiCommandCLI`
|
|
118
|
+
|
|
119
|
+
These allow a CLI implementor to specify `Command` instances to use together
|
|
120
|
+
with basic CLI details such as name and description.
|
|
121
|
+
|
|
122
|
+
### `CLI`
|
|
123
|
+
|
|
124
|
+
The `CLI` interface has the simple responsibility of taking a `CLIConfig` and a
|
|
125
|
+
list of user specified command line arguments which it should then parse and
|
|
126
|
+
execute any valid specified `Command` it discovers.
|
|
127
|
+
|
|
128
|
+
#### `BaseCLI`
|
|
129
|
+
|
|
130
|
+
The `BaseCLI` class provides a base implementation of the `CLI` interface which
|
|
131
|
+
supports both single command and multiple sub-command CLI scenarios. It provides
|
|
132
|
+
the ability to add any number of `Command` and `ServiceProvider` instances.
|
|
133
|
+
|
|
134
|
+
If only one command is provided, `BaseCLI` will operate as a single command CLI
|
|
135
|
+
and the provided command will be set as a default command. If more than one
|
|
136
|
+
command is added, `BaseCLI` will operate as a multi-command CLI. In this case
|
|
137
|
+
the default command will be set to a help command. In the case of no command
|
|
138
|
+
being specified or a parse error occurring, appropriate help will be displayed.
|
|
139
|
+
|
|
140
|
+
By default the `BaseCLI` adds the following `ServiceProvider` implementations
|
|
141
|
+
(these are documented in further detail below):
|
|
142
|
+
|
|
143
|
+
- `ShutdownServiceProvider` allowing CLI shutdown hooks to be registered.
|
|
144
|
+
- `ConfigurationServiceProvider` allowing argument value defaults to be loaded
|
|
145
|
+
from a configuration file or environment variables. This also provides a
|
|
146
|
+
key-value store service.
|
|
147
|
+
- `PrinterServiceProvider` allowing CLI output to stdout and stderr writable
|
|
148
|
+
streams.
|
|
149
|
+
|
|
150
|
+
By default the `BaseCLI` adds the following `Command` implementations (these are
|
|
151
|
+
documented in further detail below):
|
|
152
|
+
|
|
153
|
+
- Appropriate help commands depending on whether the CLI is configured with a
|
|
154
|
+
single command or multiple sub-command.
|
|
155
|
+
- commands provided by the `ConfigurationServiceProvider`.
|
|
156
|
+
- commands provided by the `PrinterServiceProvider`.
|
|
157
|
+
- `VersionCommand`
|
|
158
|
+
|
|
159
|
+
#### `DefaultRuntimeCLI`
|
|
160
|
+
|
|
161
|
+
`DefaultRuntimeCLI` is a simple extension to `BaseCLI` which uses NodeJS
|
|
162
|
+
specific APIs to access the command line arguments, stdout and stderr streams
|
|
163
|
+
and to exit the process.
|
|
164
|
+
|
|
165
|
+
### `runner`
|
|
166
|
+
|
|
167
|
+
Core CLI behaviour is provided by a `runner` implementation which is responsible
|
|
168
|
+
for parsing arguments, determining which `Command` instances to execute and then
|
|
169
|
+
executing them.
|
|
170
|
+
|
|
171
|
+
The `runner` implementation supports specification of a default command which
|
|
172
|
+
should be executed if no command names are parsed on the command line. In this
|
|
173
|
+
scenario, any arguments provided will also be parsed as possible arguments for
|
|
174
|
+
the default command.
|
|
175
|
+
|
|
176
|
+
The logic for the `runner` is somewhat complex as it allows for the prioritised
|
|
177
|
+
execution of `GlobalModifierCommand` instances and the prioritised
|
|
178
|
+
initialisation of `ServiceProvider` instances. One reason for this is to allow
|
|
179
|
+
the `ConfigurationServiceProvider` to be initialised first and for the resulting
|
|
180
|
+
configuration to be available to other `ServiceProvider` instances which are yet
|
|
181
|
+
to be initialised.
|
|
182
|
+
|
|
183
|
+
The following activity diagram illustrates the `runner` logic:
|
|
184
|
+
|
|
185
|
+
```mermaid
|
|
186
|
+
flowchart TD
|
|
187
|
+
A([start])
|
|
188
|
+
|
|
189
|
+
subgraph 1 [for each ServiceProvider in servicePriority order:]
|
|
190
|
+
|
|
191
|
+
B([scan args for provided\nGlobalModifierCommand clauses])
|
|
192
|
+
|
|
193
|
+
subgraph 2 [for each discovered clause:]
|
|
194
|
+
C([set default\narg values])
|
|
195
|
+
D([parse args])
|
|
196
|
+
E([add to list of\nGlobalModifierCommands\nclauses to execute])
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
F([scan default arg values for provided\nGlobalModifierCommand clauses])
|
|
200
|
+
|
|
201
|
+
subgraph 3 [for each discovered clause:]
|
|
202
|
+
G([parse args])
|
|
203
|
+
H([add to list of\nGlobalModifierCommands\nclauses to execute])
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
I([order GlobalModifierCommands\nclauses by executePriority])
|
|
207
|
+
|
|
208
|
+
subgraph 4 [for each discovered clause:]
|
|
209
|
+
J([execute GlobalModifierCommand])
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
K([init service provided by ServiceProvider])
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
L([scan args for non-ServiceProvider\nGlobalModifierCommand clauses])
|
|
216
|
+
|
|
217
|
+
subgraph 5 [for each discovered clause:]
|
|
218
|
+
M([set default\narg values])
|
|
219
|
+
N([parse args])
|
|
220
|
+
O([add to list of\nGlobalModifierCommands\nclauses to execute])
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
P([scan default arg values for non-ServiceProvider\nGlobalModifierCommand clauses])
|
|
224
|
+
|
|
225
|
+
subgraph 6 [for each discovered clause:]
|
|
226
|
+
Q([parse args])
|
|
227
|
+
R([add to list of\nGlobalModifierCommands\nclauses to execute])
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
S([order GlobalModifierCommands\nclauses by executePriority])
|
|
231
|
+
|
|
232
|
+
subgraph 7 [for each discovered clause:]
|
|
233
|
+
T([execute GlobalModifierCommand])
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
U([scan args for non-modifier Command clause])
|
|
237
|
+
|
|
238
|
+
V{clause found?}
|
|
239
|
+
V1([set default\narg values])
|
|
240
|
+
V2([parse args])
|
|
241
|
+
V3([execute\nnon-modifier Command])
|
|
242
|
+
W{default\nnon-modifier Command\nprovided?}
|
|
243
|
+
W1([scan args for\nnon-modifier Command clause])
|
|
244
|
+
W2{clause\nfound?}
|
|
245
|
+
W21([set default\narg values])
|
|
246
|
+
W22([parse args])
|
|
247
|
+
W23{valid?}
|
|
248
|
+
W24([execute\nnon-modifier Command])
|
|
249
|
+
W3([set default\narg values])
|
|
250
|
+
W31{valid?}
|
|
251
|
+
W32([execute\nnon-modifier Command])
|
|
252
|
+
|
|
253
|
+
Z([end])
|
|
254
|
+
|
|
255
|
+
C --> D
|
|
256
|
+
D --> E
|
|
257
|
+
|
|
258
|
+
G --> H
|
|
259
|
+
|
|
260
|
+
M --> N
|
|
261
|
+
N --> O
|
|
262
|
+
|
|
263
|
+
Q --> R
|
|
264
|
+
|
|
265
|
+
A --> 1
|
|
266
|
+
B --> 2
|
|
267
|
+
2 --> F
|
|
268
|
+
F --> 3
|
|
269
|
+
3 --> I
|
|
270
|
+
I --> 4
|
|
271
|
+
4 --> K
|
|
272
|
+
1 --> L
|
|
273
|
+
L --> 5
|
|
274
|
+
5 --> P
|
|
275
|
+
P --> 6
|
|
276
|
+
6 --> S
|
|
277
|
+
S --> 7
|
|
278
|
+
7 --> U
|
|
279
|
+
U --> V
|
|
280
|
+
V --> |yes|V1
|
|
281
|
+
V --> |no|W
|
|
282
|
+
W --> |yes|W1
|
|
283
|
+
W --> |no|Z
|
|
284
|
+
|
|
285
|
+
V1 --> V2
|
|
286
|
+
V2 --> V3
|
|
287
|
+
V3 --> Z
|
|
288
|
+
|
|
289
|
+
W1 --> W2
|
|
290
|
+
W2 --> |yes|W21
|
|
291
|
+
W2 --> |no|W3
|
|
292
|
+
|
|
293
|
+
W21 --> W22
|
|
294
|
+
W22 --> W23
|
|
295
|
+
|
|
296
|
+
W23 --> |yes|W24
|
|
297
|
+
W23 --> |no|Z
|
|
298
|
+
|
|
299
|
+
W24 --> Z
|
|
300
|
+
|
|
301
|
+
W3 --> W31
|
|
302
|
+
W31 --> |yes|W32
|
|
303
|
+
W31 --> |no|Z
|
|
304
|
+
|
|
305
|
+
W32 --> Z
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### `scanner`
|
|
309
|
+
|
|
310
|
+
The `runner` defers to a `scanner` implementation which scans arguments for
|
|
311
|
+
potential `CommandClause` instances e.g. a `Command.name` followed by potential
|
|
312
|
+
arguments for that command..
|
|
313
|
+
|
|
314
|
+
### `parser`
|
|
315
|
+
|
|
316
|
+
The `runner` defers to a `parser` implementation which performs the actual
|
|
317
|
+
argument parsing based on the `CommandClause` instances returned from the
|
|
318
|
+
`scanner`.
|
|
319
|
+
|
|
320
|
+
The following parsing rules apply:
|
|
321
|
+
|
|
322
|
+
**Arguments Must Follow Command**
|
|
323
|
+
|
|
324
|
+
All arguments for a command are expected to FOLLOW the command i.e. this is
|
|
325
|
+
**NOT** valid:
|
|
326
|
+
|
|
327
|
+
executable <sub_command_argument> <sub_command> // not valid
|
|
328
|
+
|
|
329
|
+
**Arbitrary Option Order**
|
|
330
|
+
|
|
331
|
+
The order of options for a particular command is not important i.e. these are
|
|
332
|
+
equivalent:
|
|
333
|
+
|
|
334
|
+
executable <sub_command> --<option_1_name> <option_1_value> --<option_2_name> <option_2_value>
|
|
335
|
+
executable <sub_command> --<option_2_name> <option_2_value> --<option_1_name> <option_1_value>
|
|
336
|
+
|
|
337
|
+
**Arbitrary Command Order**
|
|
338
|
+
|
|
339
|
+
The order of commands is not important i.e. these are equivalent:
|
|
340
|
+
|
|
341
|
+
executable <sub_command> [sub_command_arguments] --<modifier_command_1> [modifier_command_1_arguments] \
|
|
342
|
+
--<modifier_command_2> [modifier_command_2_arguments]
|
|
343
|
+
executable --<modifier_command_1> [modifier_command_1_arguments] <sub_command> [sub_command_arguments] \
|
|
344
|
+
--<modifier_command_2> [modifier_command_2_arguments]
|
|
345
|
+
|
|
346
|
+
**No Command Interleaving**
|
|
347
|
+
|
|
348
|
+
Arguments for commands cannot be interleaved with other commands i.e. this is
|
|
349
|
+
**NOT** valid:
|
|
350
|
+
|
|
351
|
+
executable --<modifier_command> <sub_command> [sub_command_arguments] [modifier_command_arguments] // not valid
|
|
352
|
+
|
|
353
|
+
**Single Command**
|
|
354
|
+
|
|
355
|
+
Apart from global modifier commands, there is expected to be only one command
|
|
356
|
+
specified i.e. these will **NOT** work as intended:
|
|
357
|
+
|
|
358
|
+
// not valid - sub-command 2 and arguments will be treated as trailing arguments of sub-command 1.
|
|
359
|
+
executable <sub_command_1> [sub_command_1_arguments] <sub_command_2> [sub_command_2_arguments]
|
|
360
|
+
|
|
361
|
+
// not valid - sub-command and arguments will be treated as trailing arguments of global command.
|
|
362
|
+
executable --<global_command> <sub_command> [sub_command_arguments]
|
|
363
|
+
|
|
364
|
+
**Group Command**
|
|
365
|
+
|
|
366
|
+
A group command name must always be following immediately by a container
|
|
367
|
+
sub-command name i.e. these are **NOT** valid:
|
|
368
|
+
|
|
369
|
+
executable <member_sub_command> <group_command> // not valid
|
|
370
|
+
executable <group_command> <global_command> <member_sub_command> // not valid
|
|
371
|
+
|
|
372
|
+
**Unused Leading and Trailing Arguments**
|
|
373
|
+
|
|
374
|
+
Any leading arguments which appear BEFORE an identified command name are
|
|
375
|
+
retained. Any trailing arguments which appear after an identified name which are
|
|
376
|
+
not consumed when parsing the command arguments are also retained.
|
|
377
|
+
|
|
378
|
+
Once a command has been identified and parsed any retained arguments are
|
|
379
|
+
considered unused and a warning is output.
|
|
380
|
+
|
|
381
|
+
If a command is NOT identified, any retained arguments are considered potential
|
|
382
|
+
arguments for a default command if it has been configured. This behaviour means
|
|
383
|
+
the following are equivalent:
|
|
384
|
+
|
|
385
|
+
executable <default_command_argument> --<modifier_command_name> <modifier_command_argument>
|
|
386
|
+
executable --<modifier_command_name> <modifier_command_argument> <default_command_argument>
|
|
387
|
+
|
|
388
|
+
### Command Execution
|
|
389
|
+
|
|
390
|
+
A `Command` is executed via the implemented function:
|
|
391
|
+
|
|
392
|
+
execute(argumentValues: ArgumentValues, context: Context): Promise<void>;
|
|
393
|
+
|
|
394
|
+
The `Context` instance allow access to the `CLIConfig` and the ability to access
|
|
395
|
+
services by registered service IDs.
|
|
396
|
+
|
|
397
|
+
The `ArgumentValues` instance provides access to the populated and validated
|
|
398
|
+
arguments for the command. These values are provided either:
|
|
399
|
+
|
|
400
|
+
- as a single key-value pair in the form `commandName: globalArgumentValue` for
|
|
401
|
+
a `GlobalCommand` or a `GlobalModifierCommand`.
|
|
402
|
+
- as a complex nested key-value structure mirroring the defined `Option` and
|
|
403
|
+
`Positional` instances of a `SubCommand`
|
|
404
|
+
|
|
405
|
+
As an example, if a `GlobalModifierCommand` is defined as follows:
|
|
406
|
+
|
|
407
|
+
```
|
|
408
|
+
const globalModifierCommand: GlobalModifierCommand = {
|
|
409
|
+
name: "log-level",
|
|
410
|
+
argument: {
|
|
411
|
+
name: "level",
|
|
412
|
+
type: ArgumentValueTypeName.STRING,
|
|
413
|
+
},
|
|
414
|
+
executePriority: 1,
|
|
415
|
+
execute: (argumentValues: ArgumentValues, context: Context) => Promise.resolve()
|
|
416
|
+
};
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
and a `SubCommand` is defined as follows:
|
|
420
|
+
|
|
421
|
+
```
|
|
422
|
+
const subCommand: SubCommand = {
|
|
423
|
+
name: "connect",
|
|
424
|
+
options: [
|
|
425
|
+
{
|
|
426
|
+
name: "address",
|
|
427
|
+
type: ComplexValueTypeName.COMPLEX,
|
|
428
|
+
properties: [
|
|
429
|
+
{
|
|
430
|
+
name: "host",
|
|
431
|
+
type: ArgumentValueTypeName.STRING
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
name: "port",
|
|
435
|
+
type: ArgumentValueTypeName.NUMBER
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
positionals: [
|
|
441
|
+
{
|
|
442
|
+
name: "retryOnError",
|
|
443
|
+
type: ArgumentValueTypeName.BOOLEAN
|
|
444
|
+
}
|
|
445
|
+
],
|
|
446
|
+
execute: (argumentValues: ArgumentValues, context: Context) => Promise.resolve()
|
|
447
|
+
};
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
when the following command line arguments are specified:
|
|
451
|
+
|
|
452
|
+
`myNetworkApp --connect --address.host=127.0.0.1 --address.port=8080 true --log-level=DEBUG`
|
|
453
|
+
|
|
454
|
+
then the `ArgumentValues` passed to the `globalModifierCommand.execute(...)`
|
|
455
|
+
function would be:
|
|
456
|
+
|
|
457
|
+
```
|
|
458
|
+
{
|
|
459
|
+
"log-level": "DEBUG"
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
and the `ArgumentValues` passed to the `subCommand.execute(...)` function would
|
|
464
|
+
be:
|
|
465
|
+
|
|
466
|
+
```
|
|
467
|
+
{
|
|
468
|
+
address: {
|
|
469
|
+
host: "127.0.0.1",
|
|
470
|
+
port: 8080
|
|
471
|
+
},
|
|
472
|
+
retryOnError: true
|
|
473
|
+
}
|
|
474
|
+
```
|