@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
|
@@ -21,22 +21,16 @@ import type Positional from "../../api/argument/Positional.ts";
|
|
|
21
21
|
import type ComplexOption from "../../api/argument/ComplexOption.ts";
|
|
22
22
|
import type SubCommand from "../../api/command/SubCommand.ts";
|
|
23
23
|
import type GlobalCommand from "../../api/command/GlobalCommand.ts";
|
|
24
|
-
import {
|
|
25
|
-
isGlobalCommand,
|
|
26
|
-
isSubCommand,
|
|
27
|
-
} from "../../runtime/command/CommandTypeGuards.ts";
|
|
24
|
+
import { isGlobalCommand, isSubCommand } from "../../runtime/command/CommandTypeGuards.ts";
|
|
28
25
|
|
|
29
|
-
export default class DefaultArgumentPrompterService
|
|
30
|
-
implements ArgumentPrompterService {
|
|
26
|
+
export default class DefaultArgumentPrompterService implements ArgumentPrompterService {
|
|
31
27
|
readonly #prompterService: PrompterService;
|
|
32
28
|
|
|
33
29
|
public constructor(prompterService: PrompterService) {
|
|
34
30
|
this.#prompterService = prompterService;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
|
-
async promptForMissingArguments(
|
|
38
|
-
parseResult: ParseResult,
|
|
39
|
-
): Promise<ParseResult> {
|
|
33
|
+
async promptForMissingArguments(parseResult: ParseResult): Promise<ParseResult> {
|
|
40
34
|
if (!this.#prompterService.promptEnabled) {
|
|
41
35
|
return parseResult;
|
|
42
36
|
}
|
|
@@ -69,9 +63,7 @@ export default class DefaultArgumentPrompterService
|
|
|
69
63
|
return parseResult;
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
async #promptForGlobalCommand(
|
|
73
|
-
parseResult: ParseResult,
|
|
74
|
-
): Promise<ParseResult> {
|
|
66
|
+
async #promptForGlobalCommand(parseResult: ParseResult): Promise<ParseResult> {
|
|
75
67
|
const command = parseResult.command as GlobalCommand;
|
|
76
68
|
if (!command.argument) {
|
|
77
69
|
return parseResult;
|
|
@@ -97,48 +89,33 @@ export default class DefaultArgumentPrompterService
|
|
|
97
89
|
};
|
|
98
90
|
}
|
|
99
91
|
|
|
100
|
-
async #promptForSubCommand(
|
|
101
|
-
parseResult: ParseResult,
|
|
102
|
-
): Promise<ParseResult> {
|
|
92
|
+
async #promptForSubCommand(parseResult: ParseResult): Promise<ParseResult> {
|
|
103
93
|
const command = parseResult.command as SubCommand;
|
|
104
|
-
const existingValues = (parseResult.populatedArgumentValues ??
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
PopulatedArgumentValues[string]
|
|
109
|
-
> = { ...existingValues };
|
|
94
|
+
const existingValues = (parseResult.populatedArgumentValues ?? {}) as PopulatedArgumentValues;
|
|
95
|
+
const newValues: Record<string, PopulatedArgumentValues[string]> = {
|
|
96
|
+
...existingValues,
|
|
97
|
+
};
|
|
110
98
|
const remainingInvalid: InvalidArgument[] = [];
|
|
111
99
|
|
|
112
100
|
for (const invalid of parseResult.invalidArguments) {
|
|
113
|
-
if (
|
|
114
|
-
invalid.reason !== InvalidArgumentReason.MISSING_VALUE ||
|
|
115
|
-
!invalid.name
|
|
116
|
-
) {
|
|
101
|
+
if (invalid.reason !== InvalidArgumentReason.MISSING_VALUE || !invalid.name) {
|
|
117
102
|
remainingInvalid.push(invalid);
|
|
118
103
|
continue;
|
|
119
104
|
}
|
|
120
105
|
|
|
121
|
-
const arg = DefaultArgumentPrompterService.#findArgument(
|
|
122
|
-
command,
|
|
123
|
-
invalid.name,
|
|
124
|
-
);
|
|
106
|
+
const arg = DefaultArgumentPrompterService.#findArgument(command, invalid.name);
|
|
125
107
|
if (!arg) {
|
|
126
108
|
remainingInvalid.push(invalid);
|
|
127
109
|
continue;
|
|
128
110
|
}
|
|
129
111
|
|
|
130
|
-
if (
|
|
131
|
-
"type" in arg &&
|
|
132
|
-
(arg as ComplexOption).type === ComplexValueTypeName.COMPLEX
|
|
133
|
-
) {
|
|
112
|
+
if ("type" in arg && (arg as ComplexOption).type === ComplexValueTypeName.COMPLEX) {
|
|
134
113
|
const complexValues = await this.#promptForComplexOption(
|
|
135
114
|
invalid.name,
|
|
136
115
|
arg as ComplexOption,
|
|
137
116
|
);
|
|
138
117
|
newValues[invalid.name] = complexValues;
|
|
139
|
-
} else if (
|
|
140
|
-
DefaultArgumentPrompterService.#isArrayArgument(arg)
|
|
141
|
-
) {
|
|
118
|
+
} else if (DefaultArgumentPrompterService.#isArrayArgument(arg)) {
|
|
142
119
|
const arrayValues = await this.#promptForArrayArgument(
|
|
143
120
|
invalid.name,
|
|
144
121
|
arg as Option | Positional,
|
|
@@ -174,15 +151,11 @@ export default class DefaultArgumentPrompterService
|
|
|
174
151
|
const values: Record<string, PopulatedArgumentValues[string]> = {};
|
|
175
152
|
|
|
176
153
|
for (const prop of complexOption.properties) {
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
.#promptForComplexOption(
|
|
183
|
-
`${name}.${(prop as ComplexOption).name}`,
|
|
184
|
-
prop as ComplexOption,
|
|
185
|
-
);
|
|
154
|
+
if ("type" in prop && (prop as ComplexOption).type === ComplexValueTypeName.COMPLEX) {
|
|
155
|
+
values[(prop as ComplexOption).name] = await this.#promptForComplexOption(
|
|
156
|
+
`${name}.${(prop as ComplexOption).name}`,
|
|
157
|
+
prop as ComplexOption,
|
|
158
|
+
);
|
|
186
159
|
} else {
|
|
187
160
|
const option = prop as Option;
|
|
188
161
|
if (option.isOptional && option.defaultValue !== undefined) {
|
|
@@ -213,9 +186,7 @@ export default class DefaultArgumentPrompterService
|
|
|
213
186
|
while (true) {
|
|
214
187
|
const prompt = DefaultArgumentPrompterService.#argumentToPrompt(
|
|
215
188
|
name,
|
|
216
|
-
`${arg.description ?? name}${
|
|
217
|
-
values.length > 0 ? ` [${values.length + 1}]` : ""
|
|
218
|
-
}`,
|
|
189
|
+
`${arg.description ?? name}${values.length > 0 ? ` [${values.length + 1}]` : ""}`,
|
|
219
190
|
arg as Argument,
|
|
220
191
|
);
|
|
221
192
|
const result = await this.#prompterService.prompt(prompt);
|
|
@@ -241,11 +212,7 @@ export default class DefaultArgumentPrompterService
|
|
|
241
212
|
return values;
|
|
242
213
|
}
|
|
243
214
|
|
|
244
|
-
static #argumentToPrompt(
|
|
245
|
-
name: string,
|
|
246
|
-
description: string,
|
|
247
|
-
arg: Argument,
|
|
248
|
-
): Prompt {
|
|
215
|
+
static #argumentToPrompt(name: string, description: string, arg: Argument): Prompt {
|
|
249
216
|
if (arg.type === ArgumentValueTypeName.BOOLEAN) {
|
|
250
217
|
return {
|
|
251
218
|
name,
|
|
@@ -269,9 +236,7 @@ export default class DefaultArgumentPrompterService
|
|
|
269
236
|
}
|
|
270
237
|
|
|
271
238
|
const validationOption: PromptOption = {
|
|
272
|
-
displayValue: arg.type === ArgumentValueTypeName.SECRET
|
|
273
|
-
? "__SECRET__"
|
|
274
|
-
: name,
|
|
239
|
+
displayValue: arg.type === ArgumentValueTypeName.SECRET ? "__SECRET__" : name,
|
|
275
240
|
returnedValue: "",
|
|
276
241
|
min: arg.minValueInclusive,
|
|
277
242
|
max: arg.maxValueInclusive,
|
|
@@ -316,9 +281,7 @@ export default class DefaultArgumentPrompterService
|
|
|
316
281
|
return undefined;
|
|
317
282
|
}
|
|
318
283
|
|
|
319
|
-
static #isArrayArgument(
|
|
320
|
-
arg: Option | Positional | ComplexOption,
|
|
321
|
-
): boolean {
|
|
284
|
+
static #isArrayArgument(arg: Option | Positional | ComplexOption): boolean {
|
|
322
285
|
if ("isArray" in arg && (arg as Option).isArray) {
|
|
323
286
|
return true;
|
|
324
287
|
}
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ServiceInfo,
|
|
3
|
-
ServiceProvider,
|
|
4
|
-
} from "../../api/service/ServiceProvider.ts";
|
|
1
|
+
import type { ServiceInfo, ServiceProvider } from "../../api/service/ServiceProvider.ts";
|
|
5
2
|
import type Context from "../../api/Context.ts";
|
|
6
3
|
import type AsciiBannerGeneratorService from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
7
|
-
import {
|
|
8
|
-
ASCII_BANNER_GENERATOR_SERVICE_ID,
|
|
9
|
-
} from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
4
|
+
import { ASCII_BANNER_GENERATOR_SERVICE_ID } from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
10
5
|
import DefaultAsciiBannerGeneratorService from "./DefaultAsciiBannerGeneratorService.ts";
|
|
11
6
|
import type CLIConfig from "../../api/CLIConfig.ts";
|
|
12
7
|
|
|
13
8
|
/**
|
|
14
9
|
* Provides an {@link AsciiBannerGeneratorService}.
|
|
15
10
|
*/
|
|
16
|
-
export default class AsciiBannerGeneratorServiceProvider
|
|
17
|
-
implements ServiceProvider {
|
|
11
|
+
export default class AsciiBannerGeneratorServiceProvider implements ServiceProvider {
|
|
18
12
|
readonly serviceId: string = ASCII_BANNER_GENERATOR_SERVICE_ID;
|
|
19
13
|
readonly servicePriority: number;
|
|
20
14
|
readonly #asciiBannerGeneratorService: AsciiBannerGeneratorService;
|
|
@@ -24,12 +18,9 @@ export default class AsciiBannerGeneratorServiceProvider
|
|
|
24
18
|
*
|
|
25
19
|
* @param servicePriority the priority of the service.
|
|
26
20
|
*/
|
|
27
|
-
public constructor(
|
|
28
|
-
servicePriority: number,
|
|
29
|
-
) {
|
|
21
|
+
public constructor(servicePriority: number) {
|
|
30
22
|
this.servicePriority = servicePriority;
|
|
31
|
-
this.#asciiBannerGeneratorService =
|
|
32
|
-
new DefaultAsciiBannerGeneratorService();
|
|
23
|
+
this.#asciiBannerGeneratorService = new DefaultAsciiBannerGeneratorService();
|
|
33
24
|
}
|
|
34
25
|
|
|
35
26
|
public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
|
|
@@ -16,7 +16,9 @@ function hslToRgb(h: number, s: number, l: number): [number, number, number] {
|
|
|
16
16
|
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
17
17
|
const x = c * (1 - Math.abs(((h * 6) % 2) - 1));
|
|
18
18
|
const m = l - c / 2;
|
|
19
|
-
let r = 0,
|
|
19
|
+
let r = 0,
|
|
20
|
+
g = 0,
|
|
21
|
+
b = 0;
|
|
20
22
|
if (h < 1 / 6) {
|
|
21
23
|
r = c;
|
|
22
24
|
g = x;
|
|
@@ -42,16 +44,12 @@ function hslToRgb(h: number, s: number, l: number): [number, number, number] {
|
|
|
42
44
|
g = 0;
|
|
43
45
|
b = x;
|
|
44
46
|
}
|
|
45
|
-
return [
|
|
46
|
-
Math.round((r + m) * 255),
|
|
47
|
-
Math.round((g + m) * 255),
|
|
48
|
-
Math.round((b + m) * 255),
|
|
49
|
-
];
|
|
47
|
+
return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
function parseHex(hex: string): [number, number, number] {
|
|
53
51
|
const v = parseInt(hex.slice(1), 16);
|
|
54
|
-
return [(v >> 16) &
|
|
52
|
+
return [(v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff];
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
function interpolateColors(
|
|
@@ -84,13 +82,11 @@ function rainbowColor(
|
|
|
84
82
|
x: number,
|
|
85
83
|
y: number,
|
|
86
84
|
): [number, number, number] {
|
|
87
|
-
const h = ((freq * (x / spread) + seed + y * freq / spread) % 1.0 + 1.0) %
|
|
88
|
-
1.0;
|
|
85
|
+
const h = (((freq * (x / spread) + seed + (y * freq) / spread) % 1.0) + 1.0) % 1.0;
|
|
89
86
|
return hslToRgb(h, 1.0, 0.5);
|
|
90
87
|
}
|
|
91
88
|
|
|
92
|
-
export default class DefaultAsciiBannerGeneratorService
|
|
93
|
-
implements AsciiBannerGeneratorService {
|
|
89
|
+
export default class DefaultAsciiBannerGeneratorService implements AsciiBannerGeneratorService {
|
|
94
90
|
#registeredFontNames: Array<string> = [];
|
|
95
91
|
|
|
96
92
|
constructor() {
|
|
@@ -110,47 +106,39 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
110
106
|
figlet.parseFont(fontName, fontDefinition);
|
|
111
107
|
}
|
|
112
108
|
|
|
113
|
-
protected applyForegroundEffect(
|
|
114
|
-
lines: string[],
|
|
115
|
-
effect: ColorEffect,
|
|
116
|
-
): string[] {
|
|
109
|
+
protected applyForegroundEffect(lines: string[], effect: ColorEffect): string[] {
|
|
117
110
|
if (effect.type === "fixed") {
|
|
118
111
|
const [r, g, b] = parseHex(effect.color);
|
|
119
112
|
const code = foregroundColorStart(r, g, b);
|
|
120
113
|
return lines.map((line) =>
|
|
121
|
-
line
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"",
|
|
125
|
-
)
|
|
114
|
+
line
|
|
115
|
+
.split("")
|
|
116
|
+
.map((ch) => (ch === " " ? ch : code + ch + FOREGROUND_COLOR_END))
|
|
117
|
+
.join(""),
|
|
126
118
|
);
|
|
127
119
|
}
|
|
128
120
|
if (effect.type === "gradient") {
|
|
129
121
|
const colorStops = effect.colors.map(parseHex);
|
|
130
122
|
return lines.map((line, yi) => {
|
|
131
123
|
if (effect.direction === "vertical") {
|
|
132
|
-
const [r, g, b] = interpolateColors(
|
|
133
|
-
colorStops,
|
|
134
|
-
yi,
|
|
135
|
-
Math.max(lines.length, 1),
|
|
136
|
-
);
|
|
124
|
+
const [r, g, b] = interpolateColors(colorStops, yi, Math.max(lines.length, 1));
|
|
137
125
|
const code = foregroundColorStart(r, g, b);
|
|
138
|
-
return line
|
|
139
|
-
|
|
140
|
-
|
|
126
|
+
return line
|
|
127
|
+
.split("")
|
|
128
|
+
.map((ch) => (ch === " " ? ch : code + ch + FOREGROUND_COLOR_END))
|
|
129
|
+
.join("");
|
|
141
130
|
}
|
|
142
131
|
const nonSpaceCount = line.split("").filter((c) => c !== " ").length;
|
|
143
132
|
let charIdx = 0;
|
|
144
|
-
return line
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
charIdx,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}).join("");
|
|
133
|
+
return line
|
|
134
|
+
.split("")
|
|
135
|
+
.map((ch) => {
|
|
136
|
+
if (ch === " ") return ch;
|
|
137
|
+
const [r, g, b] = interpolateColors(colorStops, charIdx, Math.max(nonSpaceCount, 1));
|
|
138
|
+
charIdx++;
|
|
139
|
+
return foregroundColorStart(r, g, b) + ch + FOREGROUND_COLOR_END;
|
|
140
|
+
})
|
|
141
|
+
.join("");
|
|
154
142
|
});
|
|
155
143
|
}
|
|
156
144
|
const freq = effect.frequency ?? 0.3;
|
|
@@ -160,24 +148,25 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
160
148
|
if (effect.direction === "vertical") {
|
|
161
149
|
const [r, g, b] = rainbowColor(freq, spread, seed, 0, yi);
|
|
162
150
|
const code = foregroundColorStart(r, g, b);
|
|
163
|
-
return line
|
|
164
|
-
|
|
165
|
-
|
|
151
|
+
return line
|
|
152
|
+
.split("")
|
|
153
|
+
.map((ch) => (ch === " " ? ch : code + ch + FOREGROUND_COLOR_END))
|
|
154
|
+
.join("");
|
|
166
155
|
}
|
|
167
156
|
let charIdx = 0;
|
|
168
|
-
return line
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
157
|
+
return line
|
|
158
|
+
.split("")
|
|
159
|
+
.map((ch) => {
|
|
160
|
+
if (ch === " ") return ch;
|
|
161
|
+
const [r, g, b] = rainbowColor(freq, spread, seed, charIdx, yi);
|
|
162
|
+
charIdx++;
|
|
163
|
+
return foregroundColorStart(r, g, b) + ch + FOREGROUND_COLOR_END;
|
|
164
|
+
})
|
|
165
|
+
.join("");
|
|
174
166
|
});
|
|
175
167
|
}
|
|
176
168
|
|
|
177
|
-
protected applyBackgroundEffect(
|
|
178
|
-
lines: string[],
|
|
179
|
-
effect: ColorEffect,
|
|
180
|
-
): string[] {
|
|
169
|
+
protected applyBackgroundEffect(lines: string[], effect: ColorEffect): string[] {
|
|
181
170
|
if (effect.type === "fixed") {
|
|
182
171
|
const [r, g, b] = parseHex(effect.color);
|
|
183
172
|
const code = backgroundColorStart(r, g, b);
|
|
@@ -187,18 +176,17 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
187
176
|
const colorStops = effect.colors.map(parseHex);
|
|
188
177
|
return lines.map((line, yi) => {
|
|
189
178
|
if (effect.direction === "vertical") {
|
|
190
|
-
const [r, g, b] = interpolateColors(
|
|
191
|
-
colorStops,
|
|
192
|
-
yi,
|
|
193
|
-
Math.max(lines.length, 1),
|
|
194
|
-
);
|
|
179
|
+
const [r, g, b] = interpolateColors(colorStops, yi, Math.max(lines.length, 1));
|
|
195
180
|
return backgroundColorStart(r, g, b) + line + BACKGROUND_COLOR_END;
|
|
196
181
|
}
|
|
197
182
|
const totalChars = Math.max(line.length, 1);
|
|
198
|
-
return line
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
183
|
+
return line
|
|
184
|
+
.split("")
|
|
185
|
+
.map((ch, xi) => {
|
|
186
|
+
const [r, g, b] = interpolateColors(colorStops, xi, totalChars);
|
|
187
|
+
return backgroundColorStart(r, g, b) + ch + BACKGROUND_COLOR_END;
|
|
188
|
+
})
|
|
189
|
+
.join("");
|
|
202
190
|
});
|
|
203
191
|
}
|
|
204
192
|
const freq = effect.frequency ?? 0.3;
|
|
@@ -209,17 +197,17 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
209
197
|
const [r, g, b] = rainbowColor(freq, spread, seed, 0, yi);
|
|
210
198
|
return backgroundColorStart(r, g, b) + line + BACKGROUND_COLOR_END;
|
|
211
199
|
}
|
|
212
|
-
return line
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
200
|
+
return line
|
|
201
|
+
.split("")
|
|
202
|
+
.map((ch, xi) => {
|
|
203
|
+
const [r, g, b] = rainbowColor(freq, spread, seed, xi, yi);
|
|
204
|
+
return backgroundColorStart(r, g, b) + ch + BACKGROUND_COLOR_END;
|
|
205
|
+
})
|
|
206
|
+
.join("");
|
|
216
207
|
});
|
|
217
208
|
}
|
|
218
209
|
|
|
219
|
-
async generate(
|
|
220
|
-
message: string,
|
|
221
|
-
options?: BannerGenerateOptions,
|
|
222
|
-
): Promise<string> {
|
|
210
|
+
async generate(message: string, options?: BannerGenerateOptions): Promise<string> {
|
|
223
211
|
const fontName = (options?.fontName ?? "standard").toLowerCase();
|
|
224
212
|
if (!this.getRegisteredFonts().includes(fontName)) {
|
|
225
213
|
throw new Error(`Font name is not registered: ${fontName}`);
|
|
@@ -239,7 +227,7 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
239
227
|
subMessageLine = options.subMessage
|
|
240
228
|
.toUpperCase()
|
|
241
229
|
.split("")
|
|
242
|
-
.map((c) => c === " " ? " " : c + " ")
|
|
230
|
+
.map((c) => (c === " " ? " " : c + " "))
|
|
243
231
|
.join("")
|
|
244
232
|
.trimEnd();
|
|
245
233
|
|
|
@@ -258,20 +246,14 @@ export default class DefaultAsciiBannerGeneratorService
|
|
|
258
246
|
const colorEffects = options?.colorEffects;
|
|
259
247
|
|
|
260
248
|
if (colorEffects?.messageForeground) {
|
|
261
|
-
titleLines = this.applyForegroundEffect(
|
|
262
|
-
titleLines,
|
|
263
|
-
colorEffects.messageForeground,
|
|
264
|
-
);
|
|
249
|
+
titleLines = this.applyForegroundEffect(titleLines, colorEffects.messageForeground);
|
|
265
250
|
}
|
|
266
251
|
|
|
267
252
|
let subLines: string[] | undefined;
|
|
268
253
|
if (subMessageLine !== undefined) {
|
|
269
254
|
subLines = [subMessageLine];
|
|
270
255
|
if (colorEffects?.subMessageForeground) {
|
|
271
|
-
subLines = this.applyForegroundEffect(
|
|
272
|
-
subLines,
|
|
273
|
-
colorEffects.subMessageForeground,
|
|
274
|
-
);
|
|
256
|
+
subLines = this.applyForegroundEffect(subLines, colorEffects.subMessageForeground);
|
|
275
257
|
}
|
|
276
258
|
}
|
|
277
259
|
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import type Context from "../../api/Context.ts";
|
|
2
|
-
import type {
|
|
3
|
-
ServiceInfo,
|
|
4
|
-
ServiceProvider,
|
|
5
|
-
} from "../../api/service/ServiceProvider.ts";
|
|
2
|
+
import type { ServiceInfo, ServiceProvider } from "../../api/service/ServiceProvider.ts";
|
|
6
3
|
import NoBannerCommand from "./command/NoBannerCommand.ts";
|
|
7
4
|
import type PrinterService from "../../api/service/core/PrinterService.ts";
|
|
8
5
|
import { PRINTER_SERVICE_ID } from "../../api/service/core/PrinterService.ts";
|
|
9
6
|
import type ConfigurationServiceProvider from "../configuration/ConfigurationServiceProvider.ts";
|
|
10
7
|
import type AsciiBannerGeneratorService from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
11
|
-
import {
|
|
12
|
-
ASCII_BANNER_GENERATOR_SERVICE_ID,
|
|
13
|
-
} from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
8
|
+
import { ASCII_BANNER_GENERATOR_SERVICE_ID } from "../../api/service/core/AsciiBannerGeneratorService.ts";
|
|
14
9
|
import type CLIConfig from "../../api/CLIConfig.ts";
|
|
15
|
-
export const BANNER_SERVICE_ID =
|
|
16
|
-
"@flowscripter/dynamic-cli-framework/banner-service";
|
|
10
|
+
export const BANNER_SERVICE_ID = "@flowscripter/dynamic-cli-framework/banner-service";
|
|
17
11
|
|
|
18
12
|
/**
|
|
19
13
|
* Provides ascii banner functionality.
|
|
@@ -21,9 +15,7 @@ export const BANNER_SERVICE_ID =
|
|
|
21
15
|
export default class BannerServiceProvider implements ServiceProvider {
|
|
22
16
|
readonly serviceId: string = BANNER_SERVICE_ID;
|
|
23
17
|
readonly servicePriority: number;
|
|
24
|
-
readonly #configurationServiceProvider:
|
|
25
|
-
| ConfigurationServiceProvider
|
|
26
|
-
| undefined;
|
|
18
|
+
readonly #configurationServiceProvider: ConfigurationServiceProvider | undefined;
|
|
27
19
|
|
|
28
20
|
/**
|
|
29
21
|
* Whether or not to print the banner, defaults to true.
|
|
@@ -48,9 +40,7 @@ export default class BannerServiceProvider implements ServiceProvider {
|
|
|
48
40
|
|
|
49
41
|
public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
|
|
50
42
|
return Promise.resolve({
|
|
51
|
-
commands: [
|
|
52
|
-
new NoBannerCommand(this, this.servicePriority),
|
|
53
|
-
],
|
|
43
|
+
commands: [new NoBannerCommand(this, this.servicePriority)],
|
|
54
44
|
});
|
|
55
45
|
}
|
|
56
46
|
|
|
@@ -59,41 +49,29 @@ export default class BannerServiceProvider implements ServiceProvider {
|
|
|
59
49
|
return Promise.resolve();
|
|
60
50
|
}
|
|
61
51
|
|
|
62
|
-
const printerService = context.getServiceById(
|
|
63
|
-
PRINTER_SERVICE_ID,
|
|
64
|
-
) as PrinterService;
|
|
52
|
+
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
65
53
|
|
|
66
54
|
const asciiBannerGeneratorService = context.getServiceById(
|
|
67
55
|
ASCII_BANNER_GENERATOR_SERVICE_ID,
|
|
68
56
|
) as AsciiBannerGeneratorService;
|
|
69
57
|
|
|
70
58
|
const { cliConfig } = context;
|
|
71
|
-
const bannerText = await asciiBannerGeneratorService.generate(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
);
|
|
59
|
+
const bannerText = await asciiBannerGeneratorService.generate(cliConfig.name.toUpperCase(), {
|
|
60
|
+
fontName: this.fontName,
|
|
61
|
+
subMessage: cliConfig.subMessage,
|
|
62
|
+
});
|
|
75
63
|
|
|
76
64
|
await printerService.info(printerService.blue(bannerText));
|
|
77
65
|
if (cliConfig.description !== undefined) {
|
|
78
|
-
await printerService.info(
|
|
79
|
-
` ${printerService.primary(cliConfig.description)}\n`,
|
|
80
|
-
);
|
|
66
|
+
await printerService.info(` ${printerService.primary(cliConfig.description)}\n`);
|
|
81
67
|
}
|
|
82
68
|
if (cliConfig.version.length > 0) {
|
|
83
|
-
await printerService.info(
|
|
84
|
-
` ${printerService.secondary("version: " + cliConfig.version)}\n`,
|
|
85
|
-
);
|
|
69
|
+
await printerService.info(` ${printerService.secondary("version: " + cliConfig.version)}\n`);
|
|
86
70
|
}
|
|
87
71
|
if (this.#configurationServiceProvider) {
|
|
88
72
|
const configLocation = this.#configurationServiceProvider.configLocation;
|
|
89
73
|
if (configLocation && configLocation.length > 0) {
|
|
90
|
-
await printerService.info(
|
|
91
|
-
` ${
|
|
92
|
-
printerService.secondary(
|
|
93
|
-
"config: " + configLocation,
|
|
94
|
-
)
|
|
95
|
-
}\n`,
|
|
96
|
-
);
|
|
74
|
+
await printerService.info(` ${printerService.secondary("config: " + configLocation)}\n`);
|
|
97
75
|
}
|
|
98
76
|
}
|
|
99
77
|
await printerService.info("\n");
|
|
@@ -23,18 +23,12 @@ export default class NoBannerCommand implements GlobalModifierCommand {
|
|
|
23
23
|
|
|
24
24
|
readonly #bannerServiceProvider: BannerServiceProvider;
|
|
25
25
|
|
|
26
|
-
public constructor(
|
|
27
|
-
bannerServiceProvider: BannerServiceProvider,
|
|
28
|
-
executePriority: number,
|
|
29
|
-
) {
|
|
26
|
+
public constructor(bannerServiceProvider: BannerServiceProvider, executePriority: number) {
|
|
30
27
|
this.#bannerServiceProvider = bannerServiceProvider;
|
|
31
28
|
this.executePriority = executePriority;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
public execute(
|
|
35
|
-
_context: Context,
|
|
36
|
-
argumentValue: ArgumentSingleValueType,
|
|
37
|
-
): Promise<void> {
|
|
31
|
+
public execute(_context: Context, argumentValue: ArgumentSingleValueType): Promise<void> {
|
|
38
32
|
this.#bannerServiceProvider.printBanner = !(argumentValue as boolean);
|
|
39
33
|
|
|
40
34
|
return Promise.resolve();
|
|
@@ -19,7 +19,8 @@ export interface ChiselBannerGenerateOptions extends BannerGenerateOptions {
|
|
|
19
19
|
|
|
20
20
|
export default class ChiselFontAsciiBannerGeneratorService
|
|
21
21
|
extends DefaultAsciiBannerGeneratorService
|
|
22
|
-
implements AsciiBannerGeneratorService
|
|
22
|
+
implements AsciiBannerGeneratorService
|
|
23
|
+
{
|
|
23
24
|
private _ready = false;
|
|
24
25
|
|
|
25
26
|
constructor() {
|
|
@@ -40,10 +41,7 @@ export default class ChiselFontAsciiBannerGeneratorService
|
|
|
40
41
|
return ["chisel"];
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
override async generate(
|
|
44
|
-
message: string,
|
|
45
|
-
options?: ChiselBannerGenerateOptions,
|
|
46
|
-
): Promise<string> {
|
|
44
|
+
override async generate(message: string, options?: ChiselBannerGenerateOptions): Promise<string> {
|
|
47
45
|
const chiselOptions: BannerGenerateOptions = {
|
|
48
46
|
...options,
|
|
49
47
|
fontName: "chisel",
|
|
@@ -73,11 +71,8 @@ export default class ChiselFontAsciiBannerGeneratorService
|
|
|
73
71
|
colorMap["100"] = colors.shadowBackground;
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
/\x1b\[(\d+)m/g,
|
|
79
|
-
(_, n) => `\x1b[${colorMap[n] ?? n}m`,
|
|
80
|
-
);
|
|
74
|
+
const ansiCodeRe = /\x1b\[(\d+)m/g; // oxlint-disable-line no-control-regex
|
|
75
|
+
result = result.replace(ansiCodeRe, (_, n) => `\x1b[${colorMap[n] ?? n}m`);
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
return result;
|