@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
|
@@ -128,21 +128,13 @@ function createService(
|
|
|
128
128
|
} {
|
|
129
129
|
const terminal = new MockTerminal();
|
|
130
130
|
const config = { ...DEFAULT_PROMPTER_CONFIG, ...configOverrides };
|
|
131
|
-
const service = new DefaultPrompterService(
|
|
132
|
-
config,
|
|
133
|
-
terminal,
|
|
134
|
-
keyReader,
|
|
135
|
-
getMockPrinterService(),
|
|
136
|
-
);
|
|
131
|
+
const service = new DefaultPrompterService(config, terminal, keyReader, getMockPrinterService());
|
|
137
132
|
return { service, terminal };
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
const SSH_ENV_KEYS = ["SSH_CONNECTION", "SSH_CLIENT", "SSH_TTY"] as const;
|
|
141
136
|
|
|
142
|
-
function withSshEnvOverride<T>(
|
|
143
|
-
overrides: Record<string, string | undefined>,
|
|
144
|
-
fn: () => T,
|
|
145
|
-
): T {
|
|
137
|
+
function withSshEnvOverride<T>(overrides: Record<string, string | undefined>, fn: () => T): T {
|
|
146
138
|
const saved = SSH_ENV_KEYS.map((k) => process.env[k]);
|
|
147
139
|
SSH_ENV_KEYS.forEach((k) => {
|
|
148
140
|
if (k in overrides) {
|
|
@@ -171,7 +163,9 @@ describe("DefaultPrompterService tests", () => {
|
|
|
171
163
|
const keyReader = new MockKeyReader();
|
|
172
164
|
keyReader.addKeys(
|
|
173
165
|
{ specialKey: SpecialKey.DOWN },
|
|
174
|
-
{
|
|
166
|
+
{
|
|
167
|
+
specialKey: SpecialKey.ENTER,
|
|
168
|
+
},
|
|
175
169
|
);
|
|
176
170
|
const { service } = createService(keyReader);
|
|
177
171
|
|
|
@@ -219,7 +213,9 @@ describe("DefaultPrompterService tests", () => {
|
|
|
219
213
|
const keyReader = new MockKeyReader();
|
|
220
214
|
keyReader.addKeys(
|
|
221
215
|
{ specialKey: SpecialKey.UP },
|
|
222
|
-
{
|
|
216
|
+
{
|
|
217
|
+
specialKey: SpecialKey.ENTER,
|
|
218
|
+
},
|
|
223
219
|
);
|
|
224
220
|
const { service } = createService(keyReader);
|
|
225
221
|
|
|
@@ -238,7 +234,9 @@ describe("DefaultPrompterService tests", () => {
|
|
|
238
234
|
const keyReader = new MockKeyReader();
|
|
239
235
|
keyReader.addKeys(
|
|
240
236
|
{ specialKey: SpecialKey.DOWN },
|
|
241
|
-
{
|
|
237
|
+
{
|
|
238
|
+
specialKey: SpecialKey.ENTER,
|
|
239
|
+
},
|
|
242
240
|
);
|
|
243
241
|
const { service } = createService(keyReader);
|
|
244
242
|
|
|
@@ -258,7 +256,9 @@ describe("DefaultPrompterService tests", () => {
|
|
|
258
256
|
keyReader.addKeys(
|
|
259
257
|
{ key: "h" },
|
|
260
258
|
{ key: "i" },
|
|
261
|
-
{
|
|
259
|
+
{
|
|
260
|
+
specialKey: SpecialKey.ENTER,
|
|
261
|
+
},
|
|
262
262
|
);
|
|
263
263
|
const { service } = createService(keyReader);
|
|
264
264
|
|
|
@@ -325,9 +325,7 @@ describe("DefaultPrompterService tests", () => {
|
|
|
325
325
|
name: "test",
|
|
326
326
|
promptText: "Pick one",
|
|
327
327
|
type: PromptType.SINGLE_SELECT,
|
|
328
|
-
options: [
|
|
329
|
-
{ displayValue: "A", returnedValue: "a" },
|
|
330
|
-
],
|
|
328
|
+
options: [{ displayValue: "A", returnedValue: "a" }],
|
|
331
329
|
}),
|
|
332
330
|
).rejects.toThrow("Prompting is disabled and no default for prompt: test");
|
|
333
331
|
});
|
|
@@ -342,9 +340,7 @@ describe("DefaultPrompterService tests", () => {
|
|
|
342
340
|
name: "test",
|
|
343
341
|
promptText: "Pick one",
|
|
344
342
|
type: PromptType.SINGLE_SELECT,
|
|
345
|
-
options: [
|
|
346
|
-
{ displayValue: "A", returnedValue: "a" },
|
|
347
|
-
],
|
|
343
|
+
options: [{ displayValue: "A", returnedValue: "a" }],
|
|
348
344
|
}),
|
|
349
345
|
).rejects.toThrow("Prompt cancelled");
|
|
350
346
|
});
|
|
@@ -460,9 +456,7 @@ describe("DefaultPrompterService tests", () => {
|
|
|
460
456
|
|
|
461
457
|
expect(terminal.buffer).toContain("Login at:");
|
|
462
458
|
expect(terminal.buffer).toContain("https://example.com/login");
|
|
463
|
-
expect(terminal.buffer).toContain(
|
|
464
|
-
"Press ENTER to open in the browser...",
|
|
465
|
-
);
|
|
459
|
+
expect(terminal.buffer).toContain("Press ENTER to open in the browser...");
|
|
466
460
|
expect(terminal.buffer).toContain("Open browser to login");
|
|
467
461
|
}));
|
|
468
462
|
|
|
@@ -491,9 +485,7 @@ describe("DefaultPrompterService tests", () => {
|
|
|
491
485
|
|
|
492
486
|
expect(result.name).toEqual("login");
|
|
493
487
|
expect(result.value).toEqual("https://example.com/login");
|
|
494
|
-
expect(terminal.buffer).toContain(
|
|
495
|
-
"Failed to open URL: browser not found",
|
|
496
|
-
);
|
|
488
|
+
expect(terminal.buffer).toContain("Failed to open URL: browser not found");
|
|
497
489
|
}));
|
|
498
490
|
|
|
499
491
|
test("OPEN_URL with promptEnabled=false and defaultOption returns default", async () => {
|
|
@@ -538,49 +530,42 @@ describe("DefaultPrompterService tests", () => {
|
|
|
538
530
|
},
|
|
539
531
|
],
|
|
540
532
|
}),
|
|
541
|
-
).rejects.toThrow(
|
|
542
|
-
"Prompting is disabled and no default for prompt: login",
|
|
543
|
-
);
|
|
533
|
+
).rejects.toThrow("Prompting is disabled and no default for prompt: login");
|
|
544
534
|
});
|
|
545
535
|
|
|
546
536
|
test("OPEN_URL in SSH session shows copy message and skips openUrl", () =>
|
|
547
|
-
withSshEnvOverride(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
expect(terminal.buffer).not.toContain(
|
|
580
|
-
"Press ENTER to open in the browser...",
|
|
581
|
-
);
|
|
582
|
-
},
|
|
583
|
-
));
|
|
537
|
+
withSshEnvOverride({ SSH_CONNECTION: "192.168.1.1 12345 192.168.1.2 22" }, async () => {
|
|
538
|
+
const keyReader = new MockKeyReader();
|
|
539
|
+
keyReader.addKeys({ specialKey: SpecialKey.ENTER });
|
|
540
|
+
let openUrlCalled = false;
|
|
541
|
+
const mockOpenUrl = (_url: string): Promise<void> => {
|
|
542
|
+
openUrlCalled = true;
|
|
543
|
+
return Promise.resolve();
|
|
544
|
+
};
|
|
545
|
+
const { service, terminal } = createService(keyReader, {
|
|
546
|
+
openUrl: mockOpenUrl,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
const result = await service.prompt({
|
|
550
|
+
name: "login",
|
|
551
|
+
promptText: "Login at:",
|
|
552
|
+
type: PromptType.OPEN_URL,
|
|
553
|
+
options: [
|
|
554
|
+
{
|
|
555
|
+
displayValue: "Open browser",
|
|
556
|
+
returnedValue: "https://example.com/login",
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
expect(result.name).toEqual("login");
|
|
562
|
+
expect(result.value).toEqual("https://example.com/login");
|
|
563
|
+
expect(openUrlCalled).toBe(false);
|
|
564
|
+
expect(terminal.buffer).toContain(
|
|
565
|
+
"Copy the URL above and open it in your local browser, then press ENTER to continue...",
|
|
566
|
+
);
|
|
567
|
+
expect(terminal.buffer).not.toContain("Press ENTER to open in the browser...");
|
|
568
|
+
}));
|
|
584
569
|
|
|
585
570
|
test("OPEN_URL outside SSH session shows open message", () =>
|
|
586
571
|
withoutSshEnv(async () => {
|
|
@@ -608,8 +593,6 @@ describe("DefaultPrompterService tests", () => {
|
|
|
608
593
|
});
|
|
609
594
|
|
|
610
595
|
expect(openUrlCalled).toBe(true);
|
|
611
|
-
expect(terminal.buffer).toContain(
|
|
612
|
-
"Press ENTER to open in the browser...",
|
|
613
|
-
);
|
|
596
|
+
expect(terminal.buffer).toContain("Press ENTER to open in the browser...");
|
|
614
597
|
}));
|
|
615
598
|
});
|
|
@@ -15,10 +15,7 @@ function getMockPrompterService(): PrompterService {
|
|
|
15
15
|
|
|
16
16
|
describe("PrompterServiceProvider tests", () => {
|
|
17
17
|
test("PrompterServiceProvider has correct serviceId", () => {
|
|
18
|
-
const provider = new PrompterServiceProvider(
|
|
19
|
-
100,
|
|
20
|
-
getMockPrompterService(),
|
|
21
|
-
);
|
|
18
|
+
const provider = new PrompterServiceProvider(100, getMockPrompterService());
|
|
22
19
|
|
|
23
20
|
expect(provider.serviceId).toEqual(PROMPTER_SERVICE_ID);
|
|
24
21
|
});
|
|
@@ -36,10 +33,7 @@ describe("PrompterServiceProvider tests", () => {
|
|
|
36
33
|
});
|
|
37
34
|
|
|
38
35
|
test("PrompterServiceProvider initService resolves", async () => {
|
|
39
|
-
const provider = new PrompterServiceProvider(
|
|
40
|
-
100,
|
|
41
|
-
getMockPrompterService(),
|
|
42
|
-
);
|
|
36
|
+
const provider = new PrompterServiceProvider(100, getMockPrompterService());
|
|
43
37
|
const context = new DefaultContext(getCLIConfig());
|
|
44
38
|
|
|
45
39
|
await expect(provider.initService(context)).resolves.toBeUndefined();
|
|
@@ -5,9 +5,7 @@ import { getCLIConfig } from "../../fixtures/CLIConfig.ts";
|
|
|
5
5
|
describe("ShutdownServiceProvider tests", () => {
|
|
6
6
|
test("ShutdownServiceProvider getServiceInfo works", async () => {
|
|
7
7
|
const shutdownServiceProvider = new ShutdownServiceProvider(100);
|
|
8
|
-
const serviceInfo = await shutdownServiceProvider.getServiceInfo(
|
|
9
|
-
getCLIConfig(),
|
|
10
|
-
);
|
|
8
|
+
const serviceInfo = await shutdownServiceProvider.getServiceInfo(getCLIConfig());
|
|
11
9
|
expect(serviceInfo.commands.length).toEqual(0);
|
|
12
10
|
|
|
13
11
|
await ShutdownServiceProvider.shutdown();
|
|
@@ -17,57 +17,30 @@ describe("DefaultSyntaxHighlighterService tests", () => {
|
|
|
17
17
|
test("Cannot register a syntax if already registered", () => {
|
|
18
18
|
const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
|
|
19
19
|
|
|
20
|
-
expect(() => syntaxHighlighterService.registerSyntax("jSon", yaml))
|
|
21
|
-
.toThrow();
|
|
20
|
+
expect(() => syntaxHighlighterService.registerSyntax("jSon", yaml)).toThrow();
|
|
22
21
|
});
|
|
23
22
|
|
|
24
23
|
test("Can register new syntax", () => {
|
|
25
24
|
const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
|
|
26
25
|
|
|
27
26
|
syntaxHighlighterService.registerSyntax("yaml", yaml);
|
|
28
|
-
expect(syntaxHighlighterService.getRegisteredSyntaxes()).toEqual([
|
|
29
|
-
"json",
|
|
30
|
-
"yaml",
|
|
31
|
-
]);
|
|
27
|
+
expect(syntaxHighlighterService.getRegisteredSyntaxes()).toEqual(["json", "yaml"]);
|
|
32
28
|
});
|
|
33
29
|
|
|
34
30
|
test("Cannot highlight with unknown syntax", () => {
|
|
35
31
|
const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
|
|
36
32
|
|
|
37
|
-
expect(() => syntaxHighlighterService.highlight("foo: 1", "yaml"))
|
|
38
|
-
.toThrow();
|
|
33
|
+
expect(() => syntaxHighlighterService.highlight("foo: 1", "yaml")).toThrow();
|
|
39
34
|
});
|
|
40
35
|
|
|
41
36
|
test("Can highlight with JSON syntax", () => {
|
|
42
37
|
const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
|
|
43
38
|
|
|
44
|
-
const highlighted = syntaxHighlighterService.highlight(
|
|
45
|
-
"{ foo: 1 }",
|
|
46
|
-
"json",
|
|
47
|
-
);
|
|
39
|
+
const highlighted = syntaxHighlighterService.highlight("{ foo: 1 }", "json");
|
|
48
40
|
expectBytesEquals(
|
|
49
41
|
highlighted,
|
|
50
42
|
new Uint8Array([
|
|
51
|
-
123,
|
|
52
|
-
32,
|
|
53
|
-
102,
|
|
54
|
-
111,
|
|
55
|
-
111,
|
|
56
|
-
58,
|
|
57
|
-
32,
|
|
58
|
-
27,
|
|
59
|
-
91,
|
|
60
|
-
51,
|
|
61
|
-
54,
|
|
62
|
-
109,
|
|
63
|
-
49,
|
|
64
|
-
27,
|
|
65
|
-
91,
|
|
66
|
-
51,
|
|
67
|
-
57,
|
|
68
|
-
109,
|
|
69
|
-
32,
|
|
70
|
-
125,
|
|
43
|
+
123, 32, 102, 111, 111, 58, 32, 27, 91, 51, 54, 109, 49, 27, 91, 51, 57, 109, 32, 125,
|
|
71
44
|
]),
|
|
72
45
|
);
|
|
73
46
|
});
|
|
@@ -90,46 +63,14 @@ describe("DefaultSyntaxHighlighterService tests", () => {
|
|
|
90
63
|
|
|
91
64
|
syntaxHighlighterService.colorFunction = printer.color.bind(printer);
|
|
92
65
|
|
|
93
|
-
const highlighted = syntaxHighlighterService.highlight(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
{
|
|
97
|
-
"number": "#FF0000",
|
|
98
|
-
},
|
|
99
|
-
);
|
|
66
|
+
const highlighted = syntaxHighlighterService.highlight("{ foo: 1 }", "json", {
|
|
67
|
+
number: "#FF0000",
|
|
68
|
+
});
|
|
100
69
|
expectBytesEquals(
|
|
101
70
|
highlighted,
|
|
102
71
|
new Uint8Array([
|
|
103
|
-
123,
|
|
104
|
-
32,
|
|
105
|
-
102,
|
|
106
|
-
111,
|
|
107
|
-
111,
|
|
108
|
-
58,
|
|
109
|
-
32,
|
|
110
|
-
27,
|
|
111
|
-
91,
|
|
112
|
-
51,
|
|
113
|
-
56,
|
|
114
|
-
59,
|
|
115
|
-
50,
|
|
116
|
-
59,
|
|
117
|
-
50,
|
|
118
|
-
53,
|
|
119
|
-
53,
|
|
120
|
-
59,
|
|
121
|
-
48,
|
|
122
|
-
59,
|
|
123
|
-
48,
|
|
124
|
-
109,
|
|
125
|
-
49,
|
|
126
|
-
27,
|
|
127
|
-
91,
|
|
128
|
-
51,
|
|
129
|
-
57,
|
|
130
|
-
109,
|
|
131
|
-
32,
|
|
132
|
-
125,
|
|
72
|
+
123, 32, 102, 111, 111, 58, 32, 27, 91, 51, 56, 59, 50, 59, 50, 53, 53, 59, 48, 59, 48, 109,
|
|
73
|
+
49, 27, 91, 51, 57, 109, 32, 125,
|
|
133
74
|
]),
|
|
134
75
|
);
|
|
135
76
|
});
|
|
@@ -143,32 +84,8 @@ describe("DefaultSyntaxHighlighterService tests", () => {
|
|
|
143
84
|
expectBytesEquals(
|
|
144
85
|
highlighted,
|
|
145
86
|
new Uint8Array([
|
|
146
|
-
27,
|
|
147
|
-
91,
|
|
148
|
-
51,
|
|
149
|
-
51,
|
|
150
|
-
109,
|
|
151
|
-
102,
|
|
152
|
-
111,
|
|
153
|
-
111,
|
|
154
|
-
58,
|
|
155
|
-
27,
|
|
156
|
-
91,
|
|
157
|
-
51,
|
|
158
|
-
57,
|
|
159
|
-
109,
|
|
160
|
-
32,
|
|
161
|
-
27,
|
|
162
|
-
91,
|
|
163
|
-
51,
|
|
164
|
-
54,
|
|
165
|
-
109,
|
|
166
|
-
49,
|
|
167
|
-
27,
|
|
168
|
-
91,
|
|
169
|
-
51,
|
|
170
|
-
57,
|
|
171
|
-
109,
|
|
87
|
+
27, 91, 51, 51, 109, 102, 111, 111, 58, 27, 91, 51, 57, 109, 32, 27, 91, 51, 54, 109, 49,
|
|
88
|
+
27, 91, 51, 57, 109,
|
|
172
89
|
]),
|
|
173
90
|
);
|
|
174
91
|
});
|
|
@@ -177,10 +94,7 @@ describe("DefaultSyntaxHighlighterService tests", () => {
|
|
|
177
94
|
const syntaxHighlighterService = new DefaultSyntaxHighlighterService();
|
|
178
95
|
syntaxHighlighterService.colorEnabled = false;
|
|
179
96
|
|
|
180
|
-
const highlighted = syntaxHighlighterService.highlight(
|
|
181
|
-
"{ foo: 1 }",
|
|
182
|
-
"json",
|
|
183
|
-
);
|
|
97
|
+
const highlighted = syntaxHighlighterService.highlight("{ foo: 1 }", "json");
|
|
184
98
|
|
|
185
99
|
expect(highlighted).toEqual("{ foo: 1 }");
|
|
186
100
|
});
|
|
@@ -12,10 +12,7 @@ describe("SyntaxHighlighterServiceProvider tests", () => {
|
|
|
12
12
|
test("SyntaxHighlighterServiceProvider getServiceInfo and initService works", async () => {
|
|
13
13
|
const dummyStdout = new StreamString();
|
|
14
14
|
const dummyStderr = new StreamString();
|
|
15
|
-
const syntaxHighlighterServiceProvider =
|
|
16
|
-
new SyntaxHighlighterServiceProvider(
|
|
17
|
-
100,
|
|
18
|
-
);
|
|
15
|
+
const syntaxHighlighterServiceProvider = new SyntaxHighlighterServiceProvider(100);
|
|
19
16
|
const cliConfig = getCLIConfig();
|
|
20
17
|
const context = new DefaultContext(cliConfig);
|
|
21
18
|
|
|
@@ -32,9 +29,7 @@ describe("SyntaxHighlighterServiceProvider tests", () => {
|
|
|
32
29
|
),
|
|
33
30
|
);
|
|
34
31
|
|
|
35
|
-
const serviceInfo = await syntaxHighlighterServiceProvider.getServiceInfo(
|
|
36
|
-
cliConfig,
|
|
37
|
-
);
|
|
32
|
+
const serviceInfo = await syntaxHighlighterServiceProvider.getServiceInfo(cliConfig);
|
|
38
33
|
expect(serviceInfo.commands.length).toEqual(0);
|
|
39
34
|
|
|
40
35
|
await syntaxHighlighterServiceProvider.initService(context);
|
|
@@ -136,9 +136,7 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
136
136
|
|
|
137
137
|
const result = service.render(table);
|
|
138
138
|
const lines = result.split("\n");
|
|
139
|
-
const contentLines = lines.filter((l) =>
|
|
140
|
-
l.startsWith("│") && !l.includes("─")
|
|
141
|
-
);
|
|
139
|
+
const contentLines = lines.filter((l) => l.startsWith("│") && !l.includes("─"));
|
|
142
140
|
expect(contentLines.length).toBeGreaterThan(1);
|
|
143
141
|
// Each content line should have complete words (no mid-word breaks)
|
|
144
142
|
for (const line of contentLines) {
|
|
@@ -146,9 +144,7 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
146
144
|
if (content.length > 0) {
|
|
147
145
|
const words = content.split(/\s+/);
|
|
148
146
|
for (const word of words) {
|
|
149
|
-
expect(
|
|
150
|
-
["hello", "world", "foo", "bar", ""].includes(word),
|
|
151
|
-
).toBe(true);
|
|
147
|
+
expect(["hello", "world", "foo", "bar", ""].includes(word)).toBe(true);
|
|
152
148
|
}
|
|
153
149
|
}
|
|
154
150
|
}
|
|
@@ -163,14 +159,10 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
163
159
|
|
|
164
160
|
const result = service.render(table);
|
|
165
161
|
const lines = result.split("\n");
|
|
166
|
-
const contentLines = lines.filter((l) =>
|
|
167
|
-
l.startsWith("│") && !l.includes("─")
|
|
168
|
-
);
|
|
162
|
+
const contentLines = lines.filter((l) => l.startsWith("│") && !l.includes("─"));
|
|
169
163
|
expect(contentLines.length).toBeGreaterThan(1);
|
|
170
164
|
// Verify all characters are present
|
|
171
|
-
const allContent = contentLines
|
|
172
|
-
.map((l) => l.replace(/│/g, "").replace(/ /g, ""))
|
|
173
|
-
.join("");
|
|
165
|
+
const allContent = contentLines.map((l) => l.replace(/│/g, "").replace(/ /g, "")).join("");
|
|
174
166
|
expect(allContent).toBe("ABCDEFGHIJKLMNOP");
|
|
175
167
|
});
|
|
176
168
|
|
|
@@ -245,8 +237,7 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
245
237
|
|
|
246
238
|
test("empty cells render as blank space", () => {
|
|
247
239
|
const service = createService();
|
|
248
|
-
const table = new Table(1, 2, { maxWidth: 20, padding: 1 })
|
|
249
|
-
.cell(0, 0, "Hi");
|
|
240
|
+
const table = new Table(1, 2, { maxWidth: 20, padding: 1 }).cell(0, 0, "Hi");
|
|
250
241
|
// cell(0, 1) not set
|
|
251
242
|
|
|
252
243
|
const result = service.render(table);
|
|
@@ -269,9 +260,7 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
269
260
|
const result = service.render(table);
|
|
270
261
|
const lines = result.split("\n");
|
|
271
262
|
// Filter content lines (between top and bottom borders)
|
|
272
|
-
const contentLines = lines.filter((l) =>
|
|
273
|
-
l.startsWith("│") && !l.includes("─")
|
|
274
|
-
);
|
|
263
|
+
const contentLines = lines.filter((l) => l.startsWith("│") && !l.includes("─"));
|
|
275
264
|
// Row should have 3 sub-lines due to multi-line content
|
|
276
265
|
expect(contentLines.length).toBe(3);
|
|
277
266
|
expect(contentLines[0]).toContain("line1");
|
|
@@ -304,8 +293,7 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
304
293
|
|
|
305
294
|
test("1x1 table renders correctly", () => {
|
|
306
295
|
const service = createService();
|
|
307
|
-
const table = new Table(1, 1, { maxWidth: 10, padding: 0 })
|
|
308
|
-
.cell(0, 0, "Hi");
|
|
296
|
+
const table = new Table(1, 1, { maxWidth: 10, padding: 0 }).cell(0, 0, "Hi");
|
|
309
297
|
|
|
310
298
|
const result = service.render(table);
|
|
311
299
|
const lines = result.split("\n");
|
|
@@ -319,8 +307,7 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
319
307
|
|
|
320
308
|
test("padding=0 works", () => {
|
|
321
309
|
const service = createService();
|
|
322
|
-
const table = new Table(1, 1, { maxWidth: 10, padding: 0 })
|
|
323
|
-
.cell(0, 0, "AB");
|
|
310
|
+
const table = new Table(1, 1, { maxWidth: 10, padding: 0 }).cell(0, 0, "AB");
|
|
324
311
|
|
|
325
312
|
const result = service.render(table);
|
|
326
313
|
const lines = result.split("\n");
|
|
@@ -335,22 +322,14 @@ describe("DefaultTableGeneratorService tests", () => {
|
|
|
335
322
|
|
|
336
323
|
test("out-of-bounds row index throws", () => {
|
|
337
324
|
const table = new Table(2, 2);
|
|
338
|
-
expect(() => table.row(5, { align: Align.LEFT })).toThrow(
|
|
339
|
-
|
|
340
|
-
);
|
|
341
|
-
expect(() => table.row(-1, { align: Align.LEFT })).toThrow(
|
|
342
|
-
/out of bounds/,
|
|
343
|
-
);
|
|
325
|
+
expect(() => table.row(5, { align: Align.LEFT })).toThrow(/out of bounds/);
|
|
326
|
+
expect(() => table.row(-1, { align: Align.LEFT })).toThrow(/out of bounds/);
|
|
344
327
|
});
|
|
345
328
|
|
|
346
329
|
test("out-of-bounds column index throws", () => {
|
|
347
330
|
const table = new Table(2, 2);
|
|
348
|
-
expect(() => table.column(5, { flexWeight: 1 })).toThrow(
|
|
349
|
-
|
|
350
|
-
);
|
|
351
|
-
expect(() => table.column(-1, { flexWeight: 1 })).toThrow(
|
|
352
|
-
/out of bounds/,
|
|
353
|
-
);
|
|
331
|
+
expect(() => table.column(5, { flexWeight: 1 })).toThrow(/out of bounds/);
|
|
332
|
+
expect(() => table.column(-1, { flexWeight: 1 })).toThrow(/out of bounds/);
|
|
354
333
|
});
|
|
355
334
|
|
|
356
335
|
test("out-of-bounds cell index throws", () => {
|
|
@@ -38,8 +38,8 @@ describe("TableGeneratorServiceProvider tests", () => {
|
|
|
38
38
|
const serviceInfo = await provider.getServiceInfo(cliConfig);
|
|
39
39
|
expect(serviceInfo.commands.length).toEqual(0);
|
|
40
40
|
await provider.initService(context);
|
|
41
|
-
const service =
|
|
42
|
-
.service as import("../../../src/service/tableGenerator/DefaultTableGeneratorService.ts").default;
|
|
41
|
+
const service =
|
|
42
|
+
serviceInfo.service as import("../../../src/service/tableGenerator/DefaultTableGeneratorService.ts").default;
|
|
43
43
|
expect(service.colorEnabled).toBe(true);
|
|
44
44
|
expect(typeof service.colorFunction).toBe("function");
|
|
45
45
|
expect(typeof service.backgroundColorFunction).toBe("function");
|
|
@@ -33,7 +33,9 @@ describe("DefaultTreePrinterService tests", () => {
|
|
|
33
33
|
label: "Root",
|
|
34
34
|
children: [
|
|
35
35
|
{ label: "Child1", children: ["Leaf1", "Leaf2"] },
|
|
36
|
-
{
|
|
36
|
+
{
|
|
37
|
+
label: "Child2",
|
|
38
|
+
},
|
|
37
39
|
],
|
|
38
40
|
});
|
|
39
41
|
|
|
@@ -51,11 +53,7 @@ describe("DefaultTreePrinterService tests", () => {
|
|
|
51
53
|
|
|
52
54
|
const result = service.print({
|
|
53
55
|
label: "Root",
|
|
54
|
-
children: [
|
|
55
|
-
"StringChild",
|
|
56
|
-
{ label: "NodeChild", children: ["Nested"] },
|
|
57
|
-
"Last",
|
|
58
|
-
],
|
|
56
|
+
children: ["StringChild", { label: "NodeChild", children: ["Nested"] }, "Last"],
|
|
59
57
|
});
|
|
60
58
|
|
|
61
59
|
const lines = result.split("\n");
|
|
@@ -13,9 +13,7 @@ describe("TreePrinterServiceProvider tests", () => {
|
|
|
13
13
|
const treePrinterServiceProvider = new TreePrinterServiceProvider(100);
|
|
14
14
|
const cliConfig = getCLIConfig();
|
|
15
15
|
|
|
16
|
-
const serviceInfo = await treePrinterServiceProvider.getServiceInfo(
|
|
17
|
-
cliConfig,
|
|
18
|
-
);
|
|
16
|
+
const serviceInfo = await treePrinterServiceProvider.getServiceInfo(cliConfig);
|
|
19
17
|
expect(serviceInfo.commands.length).toEqual(0);
|
|
20
18
|
expect(serviceInfo.service).toBeDefined();
|
|
21
19
|
});
|
|
@@ -40,15 +38,13 @@ describe("TreePrinterServiceProvider tests", () => {
|
|
|
40
38
|
),
|
|
41
39
|
);
|
|
42
40
|
|
|
43
|
-
const serviceInfo = await treePrinterServiceProvider.getServiceInfo(
|
|
44
|
-
cliConfig,
|
|
45
|
-
);
|
|
41
|
+
const serviceInfo = await treePrinterServiceProvider.getServiceInfo(cliConfig);
|
|
46
42
|
expect(serviceInfo.commands.length).toEqual(0);
|
|
47
43
|
|
|
48
44
|
await treePrinterServiceProvider.initService(context);
|
|
49
45
|
|
|
50
|
-
const service =
|
|
51
|
-
.service as import("../../../src/service/treePrinter/DefaultTreePrinterService.ts").default;
|
|
46
|
+
const service =
|
|
47
|
+
serviceInfo.service as import("../../../src/service/treePrinter/DefaultTreePrinterService.ts").default;
|
|
52
48
|
expect(service.colorEnabled).toBe(true);
|
|
53
49
|
expect(typeof service.colorFunction).toBe("function");
|
|
54
50
|
});
|
|
@@ -31,11 +31,7 @@ function crc32(data: Uint8Array): number {
|
|
|
31
31
|
return (crc ^ 0xffffffff) >>> 0;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function buildValidPng(
|
|
35
|
-
width: number,
|
|
36
|
-
height: number,
|
|
37
|
-
colorType: number = 6,
|
|
38
|
-
): Uint8Array {
|
|
34
|
+
function buildValidPng(width: number, height: number, colorType: number = 6): Uint8Array {
|
|
39
35
|
const parts: number[] = [];
|
|
40
36
|
|
|
41
37
|
// PNG signature
|
|
@@ -44,12 +40,7 @@ function buildValidPng(
|
|
|
44
40
|
function addChunk(type: string, data: Uint8Array) {
|
|
45
41
|
// Length (4 bytes big-endian)
|
|
46
42
|
const len = data.length;
|
|
47
|
-
parts.push(
|
|
48
|
-
(len >>> 24) & 0xff,
|
|
49
|
-
(len >>> 16) & 0xff,
|
|
50
|
-
(len >>> 8) & 0xff,
|
|
51
|
-
len & 0xff,
|
|
52
|
-
);
|
|
43
|
+
parts.push((len >>> 24) & 0xff, (len >>> 16) & 0xff, (len >>> 8) & 0xff, len & 0xff);
|
|
53
44
|
|
|
54
45
|
// Type (4 bytes)
|
|
55
46
|
const typeBytes = new TextEncoder().encode(type);
|
|
@@ -3,9 +3,7 @@ import { describe, expect, test } from "bun:test";
|
|
|
3
3
|
import { decodePngToRGBA } from "../../src/terminal/PngDecoder.ts";
|
|
4
4
|
|
|
5
5
|
// Helper to build a minimal PNG from raw components
|
|
6
|
-
function buildPng(
|
|
7
|
-
chunks: Array<{ type: string; data: Uint8Array }>,
|
|
8
|
-
): Uint8Array {
|
|
6
|
+
function buildPng(chunks: Array<{ type: string; data: Uint8Array }>): Uint8Array {
|
|
9
7
|
const parts: Uint8Array[] = [];
|
|
10
8
|
// PNG signature
|
|
11
9
|
parts.push(new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]));
|
|
@@ -177,9 +175,7 @@ describe("decodePngToRGBA", () => {
|
|
|
177
175
|
{ type: "IHDR", data: makeIHDR(1, 1, 8, 6, 1) },
|
|
178
176
|
{ type: "IEND", data: new Uint8Array(0) },
|
|
179
177
|
]);
|
|
180
|
-
expect(() => decodePngToRGBA(png)).toThrow(
|
|
181
|
-
"Interlaced PNGs are not supported",
|
|
182
|
-
);
|
|
178
|
+
expect(() => decodePngToRGBA(png)).toThrow("Interlaced PNGs are not supported");
|
|
183
179
|
});
|
|
184
180
|
|
|
185
181
|
test("throws on unknown filter type", () => {
|