product-discovery-cli 0.0.6 → 0.0.7
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.md +236 -236
- package/package.json +42 -42
- package/src/application/RunDiscoveryFlow.js +87 -86
- package/src/config/cliOptions.js +32 -32
- package/src/domain/DiscoverySession.js +15 -15
- package/src/domain/PathNaming.js +22 -22
- package/src/index.js +28 -28
- package/src/infrastructure/ConfigLoader.js +24 -24
- package/src/infrastructure/ConsolePresenter.js +79 -79
- package/src/infrastructure/JsonFileStorage.js +63 -63
- package/src/infrastructure/ProductDiscoveryApi.js +26 -26
- package/src/infrastructure/PromptService.js +31 -31
- package/src/infrastructure/i18n.js +101 -101
- package/src/presentation/CliController.js +45 -45
|
@@ -1,86 +1,87 @@
|
|
|
1
|
-
const { DiscoverySession } = require("../domain/DiscoverySession");
|
|
2
|
-
|
|
3
|
-
class RunDiscoveryFlow {
|
|
4
|
-
constructor({ prompt, apiClient, storage, presenter }) {
|
|
5
|
-
this.prompt = prompt;
|
|
6
|
-
this.apiClient = apiClient;
|
|
7
|
-
this.storage = storage;
|
|
8
|
-
this.presenter = presenter;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async execute({ apiUrl, lang, saveDefaults, i18n }) {
|
|
12
|
-
this.i18n = i18n;
|
|
13
|
-
this.presenter.printHeader();
|
|
14
|
-
|
|
15
|
-
let continueOuter = true;
|
|
16
|
-
|
|
17
|
-
while (continueOuter) {
|
|
18
|
-
const session = new DiscoverySession();
|
|
19
|
-
let shouldImprove = true;
|
|
20
|
-
|
|
21
|
-
while (shouldImprove) {
|
|
22
|
-
this.presenter.info(this.i18n.t("askIdea"));
|
|
23
|
-
const idea = await this.prompt.askInput(this.i18n.t("describeIdea"), {
|
|
24
|
-
required: true,
|
|
25
|
-
requiredMessage: this.i18n.t("required")
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const attemptText = session.addIdea(idea);
|
|
29
|
-
|
|
30
|
-
const spinner = this.presenter.spinner(this.i18n.t("callingApi"));
|
|
31
|
-
let result;
|
|
32
|
-
try {
|
|
33
|
-
result = await this.apiClient.runDiscovery(attemptText, apiUrl, lang);
|
|
34
|
-
spinner.succeed(this.i18n.t("discoveryCompleted"));
|
|
35
|
-
} catch (error) {
|
|
36
|
-
spinner.fail(this.i18n.t("discoveryFailed"));
|
|
37
|
-
this.presenter.error(error.message);
|
|
38
|
-
const retry = await this.prompt.askYesNo(this.i18n.t("askRetry"));
|
|
39
|
-
if (!retry) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
1
|
+
const { DiscoverySession } = require("../domain/DiscoverySession");
|
|
2
|
+
|
|
3
|
+
class RunDiscoveryFlow {
|
|
4
|
+
constructor({ prompt, apiClient, storage, presenter }) {
|
|
5
|
+
this.prompt = prompt;
|
|
6
|
+
this.apiClient = apiClient;
|
|
7
|
+
this.storage = storage;
|
|
8
|
+
this.presenter = presenter;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async execute({ apiUrl, lang, saveDefaults, i18n }) {
|
|
12
|
+
this.i18n = i18n;
|
|
13
|
+
this.presenter.printHeader();
|
|
14
|
+
|
|
15
|
+
let continueOuter = true;
|
|
16
|
+
|
|
17
|
+
while (continueOuter) {
|
|
18
|
+
const session = new DiscoverySession();
|
|
19
|
+
let shouldImprove = true;
|
|
20
|
+
|
|
21
|
+
while (shouldImprove) {
|
|
22
|
+
this.presenter.info(this.i18n.t("askIdea"));
|
|
23
|
+
const idea = await this.prompt.askInput(this.i18n.t("describeIdea"), {
|
|
24
|
+
required: true,
|
|
25
|
+
requiredMessage: this.i18n.t("required")
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const attemptText = session.addIdea(idea);
|
|
29
|
+
|
|
30
|
+
const spinner = this.presenter.spinner(this.i18n.t("callingApi"));
|
|
31
|
+
let result;
|
|
32
|
+
try {
|
|
33
|
+
result = await this.apiClient.runDiscovery(attemptText, apiUrl, lang);
|
|
34
|
+
spinner.succeed(this.i18n.t("discoveryCompleted"));
|
|
35
|
+
} catch (error) {
|
|
36
|
+
spinner.fail(this.i18n.t("discoveryFailed"));
|
|
37
|
+
this.presenter.error(error.message);
|
|
38
|
+
const retry = await this.prompt.askYesNo(this.i18n.t("askRetry"));
|
|
39
|
+
if (!retry) {
|
|
40
|
+
this.presenter.goodbye();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.presenter.json(result);
|
|
47
|
+
|
|
48
|
+
if (saveDefaults.autoSave === false) {
|
|
49
|
+
const improve = await this.prompt.askYesNo(this.i18n.t("askImprove"));
|
|
50
|
+
if (!improve) {
|
|
51
|
+
shouldImprove = false;
|
|
52
|
+
continueOuter = false;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const saveInfo = await this.storage.saveJson(result, saveDefaults);
|
|
59
|
+
if (saveInfo.saved) {
|
|
60
|
+
this.presenter.success(`${this.i18n.t("savedTo")} ${saveInfo.fullPath}`);
|
|
61
|
+
shouldImprove = false;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const improve = await this.prompt.askYesNo(this.i18n.t("askImprove"));
|
|
66
|
+
if (!improve) {
|
|
67
|
+
shouldImprove = false;
|
|
68
|
+
continueOuter = false;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!continueOuter) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const another = await this.prompt.askYesNo(this.i18n.t("askAnother"));
|
|
78
|
+
if (!another) {
|
|
79
|
+
continueOuter = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.presenter.goodbye();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { RunDiscoveryFlow };
|
package/src/config/cliOptions.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
const { Command } = require("commander");
|
|
2
|
-
const { getTranslator } = require("../infrastructure/i18n");
|
|
3
|
-
|
|
4
|
-
function buildOptions(defaultApiUrl) {
|
|
5
|
-
// First pass: get lang to determine i18n
|
|
6
|
-
const preProgram = new Command();
|
|
7
|
-
preProgram
|
|
8
|
-
.allowUnknownOption()
|
|
9
|
-
.option("-l, --lang <language>", "Language code (pt-br, en-us)", "pt-br");
|
|
10
|
-
|
|
11
|
-
preProgram.parse(process.argv);
|
|
12
|
-
const preOpts = preProgram.opts();
|
|
13
|
-
const i18n = getTranslator(preOpts.lang || "pt-br");
|
|
14
|
-
|
|
15
|
-
// Second pass: full options with translations
|
|
16
|
-
const program = new Command();
|
|
17
|
-
program
|
|
18
|
-
.name("product-discovery")
|
|
19
|
-
.description(i18n.t("cliDescription"))
|
|
20
|
-
.option("-u, --api-url <url>", i18n.t("optApiUrl"), defaultApiUrl)
|
|
21
|
-
.option("-l, --lang <language>", i18n.t("optLang"), "pt-br")
|
|
22
|
-
.option("-c, --config <path>", i18n.t("optConfig"))
|
|
23
|
-
.option("-s, --save", i18n.t("optSave"))
|
|
24
|
-
.option("-o, --output <dir>", i18n.t("optOutput"))
|
|
25
|
-
.option("-f, --file <name>", i18n.t("optFile"))
|
|
26
|
-
.option("--no-save", i18n.t("optNoSave"));
|
|
27
|
-
|
|
28
|
-
program.parse(process.argv);
|
|
29
|
-
return program.opts();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
module.exports = { buildOptions };
|
|
1
|
+
const { Command } = require("commander");
|
|
2
|
+
const { getTranslator } = require("../infrastructure/i18n");
|
|
3
|
+
|
|
4
|
+
function buildOptions(defaultApiUrl) {
|
|
5
|
+
// First pass: get lang to determine i18n
|
|
6
|
+
const preProgram = new Command();
|
|
7
|
+
preProgram
|
|
8
|
+
.allowUnknownOption()
|
|
9
|
+
.option("-l, --lang <language>", "Language code (pt-br, en-us)", "pt-br");
|
|
10
|
+
|
|
11
|
+
preProgram.parse(process.argv);
|
|
12
|
+
const preOpts = preProgram.opts();
|
|
13
|
+
const i18n = getTranslator(preOpts.lang || "pt-br");
|
|
14
|
+
|
|
15
|
+
// Second pass: full options with translations
|
|
16
|
+
const program = new Command();
|
|
17
|
+
program
|
|
18
|
+
.name("product-discovery")
|
|
19
|
+
.description(i18n.t("cliDescription"))
|
|
20
|
+
.option("-u, --api-url <url>", i18n.t("optApiUrl"), defaultApiUrl)
|
|
21
|
+
.option("-l, --lang <language>", i18n.t("optLang"), "pt-br")
|
|
22
|
+
.option("-c, --config <path>", i18n.t("optConfig"))
|
|
23
|
+
.option("-s, --save", i18n.t("optSave"))
|
|
24
|
+
.option("-o, --output <dir>", i18n.t("optOutput"))
|
|
25
|
+
.option("-f, --file <name>", i18n.t("optFile"))
|
|
26
|
+
.option("--no-save", i18n.t("optNoSave"));
|
|
27
|
+
|
|
28
|
+
program.parse(process.argv);
|
|
29
|
+
return program.opts();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { buildOptions };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
class DiscoverySession {
|
|
2
|
-
constructor() {
|
|
3
|
-
this.baseIdea = "";
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
addIdea(text) {
|
|
7
|
-
if (!this.baseIdea) {
|
|
8
|
-
this.baseIdea = text;
|
|
9
|
-
return this.baseIdea;
|
|
10
|
-
}
|
|
11
|
-
return `${this.baseIdea}\n\nAdditional details: ${text}`;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports = { DiscoverySession };
|
|
1
|
+
class DiscoverySession {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.baseIdea = "";
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
addIdea(text) {
|
|
7
|
+
if (!this.baseIdea) {
|
|
8
|
+
this.baseIdea = text;
|
|
9
|
+
return this.baseIdea;
|
|
10
|
+
}
|
|
11
|
+
return `${this.baseIdea}\n\nAdditional details: ${text}`;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = { DiscoverySession };
|
package/src/domain/PathNaming.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
function sanitizeForFolderName(value) {
|
|
2
|
-
return (
|
|
3
|
-
value
|
|
4
|
-
.toLowerCase()
|
|
5
|
-
.replace(/[^a-z0-9]+/gi, "-")
|
|
6
|
-
.replace(/^-+|-+$/g, "")
|
|
7
|
-
.slice(0, 60) || "product"
|
|
8
|
-
);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function timestampForPath() {
|
|
12
|
-
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function ensureJsonExtension(filename) {
|
|
16
|
-
if (!filename.toLowerCase().endsWith(".json")) {
|
|
17
|
-
return `${filename}.json`;
|
|
18
|
-
}
|
|
19
|
-
return filename;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
module.exports = { sanitizeForFolderName, timestampForPath, ensureJsonExtension };
|
|
1
|
+
function sanitizeForFolderName(value) {
|
|
2
|
+
return (
|
|
3
|
+
value
|
|
4
|
+
.toLowerCase()
|
|
5
|
+
.replace(/[^a-z0-9]+/gi, "-")
|
|
6
|
+
.replace(/^-+|-+$/g, "")
|
|
7
|
+
.slice(0, 60) || "product"
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function timestampForPath() {
|
|
12
|
+
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function ensureJsonExtension(filename) {
|
|
16
|
+
if (!filename.toLowerCase().endsWith(".json")) {
|
|
17
|
+
return `${filename}.json`;
|
|
18
|
+
}
|
|
19
|
+
return filename;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = { sanitizeForFolderName, timestampForPath, ensureJsonExtension };
|
package/src/index.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { CliController } = require("./presentation/CliController");
|
|
4
|
-
const { PromptService } = require("./infrastructure/PromptService");
|
|
5
|
-
const { ConsolePresenter } = require("./infrastructure/ConsolePresenter");
|
|
6
|
-
const { ProductDiscoveryApi } = require("./infrastructure/ProductDiscoveryApi");
|
|
7
|
-
const { JsonFileStorage } = require("./infrastructure/JsonFileStorage");
|
|
8
|
-
const { RunDiscoveryFlow } = require("./application/RunDiscoveryFlow");
|
|
9
|
-
|
|
10
|
-
const DEFAULT_API_URL = process.env.API_URL || "http://localhost:3000/api/v1/discovery";
|
|
11
|
-
|
|
12
|
-
const prompt = new PromptService();
|
|
13
|
-
const presenter = new ConsolePresenter(null);
|
|
14
|
-
const apiClient = new ProductDiscoveryApi();
|
|
15
|
-
const storage = new JsonFileStorage();
|
|
16
|
-
const useCase = new RunDiscoveryFlow({ prompt, apiClient, storage, presenter });
|
|
17
|
-
|
|
18
|
-
const controller = new CliController({
|
|
19
|
-
defaultApiUrl: DEFAULT_API_URL,
|
|
20
|
-
prompt,
|
|
21
|
-
presenter,
|
|
22
|
-
apiClient,
|
|
23
|
-
storage,
|
|
24
|
-
useCase
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
controller.start().catch((error) => {
|
|
28
|
-
presenter.error(`Unexpected error: ${error.message}`);
|
|
29
|
-
});
|
|
2
|
+
|
|
3
|
+
const { CliController } = require("./presentation/CliController");
|
|
4
|
+
const { PromptService } = require("./infrastructure/PromptService");
|
|
5
|
+
const { ConsolePresenter } = require("./infrastructure/ConsolePresenter");
|
|
6
|
+
const { ProductDiscoveryApi } = require("./infrastructure/ProductDiscoveryApi");
|
|
7
|
+
const { JsonFileStorage } = require("./infrastructure/JsonFileStorage");
|
|
8
|
+
const { RunDiscoveryFlow } = require("./application/RunDiscoveryFlow");
|
|
9
|
+
|
|
10
|
+
const DEFAULT_API_URL = process.env.API_URL || "http://localhost:3000/api/v1/discovery";
|
|
11
|
+
|
|
12
|
+
const prompt = new PromptService();
|
|
13
|
+
const presenter = new ConsolePresenter(null);
|
|
14
|
+
const apiClient = new ProductDiscoveryApi();
|
|
15
|
+
const storage = new JsonFileStorage();
|
|
16
|
+
const useCase = new RunDiscoveryFlow({ prompt, apiClient, storage, presenter });
|
|
17
|
+
|
|
18
|
+
const controller = new CliController({
|
|
19
|
+
defaultApiUrl: DEFAULT_API_URL,
|
|
20
|
+
prompt,
|
|
21
|
+
presenter,
|
|
22
|
+
apiClient,
|
|
23
|
+
storage,
|
|
24
|
+
useCase
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
controller.start().catch((error) => {
|
|
28
|
+
presenter.error(`Unexpected error: ${error.message}`);
|
|
29
|
+
});
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
const fs = require("node:fs");
|
|
2
|
-
const path = require("node:path");
|
|
3
|
-
|
|
4
|
-
class ConfigLoader {
|
|
5
|
-
load(configPath) {
|
|
6
|
-
if (!configPath) return {};
|
|
7
|
-
const absolutePath = path.isAbsolute(configPath)
|
|
8
|
-
? configPath
|
|
9
|
-
: path.join(process.cwd(), configPath);
|
|
10
|
-
|
|
11
|
-
if (!fs.existsSync(absolutePath)) {
|
|
12
|
-
throw new Error(`Config file not found: ${absolutePath}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const raw = fs.readFileSync(absolutePath, "utf-8");
|
|
16
|
-
try {
|
|
17
|
-
return JSON.parse(raw);
|
|
18
|
-
} catch (error) {
|
|
19
|
-
throw new Error(`Invalid JSON in config file: ${error.message}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
module.exports = { ConfigLoader };
|
|
1
|
+
const fs = require("node:fs");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
|
|
4
|
+
class ConfigLoader {
|
|
5
|
+
load(configPath) {
|
|
6
|
+
if (!configPath) return {};
|
|
7
|
+
const absolutePath = path.isAbsolute(configPath)
|
|
8
|
+
? configPath
|
|
9
|
+
: path.join(process.cwd(), configPath);
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(absolutePath)) {
|
|
12
|
+
throw new Error(`Config file not found: ${absolutePath}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const raw = fs.readFileSync(absolutePath, "utf-8");
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(raw);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
throw new Error(`Invalid JSON in config file: ${error.message}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = { ConfigLoader };
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
const { stdout: output } = require("node:process");
|
|
2
|
-
const chalk = require("chalk");
|
|
3
|
-
const boxen = require("boxen");
|
|
4
|
-
const ora = require("ora");
|
|
5
|
-
const pkg = require("../../package.json");
|
|
6
|
-
|
|
7
|
-
class ConsolePresenter {
|
|
8
|
-
constructor(i18n = null) {
|
|
9
|
-
this.i18n = i18n;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
printHeader() {
|
|
13
|
-
if (!this.i18n) return;
|
|
14
|
-
const logo = chalk.cyan(
|
|
15
|
-
String.raw`
|
|
16
|
-
____ _ _ ____ _
|
|
17
|
-
| _ \ _ __ ___ __| |_ _ ___| |_ | _ \(_)___ ___ _____ _____ _ __
|
|
18
|
-
| |_) | '__/ _ \ / _ | | | |/ __| __| | | | | / __|/ __/ _ \ \ / / _ \ '__|
|
|
19
|
-
| __/| | | (_) | (_| | |_| | (__| |_ | |_| | \__ \ (_| (_) \ V / __/ |
|
|
20
|
-
|_| |_| \___/ \__,_|\__,_|\___|\__| |____/|_|___/\___\___/ \_/ \___|_|
|
|
21
|
-
`
|
|
22
|
-
);
|
|
23
|
-
const title = chalk.bold.cyan(this.i18n.t("headerTitle"));
|
|
24
|
-
const subtitle = chalk.gray(this.i18n.t("headerSubtitle"));
|
|
25
|
-
const author = chalk.gray(`${this.i18n.t("headerAuthor")}: ${pkg.author}`);
|
|
26
|
-
const version = chalk.gray(`${this.i18n.t("headerVersion")}: ${pkg.version}`);
|
|
27
|
-
const license = chalk.gray(`${this.i18n.t("headerLicense")}: ${pkg.license}`);
|
|
28
|
-
const banner = `${logo}\n${title}\n${subtitle}\n\n${author}\n${version}\n${license}`;
|
|
29
|
-
output.write(
|
|
30
|
-
boxen(banner, {
|
|
31
|
-
padding: 1,
|
|
32
|
-
margin: 1,
|
|
33
|
-
borderStyle: "round",
|
|
34
|
-
borderColor: "cyan"
|
|
35
|
-
})
|
|
36
|
-
);
|
|
37
|
-
output.write("\n");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
info(message) {
|
|
41
|
-
output.write(`${chalk.bold(message)}\n`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
success(message) {
|
|
45
|
-
output.write(`${chalk.green(message)}\n\n`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
error(message) {
|
|
49
|
-
output.write(`${chalk.red(this.i18n.t("error"))} ${message}\n\n`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
json(payload) {
|
|
53
|
-
output.write(`\n${chalk.bold(this.i18n.t("generatedDiscovery"))}\n\n`);
|
|
54
|
-
output.write(`${chalk.gray(JSON.stringify(payload, null, 2))}\n\n`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
spinner(text) {
|
|
58
|
-
return ora(text).start();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
goodbye() {
|
|
62
|
-
if (!this.i18n) return;
|
|
63
|
-
output.write("\n");
|
|
64
|
-
output.write(
|
|
65
|
-
boxen(
|
|
66
|
-
`${chalk.bold.cyan(this.i18n.t("thankYou"))}\n${chalk.gray(this.i18n.t("closeConsole"))}`,
|
|
67
|
-
{
|
|
68
|
-
padding: 1,
|
|
69
|
-
margin: 1,
|
|
70
|
-
borderStyle: "round",
|
|
71
|
-
borderColor: "cyan"
|
|
72
|
-
}
|
|
73
|
-
)
|
|
74
|
-
);
|
|
75
|
-
output.write("\n");
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
module.exports = { ConsolePresenter };
|
|
1
|
+
const { stdout: output } = require("node:process");
|
|
2
|
+
const chalk = require("chalk");
|
|
3
|
+
const boxen = require("boxen");
|
|
4
|
+
const ora = require("ora");
|
|
5
|
+
const pkg = require("../../package.json");
|
|
6
|
+
|
|
7
|
+
class ConsolePresenter {
|
|
8
|
+
constructor(i18n = null) {
|
|
9
|
+
this.i18n = i18n;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
printHeader() {
|
|
13
|
+
if (!this.i18n) return;
|
|
14
|
+
const logo = chalk.cyan(
|
|
15
|
+
String.raw`
|
|
16
|
+
____ _ _ ____ _
|
|
17
|
+
| _ \ _ __ ___ __| |_ _ ___| |_ | _ \(_)___ ___ _____ _____ _ __
|
|
18
|
+
| |_) | '__/ _ \ / _ | | | |/ __| __| | | | | / __|/ __/ _ \ \ / / _ \ '__|
|
|
19
|
+
| __/| | | (_) | (_| | |_| | (__| |_ | |_| | \__ \ (_| (_) \ V / __/ |
|
|
20
|
+
|_| |_| \___/ \__,_|\__,_|\___|\__| |____/|_|___/\___\___/ \_/ \___|_|
|
|
21
|
+
`
|
|
22
|
+
);
|
|
23
|
+
const title = chalk.bold.cyan(this.i18n.t("headerTitle"));
|
|
24
|
+
const subtitle = chalk.gray(this.i18n.t("headerSubtitle"));
|
|
25
|
+
const author = chalk.gray(`${this.i18n.t("headerAuthor")}: ${pkg.author}`);
|
|
26
|
+
const version = chalk.gray(`${this.i18n.t("headerVersion")}: ${pkg.version}`);
|
|
27
|
+
const license = chalk.gray(`${this.i18n.t("headerLicense")}: ${pkg.license}`);
|
|
28
|
+
const banner = `${logo}\n${title}\n${subtitle}\n\n${author}\n${version}\n${license}`;
|
|
29
|
+
output.write(
|
|
30
|
+
boxen(banner, {
|
|
31
|
+
padding: 1,
|
|
32
|
+
margin: 1,
|
|
33
|
+
borderStyle: "round",
|
|
34
|
+
borderColor: "cyan"
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
output.write("\n");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
info(message) {
|
|
41
|
+
output.write(`${chalk.bold(message)}\n`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
success(message) {
|
|
45
|
+
output.write(`${chalk.green(message)}\n\n`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
error(message) {
|
|
49
|
+
output.write(`${chalk.red(this.i18n.t("error"))} ${message}\n\n`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
json(payload) {
|
|
53
|
+
output.write(`\n${chalk.bold(this.i18n.t("generatedDiscovery"))}\n\n`);
|
|
54
|
+
output.write(`${chalk.gray(JSON.stringify(payload, null, 2))}\n\n`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
spinner(text) {
|
|
58
|
+
return ora(text).start();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
goodbye() {
|
|
62
|
+
if (!this.i18n) return;
|
|
63
|
+
output.write("\n");
|
|
64
|
+
output.write(
|
|
65
|
+
boxen(
|
|
66
|
+
`${chalk.bold.cyan(this.i18n.t("thankYou"))}\n${chalk.gray(this.i18n.t("closeConsole"))}`,
|
|
67
|
+
{
|
|
68
|
+
padding: 1,
|
|
69
|
+
margin: 1,
|
|
70
|
+
borderStyle: "round",
|
|
71
|
+
borderColor: "cyan"
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
output.write("\n");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = { ConsolePresenter };
|