intor-cli 0.0.14 → 0.0.15
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intor-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "The Intor CLI",
|
|
5
5
|
"author": "Yiming Liao",
|
|
6
6
|
"homepage": "https://github.com/yiming-liao/intor-cli#readme",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"intor": "src/cli/index.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"@clack/prompts": "^1.0.0",
|
|
42
43
|
"@intor/reader-json5": "^0.1.0",
|
|
43
44
|
"@intor/reader-md": "^0.1.4",
|
|
44
45
|
"@intor/reader-toml": "^0.1.0",
|
package/src/cli/index.ts
CHANGED
|
@@ -4,23 +4,34 @@ import { cac } from "cac";
|
|
|
4
4
|
import { registerCheckCommand } from "./commands/check";
|
|
5
5
|
import { registerGenerateCommand } from "./commands/generate";
|
|
6
6
|
import { registerValidateCommand } from "./commands/validate";
|
|
7
|
+
import { runInteractive } from "./interactive/run";
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
9
|
+
const VERSION = "0.1.10";
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
// argv = [node, script, ...args]
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
|
|
15
|
+
// -------------------------------------------------------------------
|
|
16
|
+
// Interactive mode bypasses CAC entirely
|
|
17
|
+
// -------------------------------------------------------------------
|
|
18
|
+
if (args.length === 0) {
|
|
19
|
+
await runInteractive();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// -------------------------------------------------------------------
|
|
24
|
+
// Command mode (original CAC behavior)
|
|
25
|
+
// -------------------------------------------------------------------
|
|
26
|
+
const cli = cac("intor");
|
|
27
|
+
|
|
28
|
+
registerGenerateCommand(cli);
|
|
29
|
+
registerCheckCommand(cli);
|
|
30
|
+
registerValidateCommand(cli);
|
|
31
|
+
|
|
32
|
+
cli.help();
|
|
33
|
+
cli.version(VERSION);
|
|
34
|
+
cli.parse(process.argv);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await main();
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { ExtraExt } from "../../core";
|
|
2
|
+
import type { GenerateOptions } from "../../features/generate/generate";
|
|
3
|
+
import {
|
|
4
|
+
text,
|
|
5
|
+
multiselect,
|
|
6
|
+
confirm,
|
|
7
|
+
isCancel,
|
|
8
|
+
select,
|
|
9
|
+
note,
|
|
10
|
+
} from "@clack/prompts";
|
|
11
|
+
|
|
12
|
+
export async function promptGenerate(): Promise<GenerateOptions | null> {
|
|
13
|
+
// ------------------------------------------------------------------
|
|
14
|
+
// Mode selection
|
|
15
|
+
// ------------------------------------------------------------------
|
|
16
|
+
const mode = await select({
|
|
17
|
+
message: "Generate mode?",
|
|
18
|
+
options: [
|
|
19
|
+
{ value: "default", label: "Default (recommended)" },
|
|
20
|
+
{ value: "custom", label: "Custom configuration" },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
if (isCancel(mode)) return null;
|
|
24
|
+
if (mode === "default") return {};
|
|
25
|
+
|
|
26
|
+
const options: GenerateOptions = {};
|
|
27
|
+
|
|
28
|
+
// ------------------------------------------------------------------
|
|
29
|
+
// messageFilePath
|
|
30
|
+
// ------------------------------------------------------------------
|
|
31
|
+
const useCustomPath = await confirm({
|
|
32
|
+
message: "Do you want to configure the messages path?",
|
|
33
|
+
initialValue: false,
|
|
34
|
+
});
|
|
35
|
+
if (isCancel(useCustomPath)) return null;
|
|
36
|
+
|
|
37
|
+
if (useCustomPath) {
|
|
38
|
+
const messageFilePath = await text({
|
|
39
|
+
message: "Where are your message files located?",
|
|
40
|
+
placeholder: "messages",
|
|
41
|
+
defaultValue: "messages",
|
|
42
|
+
});
|
|
43
|
+
if (isCancel(messageFilePath)) return null;
|
|
44
|
+
options.messageFilePath = messageFilePath || undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ------------------------------------------------------------------
|
|
48
|
+
// extra extensions
|
|
49
|
+
// ------------------------------------------------------------------
|
|
50
|
+
const enableExts = await confirm({
|
|
51
|
+
message: "Enable extra message file extensions?",
|
|
52
|
+
initialValue: false,
|
|
53
|
+
});
|
|
54
|
+
if (isCancel(enableExts)) return null;
|
|
55
|
+
|
|
56
|
+
if (enableExts) {
|
|
57
|
+
const exts = await multiselect<ExtraExt>({
|
|
58
|
+
message: "Select extra extensions to enable",
|
|
59
|
+
options: [
|
|
60
|
+
{ value: "md", label: "Markdown (.md)" },
|
|
61
|
+
{ value: "yaml", label: "YAML (.yaml/.yml)" },
|
|
62
|
+
{ value: "toml", label: "TOML (.toml)" },
|
|
63
|
+
{ value: "json5", label: "JSON5 (.json5)" },
|
|
64
|
+
],
|
|
65
|
+
required: false,
|
|
66
|
+
});
|
|
67
|
+
if (isCancel(exts)) return null;
|
|
68
|
+
options.exts = exts;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ------------------------------------------------------------------
|
|
72
|
+
// custom readers
|
|
73
|
+
// ------------------------------------------------------------------
|
|
74
|
+
const enableCustomReaders = await confirm({
|
|
75
|
+
message: "Do you want to configure custom readers?",
|
|
76
|
+
initialValue: false,
|
|
77
|
+
});
|
|
78
|
+
if (isCancel(enableCustomReaders)) return null;
|
|
79
|
+
|
|
80
|
+
if (enableCustomReaders) {
|
|
81
|
+
const mapping = await text({
|
|
82
|
+
message: "Enter custom reader mappings (ext=path, comma separated)",
|
|
83
|
+
placeholder: "md=./reader-md.ts, csv=./reader-csv.ts",
|
|
84
|
+
});
|
|
85
|
+
if (isCancel(mapping)) return null;
|
|
86
|
+
options.customReaders = Object.fromEntries(
|
|
87
|
+
mapping
|
|
88
|
+
.split(",")
|
|
89
|
+
.map((pair) => pair.trim())
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.map((pair) => pair.split("=") as [string, string]),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ------------------------------------------------------------------
|
|
96
|
+
// debug
|
|
97
|
+
// ------------------------------------------------------------------
|
|
98
|
+
const debug = await confirm({
|
|
99
|
+
message: "Enable debug mode?",
|
|
100
|
+
initialValue: false,
|
|
101
|
+
});
|
|
102
|
+
if (isCancel(debug)) return null;
|
|
103
|
+
if (debug) options.debug = true;
|
|
104
|
+
|
|
105
|
+
// ------------------------------------------------------------------
|
|
106
|
+
// summary
|
|
107
|
+
// ------------------------------------------------------------------
|
|
108
|
+
note(
|
|
109
|
+
`messages path: ${options.messageFilePath ?? "(default)"}\n` +
|
|
110
|
+
`exts: ${options.exts?.join(", ") ?? "(none)"}\n` +
|
|
111
|
+
`custom readers: ${
|
|
112
|
+
options.customReaders
|
|
113
|
+
? Object.keys(options.customReaders).join(", ")
|
|
114
|
+
: "(none)"
|
|
115
|
+
}\n` +
|
|
116
|
+
`debug: ${options.debug ? "on" : "off"}`,
|
|
117
|
+
"Generate options",
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return options;
|
|
121
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { ExtraExt } from "../../core";
|
|
2
|
+
import type { ValidateOptions } from "../../features/validate/validate";
|
|
3
|
+
import {
|
|
4
|
+
select,
|
|
5
|
+
confirm,
|
|
6
|
+
multiselect,
|
|
7
|
+
text,
|
|
8
|
+
isCancel,
|
|
9
|
+
note,
|
|
10
|
+
} from "@clack/prompts";
|
|
11
|
+
|
|
12
|
+
export async function promptValidate(): Promise<ValidateOptions | null> {
|
|
13
|
+
// ------------------------------------------------------------------
|
|
14
|
+
// Mode selection
|
|
15
|
+
// ------------------------------------------------------------------
|
|
16
|
+
const mode = await select({
|
|
17
|
+
message: "Validate mode?",
|
|
18
|
+
options: [
|
|
19
|
+
{ value: "default", label: "Default (recommended)" },
|
|
20
|
+
{ value: "custom", label: "Custom configuration" },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
if (isCancel(mode)) return null;
|
|
24
|
+
if (mode === "default") return {};
|
|
25
|
+
|
|
26
|
+
const options: ValidateOptions = {};
|
|
27
|
+
|
|
28
|
+
// ------------------------------------------------------------------
|
|
29
|
+
// extra extensions
|
|
30
|
+
// ------------------------------------------------------------------
|
|
31
|
+
const enableExts = await confirm({
|
|
32
|
+
message: "Enable extra message file extensions?",
|
|
33
|
+
initialValue: false,
|
|
34
|
+
});
|
|
35
|
+
if (isCancel(enableExts)) return null;
|
|
36
|
+
|
|
37
|
+
if (enableExts) {
|
|
38
|
+
const exts = await multiselect<ExtraExt>({
|
|
39
|
+
message: "Select extra extensions to enable",
|
|
40
|
+
options: [
|
|
41
|
+
{ value: "md", label: "Markdown (.md)" },
|
|
42
|
+
{ value: "yaml", label: "YAML (.yaml/.yml)" },
|
|
43
|
+
{ value: "toml", label: "TOML (.toml)" },
|
|
44
|
+
{ value: "json5", label: "JSON5 (.json5)" },
|
|
45
|
+
],
|
|
46
|
+
required: false,
|
|
47
|
+
});
|
|
48
|
+
if (isCancel(exts)) return null;
|
|
49
|
+
options.exts = exts;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ------------------------------------------------------------------
|
|
53
|
+
// custom readers
|
|
54
|
+
// ------------------------------------------------------------------
|
|
55
|
+
const enableCustomReaders = await confirm({
|
|
56
|
+
message: "Do you want to configure custom readers?",
|
|
57
|
+
initialValue: false,
|
|
58
|
+
});
|
|
59
|
+
if (isCancel(enableCustomReaders)) return null;
|
|
60
|
+
|
|
61
|
+
if (enableCustomReaders) {
|
|
62
|
+
const mapping = await text({
|
|
63
|
+
message: "Enter custom reader mappings (ext=path, comma separated)",
|
|
64
|
+
placeholder: "md=./reader-md.ts",
|
|
65
|
+
});
|
|
66
|
+
if (isCancel(mapping)) return null;
|
|
67
|
+
options.customReaders = Object.fromEntries(
|
|
68
|
+
mapping
|
|
69
|
+
.split(",")
|
|
70
|
+
.map((pair) => pair.trim())
|
|
71
|
+
.filter(Boolean)
|
|
72
|
+
.map((pair) => pair.split("=") as [string, string]),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ------------------------------------------------------------------
|
|
77
|
+
// debug
|
|
78
|
+
// ------------------------------------------------------------------
|
|
79
|
+
const debug = await confirm({
|
|
80
|
+
message: "Enable debug mode?",
|
|
81
|
+
initialValue: false,
|
|
82
|
+
});
|
|
83
|
+
if (isCancel(debug)) return null;
|
|
84
|
+
if (debug) options.debug = true;
|
|
85
|
+
|
|
86
|
+
// ------------------------------------------------------------------
|
|
87
|
+
// Summary
|
|
88
|
+
// ------------------------------------------------------------------
|
|
89
|
+
note(
|
|
90
|
+
`exts: ${options.exts?.join(", ") ?? "(none)"}\n` +
|
|
91
|
+
`custom readers: ${
|
|
92
|
+
options.customReaders
|
|
93
|
+
? Object.keys(options.customReaders).join(", ")
|
|
94
|
+
: "(none)"
|
|
95
|
+
}\n` +
|
|
96
|
+
`debug: ${options.debug ? "on" : "off"}`,
|
|
97
|
+
"Validate options",
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return options;
|
|
101
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* eslint-disable unicorn/no-process-exit */
|
|
2
|
+
import { intro, outro, select, isCancel } from "@clack/prompts";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { check, generate, validate } from "../../features";
|
|
5
|
+
import { promptGenerate } from "./prompt-generate";
|
|
6
|
+
import { promptValidate } from "./prompt-validate";
|
|
7
|
+
|
|
8
|
+
export function introBanner() {
|
|
9
|
+
intro(
|
|
10
|
+
pc.cyan(`
|
|
11
|
+
▄▄ ▄▄ ▄▄ ▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄
|
|
12
|
+
██ ███▄██ ██ ██▀██ ██▄█▄
|
|
13
|
+
██ ██ ▀██ ██ ▀███▀ ██ ██
|
|
14
|
+
`),
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function runInteractive() {
|
|
19
|
+
introBanner();
|
|
20
|
+
|
|
21
|
+
const action = await select({
|
|
22
|
+
message: "Select an action",
|
|
23
|
+
options: [
|
|
24
|
+
{ value: "check", label: "Check translation usages" },
|
|
25
|
+
{ value: "generate", label: "Generate types & schemas" },
|
|
26
|
+
{ value: "validate", label: "Validate messages" },
|
|
27
|
+
{ value: "exit", label: "Exit" },
|
|
28
|
+
],
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (isCancel(action) || action === "exit") {
|
|
32
|
+
outro("Exited");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
switch (action) {
|
|
37
|
+
case "check": {
|
|
38
|
+
await check();
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
case "generate": {
|
|
43
|
+
const options = await promptGenerate();
|
|
44
|
+
if (!options) {
|
|
45
|
+
outro(pc.dim("Cancelled"));
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
await generate(options);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
case "validate": {
|
|
53
|
+
const options = await promptValidate();
|
|
54
|
+
if (!options) {
|
|
55
|
+
outro("Cancelled");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
await validate(options);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
outro(pc.green("Completed"));
|
|
64
|
+
}
|