@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
|
@@ -1,29 +1,9 @@
|
|
|
1
1
|
import type Styler from "../../../terminal/Styler.ts";
|
|
2
2
|
import type Terminal from "../../../terminal/Terminal.ts";
|
|
3
3
|
|
|
4
|
-
const BOX_FRAMES = [
|
|
5
|
-
"⠋",
|
|
6
|
-
"⠙",
|
|
7
|
-
"⠹",
|
|
8
|
-
"⠸",
|
|
9
|
-
"⠼",
|
|
10
|
-
"⠴",
|
|
11
|
-
"⠦",
|
|
12
|
-
"⠧",
|
|
13
|
-
"⠇",
|
|
14
|
-
"⠏",
|
|
15
|
-
];
|
|
4
|
+
const BOX_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
16
5
|
|
|
17
|
-
const STAR_FRAMES = [
|
|
18
|
-
"★",
|
|
19
|
-
"✶",
|
|
20
|
-
"✷",
|
|
21
|
-
"✹",
|
|
22
|
-
"✷",
|
|
23
|
-
"✶",
|
|
24
|
-
"★",
|
|
25
|
-
"✦",
|
|
26
|
-
];
|
|
6
|
+
const STAR_FRAMES = ["★", "✶", "✷", "✹", "✷", "✶", "★", "✦"];
|
|
27
7
|
|
|
28
8
|
export { SpinnerStyle } from "../../../api/service/core/PrinterService.ts";
|
|
29
9
|
import { SpinnerStyle } from "../../../api/service/core/PrinterService.ts";
|
|
@@ -56,9 +36,10 @@ export default class Spinner {
|
|
|
56
36
|
await this.#terminal.clearLine();
|
|
57
37
|
if (this.#message) {
|
|
58
38
|
await this.#terminal.write(
|
|
59
|
-
`${
|
|
60
|
-
|
|
61
|
-
|
|
39
|
+
`${this.#styler.colorText(
|
|
40
|
+
frames[this.#frameIndex]!,
|
|
41
|
+
this.#spinColor,
|
|
42
|
+
)} ${this.#styler.colorText(this.#message!, this.#msgColor)}`,
|
|
62
43
|
);
|
|
63
44
|
} else {
|
|
64
45
|
await this.#terminal.write(
|
|
@@ -102,7 +83,7 @@ export default class Spinner {
|
|
|
102
83
|
}
|
|
103
84
|
|
|
104
85
|
public resume(): void {
|
|
105
|
-
if (
|
|
86
|
+
if (!this.#isShown || this.#timer !== undefined) {
|
|
106
87
|
return;
|
|
107
88
|
}
|
|
108
89
|
this.#timer = setInterval(async () => {
|
|
@@ -53,9 +53,7 @@ export default class DefaultPrompterService implements PrompterService {
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
return Promise.reject(
|
|
56
|
-
new Error(
|
|
57
|
-
`Prompting is disabled and no default for prompt: ${promptDef.name}`,
|
|
58
|
-
),
|
|
56
|
+
new Error(`Prompting is disabled and no default for prompt: ${promptDef.name}`),
|
|
59
57
|
);
|
|
60
58
|
}
|
|
61
59
|
|
|
@@ -75,9 +73,7 @@ export default class DefaultPrompterService implements PrompterService {
|
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
async promptAll(
|
|
79
|
-
prompts: ReadonlyArray<Prompt>,
|
|
80
|
-
): Promise<ReadonlyArray<PromptResult>> {
|
|
76
|
+
async promptAll(prompts: ReadonlyArray<Prompt>): Promise<ReadonlyArray<PromptResult>> {
|
|
81
77
|
const results: PromptResult[] = [];
|
|
82
78
|
for (const p of prompts) {
|
|
83
79
|
results.push(await this.prompt(p));
|
|
@@ -1,8 +1,5 @@
|
|
|
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 type PrompterService from "../../api/service/core/PrompterService.ts";
|
|
7
4
|
import { PROMPTER_SERVICE_ID } from "../../api/service/core/PrompterService.ts";
|
|
8
5
|
import NoPromptCommand from "./command/NoPromptCommand.ts";
|
|
@@ -13,10 +10,7 @@ export default class PrompterServiceProvider implements ServiceProvider {
|
|
|
13
10
|
readonly servicePriority: number;
|
|
14
11
|
readonly prompterService: PrompterService;
|
|
15
12
|
|
|
16
|
-
public constructor(
|
|
17
|
-
servicePriority: number,
|
|
18
|
-
prompterService: PrompterService,
|
|
19
|
-
) {
|
|
13
|
+
public constructor(servicePriority: number, prompterService: PrompterService) {
|
|
20
14
|
this.servicePriority = servicePriority;
|
|
21
15
|
this.prompterService = prompterService;
|
|
22
16
|
}
|
|
@@ -24,9 +18,7 @@ export default class PrompterServiceProvider implements ServiceProvider {
|
|
|
24
18
|
public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
|
|
25
19
|
return Promise.resolve({
|
|
26
20
|
service: this.prompterService,
|
|
27
|
-
commands: [
|
|
28
|
-
new NoPromptCommand(this, this.servicePriority),
|
|
29
|
-
],
|
|
21
|
+
commands: [new NoPromptCommand(this, this.servicePriority)],
|
|
30
22
|
});
|
|
31
23
|
}
|
|
32
24
|
|
|
@@ -20,20 +20,13 @@ export default class NoPromptCommand implements GlobalModifierCommand {
|
|
|
20
20
|
|
|
21
21
|
readonly #prompterServiceProvider: PrompterServiceProvider;
|
|
22
22
|
|
|
23
|
-
public constructor(
|
|
24
|
-
prompterServiceProvider: PrompterServiceProvider,
|
|
25
|
-
executePriority: number,
|
|
26
|
-
) {
|
|
23
|
+
public constructor(prompterServiceProvider: PrompterServiceProvider, executePriority: number) {
|
|
27
24
|
this.#prompterServiceProvider = prompterServiceProvider;
|
|
28
25
|
this.executePriority = executePriority;
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
public execute(
|
|
32
|
-
|
|
33
|
-
argumentValue: ArgumentSingleValueType,
|
|
34
|
-
): Promise<void> {
|
|
35
|
-
this.#prompterServiceProvider.prompterService.promptEnabled =
|
|
36
|
-
!(argumentValue as boolean);
|
|
28
|
+
public execute(_context: Context, argumentValue: ArgumentSingleValueType): Promise<void> {
|
|
29
|
+
this.#prompterServiceProvider.prompterService.promptEnabled = !(argumentValue as boolean);
|
|
37
30
|
|
|
38
31
|
return Promise.resolve();
|
|
39
32
|
}
|
|
@@ -11,20 +11,14 @@ export interface PromptContext {
|
|
|
11
11
|
readonly printerService: PrinterService;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function physicalLineCount(
|
|
15
|
-
terminal: Terminal,
|
|
16
|
-
text: string,
|
|
17
|
-
): number {
|
|
14
|
+
export function physicalLineCount(terminal: Terminal, text: string): number {
|
|
18
15
|
const cols = terminal.columns();
|
|
19
16
|
if (cols <= 0) return 1;
|
|
20
17
|
const width = Bun.stringWidth(text);
|
|
21
18
|
return Math.max(1, Math.ceil(width / cols));
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
export function headerLineCount(
|
|
25
|
-
terminal: Terminal,
|
|
26
|
-
promptDef: Prompt,
|
|
27
|
-
): number {
|
|
21
|
+
export function headerLineCount(terminal: Terminal, promptDef: Prompt): number {
|
|
28
22
|
let count = physicalLineCount(terminal, promptDef.promptText);
|
|
29
23
|
if (promptDef.description) {
|
|
30
24
|
count += physicalLineCount(terminal, promptDef.description);
|
|
@@ -32,16 +26,9 @@ export function headerLineCount(
|
|
|
32
26
|
return count;
|
|
33
27
|
}
|
|
34
28
|
|
|
35
|
-
export async function renderPromptHeader(
|
|
36
|
-
ctx
|
|
37
|
-
promptDef: Prompt,
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
await ctx.terminal.write(
|
|
40
|
-
`${ctx.printerService.emphasised(promptDef.promptText)}\n`,
|
|
41
|
-
);
|
|
29
|
+
export async function renderPromptHeader(ctx: PromptContext, promptDef: Prompt): Promise<void> {
|
|
30
|
+
await ctx.terminal.write(`${ctx.printerService.emphasised(promptDef.promptText)}\n`);
|
|
42
31
|
if (promptDef.description) {
|
|
43
|
-
await ctx.terminal.write(
|
|
44
|
-
`${ctx.printerService.secondary(promptDef.description)}\n`,
|
|
45
|
-
);
|
|
32
|
+
await ctx.terminal.write(`${ctx.printerService.secondary(promptDef.description)}\n`);
|
|
46
33
|
}
|
|
47
34
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Prompt,
|
|
3
|
-
PromptResult,
|
|
4
|
-
} from "../../../api/service/core/PrompterService.ts";
|
|
1
|
+
import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
|
|
5
2
|
import { SpecialKey } from "../../../terminal/KeyReader.ts";
|
|
6
3
|
import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
|
|
7
4
|
import { headerLineCount, renderPromptHeader } from "./PromptContext.ts";
|
|
@@ -19,10 +16,7 @@ export default async function promptMultiSelect(
|
|
|
19
16
|
let focusIndex = 0;
|
|
20
17
|
const checked = new Set<number>();
|
|
21
18
|
let scrollOffset = 0;
|
|
22
|
-
const visibleCount = Math.min(
|
|
23
|
-
ctx.config.scrollVisibleOptions,
|
|
24
|
-
options.length,
|
|
25
|
-
);
|
|
19
|
+
const visibleCount = Math.min(ctx.config.scrollVisibleOptions, options.length);
|
|
26
20
|
|
|
27
21
|
ctx.keyReader.enableRawMode();
|
|
28
22
|
try {
|
|
@@ -51,15 +45,11 @@ export default async function promptMultiSelect(
|
|
|
51
45
|
const isChecked = checked.has(i);
|
|
52
46
|
const checkbox = isChecked
|
|
53
47
|
? ctx.printerService.green(ctx.config.checkboxCheckedChars)
|
|
54
|
-
: ctx.printerService.secondary(
|
|
55
|
-
ctx.config.checkboxUncheckedChars,
|
|
56
|
-
);
|
|
48
|
+
: ctx.printerService.secondary(ctx.config.checkboxUncheckedChars);
|
|
57
49
|
const text = option.displayValue;
|
|
58
50
|
await ctx.terminal.write(
|
|
59
51
|
`${checkbox} ${
|
|
60
|
-
isFocused
|
|
61
|
-
? ctx.printerService.cyan(text)
|
|
62
|
-
: ctx.printerService.secondary(text)
|
|
52
|
+
isFocused ? ctx.printerService.cyan(text) : ctx.printerService.secondary(text)
|
|
63
53
|
}\n`,
|
|
64
54
|
);
|
|
65
55
|
}
|
|
@@ -67,10 +57,7 @@ export default async function promptMultiSelect(
|
|
|
67
57
|
const keyEvent = await ctx.keyReader.readKey();
|
|
68
58
|
if (keyEvent.specialKey === SpecialKey.UP && focusIndex > 0) {
|
|
69
59
|
focusIndex--;
|
|
70
|
-
} else if (
|
|
71
|
-
keyEvent.specialKey === SpecialKey.DOWN &&
|
|
72
|
-
focusIndex < options.length - 1
|
|
73
|
-
) {
|
|
60
|
+
} else if (keyEvent.specialKey === SpecialKey.DOWN && focusIndex < options.length - 1) {
|
|
74
61
|
focusIndex++;
|
|
75
62
|
} else if (keyEvent.specialKey === SpecialKey.SPACE) {
|
|
76
63
|
if (checked.has(focusIndex)) {
|
|
@@ -80,9 +67,7 @@ export default async function promptMultiSelect(
|
|
|
80
67
|
}
|
|
81
68
|
} else if (keyEvent.specialKey === SpecialKey.ENTER) {
|
|
82
69
|
await ctx.terminal.showCursor();
|
|
83
|
-
const values = [...checked].sort().map(
|
|
84
|
-
(i) => options[i]!.returnedValue,
|
|
85
|
-
);
|
|
70
|
+
const values = [...checked].sort().map((i) => options[i]!.returnedValue);
|
|
86
71
|
return { name: promptDef.name, value: values };
|
|
87
72
|
} else if (keyEvent.specialKey === SpecialKey.ESCAPE) {
|
|
88
73
|
await ctx.terminal.showCursor();
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Prompt,
|
|
3
|
-
PromptResult,
|
|
4
|
-
} from "../../../api/service/core/PrompterService.ts";
|
|
1
|
+
import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
|
|
5
2
|
import { SpecialKey } from "../../../terminal/KeyReader.ts";
|
|
6
3
|
import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
|
|
7
4
|
import { renderPromptHeader } from "./PromptContext.ts";
|
|
8
5
|
import type { PromptContext } from "./PromptContext.ts";
|
|
9
6
|
|
|
10
7
|
function isRemoteSession(): boolean {
|
|
11
|
-
return !!(
|
|
12
|
-
process.env.SSH_CONNECTION ||
|
|
13
|
-
process.env.SSH_CLIENT ||
|
|
14
|
-
process.env.SSH_TTY
|
|
15
|
-
);
|
|
8
|
+
return !!(process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY);
|
|
16
9
|
}
|
|
17
10
|
|
|
18
11
|
async function defaultOpenUrl(url: string): Promise<void> {
|
|
@@ -53,16 +46,12 @@ export default async function promptOpenUrl(
|
|
|
53
46
|
try {
|
|
54
47
|
await renderPromptHeader(ctx, promptDef);
|
|
55
48
|
|
|
56
|
-
await ctx.terminal.write(
|
|
57
|
-
`${displayLabel}: ${ctx.printerService.cyan(url)}\n`,
|
|
58
|
-
);
|
|
49
|
+
await ctx.terminal.write(`${displayLabel}: ${ctx.printerService.cyan(url)}\n`);
|
|
59
50
|
|
|
60
51
|
const instruction = canOpenBrowser
|
|
61
52
|
? "Press ENTER to open in the browser..."
|
|
62
53
|
: "Copy the URL above and open it in your local browser, then press ENTER to continue...";
|
|
63
|
-
await ctx.terminal.write(
|
|
64
|
-
`${ctx.printerService.secondary(instruction)}\n`,
|
|
65
|
-
);
|
|
54
|
+
await ctx.terminal.write(`${ctx.printerService.secondary(instruction)}\n`);
|
|
66
55
|
|
|
67
56
|
while (true) {
|
|
68
57
|
const keyEvent = await ctx.keyReader.readKey();
|
|
@@ -73,13 +62,9 @@ export default async function promptOpenUrl(
|
|
|
73
62
|
await openUrlFn(url);
|
|
74
63
|
} catch (e) {
|
|
75
64
|
await ctx.terminal.write(
|
|
76
|
-
`${
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
e instanceof Error ? e.message : String(e)
|
|
80
|
-
}`,
|
|
81
|
-
)
|
|
82
|
-
}\n`,
|
|
65
|
+
`${ctx.printerService.red(
|
|
66
|
+
`Failed to open URL: ${e instanceof Error ? e.message : String(e)}`,
|
|
67
|
+
)}\n`,
|
|
83
68
|
);
|
|
84
69
|
}
|
|
85
70
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Prompt,
|
|
3
|
-
PromptResult,
|
|
4
|
-
} from "../../../api/service/core/PrompterService.ts";
|
|
1
|
+
import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
|
|
5
2
|
import { SpecialKey } from "../../../terminal/KeyReader.ts";
|
|
6
3
|
import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
|
|
7
4
|
import { headerLineCount, renderPromptHeader } from "./PromptContext.ts";
|
|
@@ -25,10 +22,7 @@ export default async function promptSingleSelect(
|
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
let scrollOffset = 0;
|
|
28
|
-
const visibleCount = Math.min(
|
|
29
|
-
ctx.config.scrollVisibleOptions,
|
|
30
|
-
options.length,
|
|
31
|
-
);
|
|
25
|
+
const visibleCount = Math.min(ctx.config.scrollVisibleOptions, options.length);
|
|
32
26
|
|
|
33
27
|
ctx.keyReader.enableRawMode();
|
|
34
28
|
try {
|
|
@@ -57,32 +51,21 @@ export default async function promptSingleSelect(
|
|
|
57
51
|
const prefix = isSelected ? ctx.config.inputPromptCharacters : " ";
|
|
58
52
|
const text = prefix + option.displayValue;
|
|
59
53
|
await ctx.terminal.write(
|
|
60
|
-
`${
|
|
61
|
-
isSelected
|
|
62
|
-
? ctx.printerService.cyan(text)
|
|
63
|
-
: ctx.printerService.secondary(text)
|
|
64
|
-
}\n`,
|
|
54
|
+
`${isSelected ? ctx.printerService.cyan(text) : ctx.printerService.secondary(text)}\n`,
|
|
65
55
|
);
|
|
66
56
|
}
|
|
67
57
|
|
|
68
58
|
const keyEvent = await ctx.keyReader.readKey();
|
|
69
59
|
if (keyEvent.specialKey === SpecialKey.UP && selectedIndex > 0) {
|
|
70
60
|
selectedIndex--;
|
|
71
|
-
} else if (
|
|
72
|
-
keyEvent.specialKey === SpecialKey.DOWN &&
|
|
73
|
-
selectedIndex < options.length - 1
|
|
74
|
-
) {
|
|
61
|
+
} else if (keyEvent.specialKey === SpecialKey.DOWN && selectedIndex < options.length - 1) {
|
|
75
62
|
selectedIndex++;
|
|
76
63
|
} else if (keyEvent.specialKey === SpecialKey.ENTER) {
|
|
77
64
|
await ctx.terminal.showCursor();
|
|
78
65
|
const option = options[selectedIndex]!;
|
|
79
|
-
const validationError = option.validate
|
|
80
|
-
? option.validate(option.returnedValue)
|
|
81
|
-
: undefined;
|
|
66
|
+
const validationError = option.validate ? option.validate(option.returnedValue) : undefined;
|
|
82
67
|
if (validationError) {
|
|
83
|
-
await ctx.terminal.write(
|
|
84
|
-
`${ctx.printerService.red(validationError)}\n`,
|
|
85
|
-
);
|
|
68
|
+
await ctx.terminal.write(`${ctx.printerService.red(validationError)}\n`);
|
|
86
69
|
firstRender = true;
|
|
87
70
|
continue;
|
|
88
71
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Prompt,
|
|
3
|
-
PromptResult,
|
|
4
|
-
} from "../../../api/service/core/PrompterService.ts";
|
|
1
|
+
import type { Prompt, PromptResult } from "../../../api/service/core/PrompterService.ts";
|
|
5
2
|
import type { ArgumentSingleValueType } from "../../../api/argument/ArgumentValueTypes.ts";
|
|
6
3
|
import { SpecialKey } from "../../../terminal/KeyReader.ts";
|
|
7
4
|
import ShutdownServiceProvider from "../../shutdown/ShutdownServiceProvider.ts";
|
|
@@ -16,14 +13,10 @@ export default async function promptText(
|
|
|
16
13
|
try {
|
|
17
14
|
while (true) {
|
|
18
15
|
await renderPromptHeader(ctx, promptDef);
|
|
19
|
-
const promptMarker = ctx.printerService.cyan(
|
|
20
|
-
ctx.config.inputPromptCharacters,
|
|
21
|
-
);
|
|
16
|
+
const promptMarker = ctx.printerService.cyan(ctx.config.inputPromptCharacters);
|
|
22
17
|
await ctx.terminal.write(promptMarker);
|
|
23
18
|
|
|
24
|
-
let buffer = promptDef.defaultOption
|
|
25
|
-
? String(promptDef.defaultOption.returnedValue)
|
|
26
|
-
: "";
|
|
19
|
+
let buffer = promptDef.defaultOption ? String(promptDef.defaultOption.returnedValue) : "";
|
|
27
20
|
if (buffer.length > 0) {
|
|
28
21
|
await ctx.terminal.write(buffer);
|
|
29
22
|
}
|
|
@@ -48,30 +41,24 @@ export default async function promptText(
|
|
|
48
41
|
}
|
|
49
42
|
} else if (keyEvent.key) {
|
|
50
43
|
buffer += keyEvent.key;
|
|
51
|
-
const isSecret =
|
|
52
|
-
promptDef.options[0]!.displayValue === "__SECRET__";
|
|
44
|
+
const isSecret =
|
|
45
|
+
promptDef.options.length > 0 && promptDef.options[0]!.displayValue === "__SECRET__";
|
|
53
46
|
await ctx.terminal.write(isSecret ? "*" : keyEvent.key);
|
|
54
47
|
}
|
|
55
48
|
}
|
|
56
49
|
|
|
57
50
|
if (buffer.length === 0 && !promptDef.defaultOption) {
|
|
58
|
-
await ctx.terminal.write(
|
|
59
|
-
ctx.printerService.red("Value required\n"),
|
|
60
|
-
);
|
|
51
|
+
await ctx.terminal.write(ctx.printerService.red("Value required\n"));
|
|
61
52
|
continue;
|
|
62
53
|
}
|
|
63
54
|
|
|
64
55
|
const value: ArgumentSingleValueType = buffer;
|
|
65
56
|
|
|
66
|
-
const validationOption = promptDef.options.length > 0
|
|
67
|
-
? promptDef.options[0]
|
|
68
|
-
: undefined;
|
|
57
|
+
const validationOption = promptDef.options.length > 0 ? promptDef.options[0] : undefined;
|
|
69
58
|
if (validationOption?.validate) {
|
|
70
59
|
const error = validationOption.validate(value);
|
|
71
60
|
if (error) {
|
|
72
|
-
await ctx.terminal.write(
|
|
73
|
-
`${ctx.printerService.red(error)}\n`,
|
|
74
|
-
);
|
|
61
|
+
await ctx.terminal.write(`${ctx.printerService.red(error)}\n`);
|
|
75
62
|
continue;
|
|
76
63
|
}
|
|
77
64
|
}
|
|
@@ -80,9 +67,7 @@ export default async function promptText(
|
|
|
80
67
|
const num = Number(value);
|
|
81
68
|
if (!isNaN(num) && num < validationOption.min) {
|
|
82
69
|
await ctx.terminal.write(
|
|
83
|
-
ctx.printerService.red(
|
|
84
|
-
`Value must be at least ${validationOption.min}\n`,
|
|
85
|
-
),
|
|
70
|
+
ctx.printerService.red(`Value must be at least ${validationOption.min}\n`),
|
|
86
71
|
);
|
|
87
72
|
continue;
|
|
88
73
|
}
|
|
@@ -91,9 +76,7 @@ export default async function promptText(
|
|
|
91
76
|
const num = Number(value);
|
|
92
77
|
if (!isNaN(num) && num > validationOption.max) {
|
|
93
78
|
await ctx.terminal.write(
|
|
94
|
-
ctx.printerService.red(
|
|
95
|
-
`Value must be at most ${validationOption.max}\n`,
|
|
96
|
-
),
|
|
79
|
+
ctx.printerService.red(`Value must be at most ${validationOption.max}\n`),
|
|
97
80
|
);
|
|
98
81
|
continue;
|
|
99
82
|
}
|
|
@@ -6,10 +6,7 @@ import {
|
|
|
6
6
|
import type { PromptContext } from "./PromptContext.ts";
|
|
7
7
|
import promptSingleSelect from "./promptSingleSelect.ts";
|
|
8
8
|
|
|
9
|
-
export default function promptToggle(
|
|
10
|
-
ctx: PromptContext,
|
|
11
|
-
promptDef: Prompt,
|
|
12
|
-
): Promise<PromptResult> {
|
|
9
|
+
export default function promptToggle(ctx: PromptContext, promptDef: Prompt): Promise<PromptResult> {
|
|
13
10
|
const trueFalse: Prompt = {
|
|
14
11
|
name: promptDef.name,
|
|
15
12
|
promptText: promptDef.promptText,
|
|
@@ -19,10 +16,13 @@ export default function promptToggle(
|
|
|
19
16
|
displayValue: "False",
|
|
20
17
|
returnedValue: false,
|
|
21
18
|
},
|
|
22
|
-
options:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
options:
|
|
20
|
+
promptDef.options.length > 0
|
|
21
|
+
? promptDef.options
|
|
22
|
+
: [
|
|
23
|
+
{ displayValue: "True", returnedValue: true },
|
|
24
|
+
{ displayValue: "False", returnedValue: false },
|
|
25
|
+
],
|
|
26
26
|
};
|
|
27
27
|
return promptSingleSelect(ctx, trueFalse);
|
|
28
28
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import process from "node:process";
|
|
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 DefaultShutdownService from "./DefaultShutdownService.ts";
|
|
7
4
|
import type ShutdownService from "../../api/service/core/ShutdownService.ts";
|
|
8
5
|
import { SHUTDOWN_SERVICE_ID } from "../../api/service/core/ShutdownService.ts";
|
|
@@ -18,9 +15,7 @@ export default class ShutdownServiceProvider implements ServiceProvider {
|
|
|
18
15
|
readonly #shutdownService: ShutdownService;
|
|
19
16
|
static #shutdownInProgress = false;
|
|
20
17
|
|
|
21
|
-
public constructor(
|
|
22
|
-
readonly servicePriority: number,
|
|
23
|
-
) {
|
|
18
|
+
public constructor(readonly servicePriority: number) {
|
|
24
19
|
this.#shutdownService = new DefaultShutdownService();
|
|
25
20
|
process.on("beforeExit", ShutdownServiceProvider.shutdown);
|
|
26
21
|
process.on("SIGINT", ShutdownServiceProvider.onInterrupt);
|
|
@@ -40,9 +35,7 @@ export default class ShutdownServiceProvider implements ServiceProvider {
|
|
|
40
35
|
|
|
41
36
|
static onInterrupt(): void {
|
|
42
37
|
shutdownState.interruptCount++;
|
|
43
|
-
if (
|
|
44
|
-
!shutdownState.longRunningMode || shutdownState.interruptCount >= 3
|
|
45
|
-
) {
|
|
38
|
+
if (!shutdownState.longRunningMode || shutdownState.interruptCount >= 3) {
|
|
46
39
|
ShutdownServiceProvider.shutdown().then(() => {
|
|
47
40
|
process.exit(130);
|
|
48
41
|
});
|
|
@@ -9,11 +9,7 @@ type Sheet = Record<string, (value: string) => string> | undefined;
|
|
|
9
9
|
interface Emphasize {
|
|
10
10
|
listLanguages(): ReadonlyArray<string>;
|
|
11
11
|
registered(name: string): boolean;
|
|
12
|
-
highlight(
|
|
13
|
-
name: string,
|
|
14
|
-
text: string,
|
|
15
|
-
sheet: Sheet,
|
|
16
|
-
): { value: string };
|
|
12
|
+
highlight(name: string, text: string, sheet: Sheet): { value: string };
|
|
17
13
|
register(name: string, syntax: HighlightSyntax): void;
|
|
18
14
|
}
|
|
19
15
|
|
|
@@ -21,30 +17,24 @@ interface Emphasize {
|
|
|
21
17
|
* Default implementation of {@link SyntaxHighlighterService} which has a syntax definition
|
|
22
18
|
* for JSON already registered.
|
|
23
19
|
*/
|
|
24
|
-
export default class DefaultSyntaxHighlighterService
|
|
25
|
-
implements SyntaxHighlighterService {
|
|
20
|
+
export default class DefaultSyntaxHighlighterService implements SyntaxHighlighterService {
|
|
26
21
|
colorEnabled = true;
|
|
27
|
-
colorFunction: (text: string, hexFormattedColor: string) => string = (text) =>
|
|
28
|
-
text;
|
|
22
|
+
colorFunction: (text: string, hexFormattedColor: string) => string = (text) => text;
|
|
29
23
|
|
|
30
|
-
emphasize: Emphasize;
|
|
24
|
+
#emphasize: Emphasize;
|
|
31
25
|
|
|
32
26
|
constructor() {
|
|
33
|
-
this
|
|
27
|
+
this.#emphasize = createEmphasize();
|
|
34
28
|
this.registerSyntax("json", json);
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
getRegisteredSyntaxes(): ReadonlyArray<string> {
|
|
38
|
-
return this
|
|
32
|
+
return this.#emphasize.listLanguages();
|
|
39
33
|
}
|
|
40
34
|
|
|
41
|
-
highlight(
|
|
42
|
-
text: string,
|
|
43
|
-
syntaxName: string,
|
|
44
|
-
colorScheme?: ColorScheme,
|
|
45
|
-
): string {
|
|
35
|
+
highlight(text: string, syntaxName: string, colorScheme?: ColorScheme): string {
|
|
46
36
|
const name = syntaxName.toLowerCase();
|
|
47
|
-
if (!this
|
|
37
|
+
if (!this.#emphasize.registered(name)) {
|
|
48
38
|
throw new Error(`Syntax name is not registered: ${name}`);
|
|
49
39
|
}
|
|
50
40
|
|
|
@@ -62,30 +52,27 @@ export default class DefaultSyntaxHighlighterService
|
|
|
62
52
|
if (!value) {
|
|
63
53
|
throw new Error(`Invalid color for entry: ${key}`);
|
|
64
54
|
}
|
|
65
|
-
if (
|
|
66
|
-
(value.length !== 7) ||
|
|
67
|
-
(!value.toLowerCase().startsWith("#"))
|
|
68
|
-
) {
|
|
55
|
+
if (value.length !== 7 || !value.toLowerCase().startsWith("#")) {
|
|
69
56
|
throw new Error(`Invalid color: ${value}`);
|
|
70
57
|
}
|
|
71
58
|
|
|
72
59
|
const colorValue = parseInt(value.slice(1), 16);
|
|
73
60
|
|
|
74
|
-
if (isNaN(colorValue) ||
|
|
61
|
+
if (isNaN(colorValue) || colorValue < 0 || colorValue > 0xffffff) {
|
|
75
62
|
throw new Error(`Invalid color: ${value}`);
|
|
76
63
|
}
|
|
77
64
|
sheet[key] = (text: string) => this.colorFunction(text, value);
|
|
78
65
|
}
|
|
79
66
|
}
|
|
80
67
|
|
|
81
|
-
return this
|
|
68
|
+
return this.#emphasize.highlight(name, text, sheet).value;
|
|
82
69
|
}
|
|
83
70
|
|
|
84
71
|
registerSyntax(syntaxName: string, syntaxDefinition: HighlightSyntax): void {
|
|
85
72
|
const name = syntaxName.toLowerCase();
|
|
86
|
-
if (this
|
|
73
|
+
if (this.#emphasize.registered(name)) {
|
|
87
74
|
throw new Error(`Syntax name already registered: ${name}`);
|
|
88
75
|
}
|
|
89
|
-
this
|
|
76
|
+
this.#emphasize.register(name, syntaxDefinition);
|
|
90
77
|
}
|
|
91
78
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
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 DefaultSyntaxHighlighterService from "./DefaultSyntaxHighlighterService.ts";
|
|
6
|
-
import {
|
|
7
|
-
SYNTAX_HIGHLIGHTER_SERVICE_ID,
|
|
8
|
-
} from "../../api/service/core/SyntaxHighlighterService.ts";
|
|
3
|
+
import { SYNTAX_HIGHLIGHTER_SERVICE_ID } from "../../api/service/core/SyntaxHighlighterService.ts";
|
|
9
4
|
import type Context from "../../api/Context.ts";
|
|
10
5
|
import type PrinterService from "../../api/service/core/PrinterService.ts";
|
|
11
6
|
import { PRINTER_SERVICE_ID } from "../../api/service/core/PrinterService.ts";
|
|
@@ -14,8 +9,7 @@ import type CLIConfig from "../../api/CLIConfig.ts";
|
|
|
14
9
|
/**
|
|
15
10
|
* Provides a {@link SyntaxHighlighterService}.
|
|
16
11
|
*/
|
|
17
|
-
export default class SyntaxHighlighterServiceProvider
|
|
18
|
-
implements ServiceProvider {
|
|
12
|
+
export default class SyntaxHighlighterServiceProvider implements ServiceProvider {
|
|
19
13
|
readonly serviceId: string = SYNTAX_HIGHLIGHTER_SERVICE_ID;
|
|
20
14
|
readonly #defaultSyntaxHighlighterService: DefaultSyntaxHighlighterService;
|
|
21
15
|
|
|
@@ -24,11 +18,8 @@ export default class SyntaxHighlighterServiceProvider
|
|
|
24
18
|
*
|
|
25
19
|
* @param servicePriority the priority of the service.
|
|
26
20
|
*/
|
|
27
|
-
public constructor(
|
|
28
|
-
|
|
29
|
-
) {
|
|
30
|
-
this.#defaultSyntaxHighlighterService =
|
|
31
|
-
new DefaultSyntaxHighlighterService();
|
|
21
|
+
public constructor(readonly servicePriority: number) {
|
|
22
|
+
this.#defaultSyntaxHighlighterService = new DefaultSyntaxHighlighterService();
|
|
32
23
|
}
|
|
33
24
|
|
|
34
25
|
public getServiceInfo(_cliConfig: CLIConfig): Promise<ServiceInfo> {
|
|
@@ -39,14 +30,10 @@ export default class SyntaxHighlighterServiceProvider
|
|
|
39
30
|
}
|
|
40
31
|
|
|
41
32
|
initService(context: Context): Promise<void> {
|
|
42
|
-
const printerService = context.getServiceById(
|
|
43
|
-
PRINTER_SERVICE_ID,
|
|
44
|
-
) as PrinterService;
|
|
33
|
+
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
45
34
|
|
|
46
|
-
this.#defaultSyntaxHighlighterService.colorEnabled =
|
|
47
|
-
|
|
48
|
-
this.#defaultSyntaxHighlighterService.colorFunction = printerService.color
|
|
49
|
-
.bind(printerService);
|
|
35
|
+
this.#defaultSyntaxHighlighterService.colorEnabled = printerService.colorEnabled;
|
|
36
|
+
this.#defaultSyntaxHighlighterService.colorFunction = printerService.color.bind(printerService);
|
|
50
37
|
|
|
51
38
|
return Promise.resolve(undefined);
|
|
52
39
|
}
|