xw-devtool-cli 1.0.16 → 1.0.18
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 +12 -0
- package/README_EN.md +225 -0
- package/package.json +4 -2
- package/src/commands/url.js +7 -6
- package/src/i18n.js +46 -0
- package/src/index.js +98 -40
- package/src/locales/en.js +46 -0
- package/src/locales/zh.js +46 -0
- package/src/utils/config.js +29 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# xw-devtool-cli
|
|
2
2
|
|
|
3
|
+
**中文** | [English Documentation](./README_EN.md)
|
|
4
|
+
|
|
3
5
|
一个基于 Node.js 的开发者命令行工具箱,旨在提供开箱即用的常用开发工具,帮助开发者快速处理日常任务。
|
|
4
6
|
|
|
5
7
|
主要功能包括:Base64 编解码、图片格式转换、图片与 Base64 互转、Mock 数据生成、时间戳/日期格式化、时间计算、URL 编解码、UUID 生成、汉字转拼音、颜色转换、变量格式转换、哈希计算、二维码生成、特殊符号大全、Markdown 语法工具、VS Code 代码段生成等。所有结果均自动复制到剪贴板,极大提升开发效率。
|
|
@@ -38,6 +40,9 @@
|
|
|
38
40
|
- 结果自动复制到剪贴板。
|
|
39
41
|
- 支持从剪贴板自动读取输入(部分工具支持直接回车读取)。
|
|
40
42
|
- 支持将大文本结果保存为文件。
|
|
43
|
+
- **多语言支持 (i18n)**:
|
|
44
|
+
- 支持 **中文** 和 **English**。
|
|
45
|
+
- 可通过菜单中的 `Settings` 切换,或使用命令行参数:`xw-devtool --zh` / `xw-devtool --en`。
|
|
41
46
|
|
|
42
47
|
## 📦 安装
|
|
43
48
|
|
|
@@ -59,6 +64,12 @@ npx xw-devtool-cli@latest
|
|
|
59
64
|
xw-devtool
|
|
60
65
|
```
|
|
61
66
|
|
|
67
|
+
或者指定语言启动:
|
|
68
|
+
```bash
|
|
69
|
+
xw-devtool --zh # 中文启动
|
|
70
|
+
xw-devtool --en # 英文启动 (Start in English)
|
|
71
|
+
```
|
|
72
|
+
|
|
62
73
|
启动后将显示交互式菜单,通过键盘输入对应的数字或字母选择功能:
|
|
63
74
|
|
|
64
75
|
```text
|
|
@@ -86,6 +97,7 @@ i. Special Characters (Symbols)
|
|
|
86
97
|
j. Emoji Picker
|
|
87
98
|
k. Markdown Snippets
|
|
88
99
|
l. VS Code Snippet Generator
|
|
100
|
+
s. Settings (Language)
|
|
89
101
|
0. Exit
|
|
90
102
|
=================================
|
|
91
103
|
```
|
package/README_EN.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# xw-devtool-cli
|
|
2
|
+
|
|
3
|
+
[中文文档](./README.md) | **English**
|
|
4
|
+
|
|
5
|
+
A Node.js-based developer command-line toolbox designed to provide out-of-the-box common development tools to help developers handle daily tasks quickly.
|
|
6
|
+
|
|
7
|
+
Key features include: Base64 encoding/decoding, image format conversion, image <-> Base64, Mock data generation, timestamp/date formatting, time calculation, URL encoding/decoding, UUID generation, Chinese pinyin conversion, color conversion, variable format conversion, hash calculation, QR code generation, special symbols, Markdown snippets, VS Code snippet generation, etc. All results are automatically copied to the clipboard, greatly improving development efficiency.
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
- **Base64 Tools**: Convert strings to/from Base64, supports reading from clipboard, file, or manual input.
|
|
12
|
+
- **Image Tools**:
|
|
13
|
+
- **Format Conversion**: Convert between PNG, JPG, WebP, with adjustable compression quality.
|
|
14
|
+
- **Image ↔ Base64**: Convert images to Base64 strings and vice versa.
|
|
15
|
+
- **Placeholder Image**: Quickly generate placeholder images with custom size, color, and text.
|
|
16
|
+
- **Mock Data**:
|
|
17
|
+
- Generate: Lorem Ipsum, Chinese characters, ID cards, Emails, URLs, Order IDs, Phone numbers.
|
|
18
|
+
- Supports batch generation.
|
|
19
|
+
- **Time Tools**:
|
|
20
|
+
- **Formatting**: Timestamp/Date string -> `YYYY-MM-DD HH:mm:ss`.
|
|
21
|
+
- **Timestamp**: Quickly get current millisecond timestamp.
|
|
22
|
+
- **Calculation**: Calculate date differences or offsets (Add/Subtract).
|
|
23
|
+
- **Dev Tools**:
|
|
24
|
+
- **URL Encode/Decode**
|
|
25
|
+
- **Unicode Encode/Decode**: Text <-> Unicode escape sequences (\uXXXX).
|
|
26
|
+
- **UUID**: Generate UUID v4.
|
|
27
|
+
- **Pinyin**: Convert Chinese characters to Pinyin (without tone).
|
|
28
|
+
- **Color Converter**: Hex <-> RGB.
|
|
29
|
+
- **Variable Format**: CamelCase, PascalCase, SnakeCase, KebabCase, ConstantCase.
|
|
30
|
+
- **Hash Calculator**: MD5, SHA1, SHA256, SHA512, SM3.
|
|
31
|
+
- **QR Code**: Display QR codes in terminal, save as PNG.
|
|
32
|
+
- **Special Symbols**: 170+ symbols, arrows, math symbols, etc.
|
|
33
|
+
- **Emoji Picker**: Browse and copy emojis.
|
|
34
|
+
- **HTML Entity**: Encode/Decode HTML entities.
|
|
35
|
+
- **Markdown Snippets**: Common Markdown templates.
|
|
36
|
+
- **VS Code Snippets**: Generate VS Code snippet JSON from code.
|
|
37
|
+
- **Convenience**:
|
|
38
|
+
- File selection dialog (Windows).
|
|
39
|
+
- Auto-copy results to clipboard.
|
|
40
|
+
- Auto-read from clipboard.
|
|
41
|
+
- Save large results to file.
|
|
42
|
+
- **Internationalization (i18n)**:
|
|
43
|
+
- Support **English** and **Chinese**.
|
|
44
|
+
- Switch via **Settings** in the menu or use CLI flags: `xw-devtool --en` / `xw-devtool --zh`.
|
|
45
|
+
|
|
46
|
+
## 📦 Installation
|
|
47
|
+
|
|
48
|
+
### Global Installation (Recommended)
|
|
49
|
+
```bash
|
|
50
|
+
npm install -g xw-devtool-cli
|
|
51
|
+
```
|
|
52
|
+
After installation, use `xw-devtool` or `xw-dev` command.
|
|
53
|
+
|
|
54
|
+
### Run via npx
|
|
55
|
+
```bash
|
|
56
|
+
npx xw-devtool-cli@latest
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 🚀 Quick Start
|
|
60
|
+
|
|
61
|
+
Run in terminal:
|
|
62
|
+
```bash
|
|
63
|
+
xw-devtool
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or specify language directly:
|
|
67
|
+
```bash
|
|
68
|
+
xw-devtool --en # Start in English
|
|
69
|
+
xw-devtool --zh # Start in Chinese
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The interactive menu will appear:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
=================================
|
|
76
|
+
xw-devtool-cli Menu
|
|
77
|
+
=================================
|
|
78
|
+
1. Image <-> Base64
|
|
79
|
+
2. Image Format Convert
|
|
80
|
+
3. Placeholder Image Generator
|
|
81
|
+
4. QR Code Generator
|
|
82
|
+
5. URL Encode/Decode
|
|
83
|
+
6. String Encode/Decode (Base64)
|
|
84
|
+
7. Unicode Encode/Decode
|
|
85
|
+
8. HTML Entity Encode/Decode
|
|
86
|
+
9. Variable Format Converter
|
|
87
|
+
a. JSON Format (Minify/Prettify)
|
|
88
|
+
b. Chinese to Pinyin
|
|
89
|
+
c. Time Format / Timestamp
|
|
90
|
+
d. Time Calculation (Diff/Offset)
|
|
91
|
+
e. Color Converter (Hex <-> RGB)
|
|
92
|
+
f. Get UUID
|
|
93
|
+
g. Hash Calculator (MD5/SHA/SM3)
|
|
94
|
+
h. Mock Text
|
|
95
|
+
i. Special Characters (Symbols)
|
|
96
|
+
j. Emoji Picker
|
|
97
|
+
k. Markdown Snippets
|
|
98
|
+
l. VS Code Snippet Generator
|
|
99
|
+
s. Settings (Language)
|
|
100
|
+
0. Exit
|
|
101
|
+
=================================
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 📖 Detailed Usage
|
|
105
|
+
|
|
106
|
+
### 1. Image <-> Base64
|
|
107
|
+
- Select `1`.
|
|
108
|
+
- **Image -> Base64**:
|
|
109
|
+
- Select image file.
|
|
110
|
+
- Output Base64 string (can save to `.txt`).
|
|
111
|
+
- **Base64 -> Image**:
|
|
112
|
+
- Input Base64 string (file or clipboard).
|
|
113
|
+
- Auto-detect format and save as file.
|
|
114
|
+
|
|
115
|
+
### 2. Image Format Convert
|
|
116
|
+
- Select `2`.
|
|
117
|
+
- Select source image.
|
|
118
|
+
- Select target format (PNG / JPG / WebP).
|
|
119
|
+
- Set quality/compression.
|
|
120
|
+
- Saved in the same directory.
|
|
121
|
+
|
|
122
|
+
### 3. Placeholder Image Generator
|
|
123
|
+
- Select `3`.
|
|
124
|
+
- **Mode 1: Local Image File**
|
|
125
|
+
- Generate file locally.
|
|
126
|
+
- Customize: Size, Colors, Text, Format.
|
|
127
|
+
- **Mode 2: Remote Image URL**
|
|
128
|
+
- Generate URL and copy to clipboard.
|
|
129
|
+
- Supports: Picsum Photos, DummyImage, Via Placeholder, Placehold.jp, DevTool Tech, FPO Img.
|
|
130
|
+
|
|
131
|
+
### 4. QR Code Generator
|
|
132
|
+
- Select `4`.
|
|
133
|
+
- Input text or URL.
|
|
134
|
+
- Preview in terminal.
|
|
135
|
+
- Option to save as PNG.
|
|
136
|
+
|
|
137
|
+
### 5. URL Encode/Decode
|
|
138
|
+
- Select `5`.
|
|
139
|
+
- Select `Encode` or `Decode`.
|
|
140
|
+
- Input URL, result auto-copied.
|
|
141
|
+
|
|
142
|
+
### 6. String Base64
|
|
143
|
+
- Select `6`.
|
|
144
|
+
- Input sources: Clipboard, File, Manual.
|
|
145
|
+
- Output: Copy, Save to file.
|
|
146
|
+
|
|
147
|
+
### 7. Unicode Encode/Decode
|
|
148
|
+
- Select `7`.
|
|
149
|
+
- **Encode**: Text to Unicode escape sequences.
|
|
150
|
+
- **Non-ASCII Only**: Recommended.
|
|
151
|
+
- **All Characters**.
|
|
152
|
+
- **Decode**: Unicode to Text.
|
|
153
|
+
|
|
154
|
+
### 8. HTML Entity Encode/Decode
|
|
155
|
+
- Select `8`.
|
|
156
|
+
- **Standard**: Special chars only.
|
|
157
|
+
- **Everything**: All chars.
|
|
158
|
+
|
|
159
|
+
### 9. Variable Format Converter
|
|
160
|
+
- Select `9`.
|
|
161
|
+
- Input variable name.
|
|
162
|
+
- Shows CamelCase, PascalCase, SnakeCase, KebabCase, ConstantCase.
|
|
163
|
+
- Select one to copy.
|
|
164
|
+
|
|
165
|
+
### 10. JSON Format
|
|
166
|
+
- Select `a`.
|
|
167
|
+
- **Minify**: Remove whitespace.
|
|
168
|
+
- **Prettify (2/4 spaces)**.
|
|
169
|
+
- **Note**: Results copied to clipboard only (to avoid flooding terminal).
|
|
170
|
+
|
|
171
|
+
### 11. Chinese to Pinyin
|
|
172
|
+
- Select `b`.
|
|
173
|
+
- Input Chinese string.
|
|
174
|
+
- Output Pinyin (no tone).
|
|
175
|
+
|
|
176
|
+
### 12. Time Format
|
|
177
|
+
- Select `c`.
|
|
178
|
+
- Timestamp <-> Date String.
|
|
179
|
+
- Enter to get current timestamp.
|
|
180
|
+
|
|
181
|
+
### 13. Time Calculation
|
|
182
|
+
- Select `d`.
|
|
183
|
+
- **Diff**: Calculate difference between two dates.
|
|
184
|
+
- **Offset**: Calculate date after add/subtract time units.
|
|
185
|
+
|
|
186
|
+
### 14. Color Converter
|
|
187
|
+
- Select `e`.
|
|
188
|
+
- Hex <-> RGB.
|
|
189
|
+
|
|
190
|
+
### 15. Get UUID
|
|
191
|
+
- Select `f`.
|
|
192
|
+
- Generate UUID v4.
|
|
193
|
+
|
|
194
|
+
### 16. Hash Calculator
|
|
195
|
+
- Select `g`.
|
|
196
|
+
- Input text.
|
|
197
|
+
- Shows MD5, SHA1, SHA256, SHA512, SM3.
|
|
198
|
+
|
|
199
|
+
### 17. Mock Data
|
|
200
|
+
- Select `h`.
|
|
201
|
+
- Generate Lorem Ipsum, Names, IDs, Emails, Phones, etc.
|
|
202
|
+
|
|
203
|
+
### 18. Special Symbols
|
|
204
|
+
- Select `i`.
|
|
205
|
+
- Grid view of symbols.
|
|
206
|
+
- Select index to copy.
|
|
207
|
+
|
|
208
|
+
### 19. Emoji Picker
|
|
209
|
+
- Select `j`.
|
|
210
|
+
- Categorized emojis.
|
|
211
|
+
- Select to copy.
|
|
212
|
+
|
|
213
|
+
### 20. Markdown Snippets
|
|
214
|
+
- Select `k`.
|
|
215
|
+
- Templates for Headers, Lists, Tables, Links, etc.
|
|
216
|
+
|
|
217
|
+
### 21. VS Code Snippet Generator
|
|
218
|
+
- Select `l`.
|
|
219
|
+
- Convert code to `.code-snippets` JSON body.
|
|
220
|
+
- Auto-escapes quotes/newlines.
|
|
221
|
+
- Copied to clipboard.
|
|
222
|
+
|
|
223
|
+
## 📄 License
|
|
224
|
+
|
|
225
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xw-devtool-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "基于node的开发者助手cli",
|
|
6
6
|
"main": "index.js",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|
|
13
13
|
"src",
|
|
14
|
-
"README.md"
|
|
14
|
+
"README.md",
|
|
15
|
+
"README_EN.md"
|
|
15
16
|
],
|
|
16
17
|
"scripts": {
|
|
17
18
|
"start": "node bin/index.js",
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"commander": "^14.0.2",
|
|
68
69
|
"dayjs": "^1.11.19",
|
|
69
70
|
"he": "^1.2.0",
|
|
71
|
+
"i18next": "^25.7.3",
|
|
70
72
|
"inquirer": "^13.1.0",
|
|
71
73
|
"lorem-ipsum": "^2.0.8",
|
|
72
74
|
"pinyin": "^4.0.0",
|
package/src/commands/url.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import { copy } from '../utils/clipboard.js';
|
|
3
3
|
import { selectFromMenu } from '../utils/menu.js';
|
|
4
|
+
import i18next from '../i18n.js';
|
|
4
5
|
|
|
5
6
|
export async function urlHandler() {
|
|
6
|
-
const mode = await selectFromMenu('
|
|
7
|
-
{ name: '
|
|
8
|
-
{ name: '
|
|
7
|
+
const mode = await selectFromMenu(i18next.t('url.title'), [
|
|
8
|
+
{ name: i18next.t('url.encode'), value: 'encode' },
|
|
9
|
+
{ name: i18next.t('url.decode'), value: 'decode' }
|
|
9
10
|
]);
|
|
10
11
|
|
|
11
12
|
const { input } = await inquirer.prompt([
|
|
12
13
|
{
|
|
13
14
|
type: 'input',
|
|
14
15
|
name: 'input',
|
|
15
|
-
message:
|
|
16
|
+
message: i18next.t('url.inputPrompt', { mode: mode === 'encode' ? i18next.t('url.encode') : i18next.t('url.decode') })
|
|
16
17
|
}
|
|
17
18
|
]);
|
|
18
19
|
|
|
@@ -23,9 +24,9 @@ export async function urlHandler() {
|
|
|
23
24
|
} else {
|
|
24
25
|
result = decodeURIComponent(input);
|
|
25
26
|
}
|
|
26
|
-
console.log(`\
|
|
27
|
+
console.log(`\n${i18next.t('url.result')}\n${result}\n`);
|
|
27
28
|
await copy(result);
|
|
28
29
|
} catch (e) {
|
|
29
|
-
console.error('
|
|
30
|
+
console.error(i18next.t('url.error'), e.message);
|
|
30
31
|
}
|
|
31
32
|
}
|
package/src/i18n.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import i18next from 'i18next';
|
|
2
|
+
import en from './locales/en.js';
|
|
3
|
+
import zh from './locales/zh.js';
|
|
4
|
+
import { loadConfig, saveConfig } from './utils/config.js';
|
|
5
|
+
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
|
|
8
|
+
let systemLocale = 'en';
|
|
9
|
+
try {
|
|
10
|
+
systemLocale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
11
|
+
} catch (e) {}
|
|
12
|
+
|
|
13
|
+
let language = config.language || systemLocale;
|
|
14
|
+
|
|
15
|
+
// Check command line arguments for language override
|
|
16
|
+
// Note: We check this before commander parses arguments because i18n is initialized at top-level
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
let newLang = null;
|
|
19
|
+
if (args.includes('--zh')) {
|
|
20
|
+
newLang = 'zh';
|
|
21
|
+
} else if (args.includes('--en')) {
|
|
22
|
+
newLang = 'en';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (newLang) {
|
|
26
|
+
language = newLang;
|
|
27
|
+
// Persist the language setting if changed via CLI
|
|
28
|
+
saveConfig({ language: newLang });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (language.toLowerCase().startsWith('zh')) {
|
|
32
|
+
language = 'zh';
|
|
33
|
+
} else {
|
|
34
|
+
language = 'en';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await i18next.init({
|
|
38
|
+
lng: language,
|
|
39
|
+
fallbackLng: 'en',
|
|
40
|
+
resources: {
|
|
41
|
+
en: { translation: en },
|
|
42
|
+
zh: { translation: zh }
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default i18next;
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
|
-
import {
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import i18next from './i18n.js';
|
|
4
|
+
import { saveConfig } from './utils/config.js';
|
|
5
|
+
|
|
3
6
|
import { urlHandler } from './commands/url.js';
|
|
4
7
|
import { base64Handler } from './commands/base64.js';
|
|
5
8
|
import { unicodeHandler } from './commands/unicode.js';
|
|
@@ -23,13 +26,13 @@ import { markdownHandler } from './commands/markdown.js';
|
|
|
23
26
|
import { vscodeSnippetHandler } from './commands/vscodeSnippet.js';
|
|
24
27
|
|
|
25
28
|
process.on('SIGINT', () => {
|
|
26
|
-
console.log('
|
|
29
|
+
console.log(`\n${i18next.t('menu.bye')}`);
|
|
27
30
|
process.exit(0);
|
|
28
31
|
});
|
|
29
32
|
process.on('unhandledRejection', (err) => {
|
|
30
33
|
const msg = (err && err.message) ? err.message : String(err);
|
|
31
34
|
if (msg.includes('SIGINT') || (err && err.name === 'ExitPromptError')) {
|
|
32
|
-
console.log('
|
|
35
|
+
console.log(`\n${i18next.t('menu.bye')}`);
|
|
33
36
|
process.exit(0);
|
|
34
37
|
} else {
|
|
35
38
|
console.error('Unhandled error:', err);
|
|
@@ -37,41 +40,50 @@ process.on('unhandledRejection', (err) => {
|
|
|
37
40
|
}
|
|
38
41
|
});
|
|
39
42
|
|
|
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
|
-
|
|
43
|
+
function getFeatures() {
|
|
44
|
+
return [
|
|
45
|
+
// Image Tools
|
|
46
|
+
{ name: i18next.t('menu.features.imgBase64'), value: 'imgBase64' },
|
|
47
|
+
{ name: i18next.t('menu.features.imgConvert'), value: 'imgConvert' },
|
|
48
|
+
{ name: i18next.t('menu.features.placeholderImg'), value: 'placeholderImg' },
|
|
49
|
+
{ name: i18next.t('menu.features.qrcode'), value: 'qrcode' },
|
|
50
|
+
|
|
51
|
+
// Encode/Decode & Formatting
|
|
52
|
+
{ name: i18next.t('menu.features.url'), value: 'url' },
|
|
53
|
+
{ name: i18next.t('menu.features.base64'), value: 'base64' },
|
|
54
|
+
{ name: i18next.t('menu.features.unicode'), value: 'unicode' },
|
|
55
|
+
{ name: i18next.t('menu.features.htmlEntities'), value: 'htmlEntities' },
|
|
56
|
+
{ name: i18next.t('menu.features.variableFormat'), value: 'variableFormat' },
|
|
57
|
+
{ name: i18next.t('menu.features.jsonFormat'), value: 'jsonFormat' },
|
|
58
|
+
{ name: i18next.t('menu.features.pinyin'), value: 'pinyin' },
|
|
59
|
+
|
|
60
|
+
// Utils (Time, Color, UUID, Hash)
|
|
61
|
+
{ name: i18next.t('menu.features.timeFormat'), value: 'timeFormat' },
|
|
62
|
+
{ name: i18next.t('menu.features.timeCalc'), value: 'timeCalc' },
|
|
63
|
+
{ name: i18next.t('menu.features.color'), value: 'color' },
|
|
64
|
+
{ name: i18next.t('menu.features.uuid'), value: 'uuid' },
|
|
65
|
+
{ name: i18next.t('menu.features.hashing'), value: 'hashing' },
|
|
66
|
+
|
|
67
|
+
// Content/Mocking
|
|
68
|
+
{ name: i18next.t('menu.features.mock'), value: 'mock' },
|
|
69
|
+
{ name: i18next.t('menu.features.specialChars'), value: 'specialChars' },
|
|
70
|
+
{ name: i18next.t('menu.features.emoji'), value: 'emoji' },
|
|
71
|
+
{ name: i18next.t('menu.features.markdown'), value: 'markdown' },
|
|
72
|
+
{ name: i18next.t('menu.features.vscodeSnippet'), value: 'vscodeSnippet' },
|
|
73
|
+
|
|
74
|
+
// Settings
|
|
75
|
+
{ name: i18next.t('menu.features.settings'), value: 'settings' }
|
|
76
|
+
];
|
|
77
|
+
}
|
|
70
78
|
|
|
71
79
|
async function main() {
|
|
80
|
+
const program = new Command();
|
|
81
|
+
|
|
72
82
|
program
|
|
73
83
|
.version('1.0.0')
|
|
74
84
|
.description('Developer Assistant CLI')
|
|
85
|
+
.option('--en', 'Set language to English')
|
|
86
|
+
.option('--zh', 'Set language to Chinese')
|
|
75
87
|
.action(async () => {
|
|
76
88
|
await showMenu();
|
|
77
89
|
});
|
|
@@ -97,20 +109,22 @@ function getFeatureIndex(key) {
|
|
|
97
109
|
}
|
|
98
110
|
|
|
99
111
|
async function showMenu() {
|
|
112
|
+
const features = getFeatures();
|
|
113
|
+
|
|
100
114
|
console.log('\n=================================');
|
|
101
|
-
console.log(
|
|
115
|
+
console.log(` ${i18next.t('menu.title')}`);
|
|
102
116
|
console.log('=================================');
|
|
103
117
|
features.forEach((feature, index) => {
|
|
104
118
|
console.log(`${getFeatureKey(index)}. ${feature.name}`);
|
|
105
119
|
});
|
|
106
|
-
console.log(
|
|
120
|
+
console.log(`0. ${i18next.t('menu.exit')}`);
|
|
107
121
|
console.log('=================================\n');
|
|
108
122
|
|
|
109
123
|
const { choice } = await inquirer.prompt([
|
|
110
124
|
{
|
|
111
125
|
type: 'input',
|
|
112
126
|
name: 'choice',
|
|
113
|
-
message:
|
|
127
|
+
message: i18next.t('menu.prompt'),
|
|
114
128
|
validate: (input) => {
|
|
115
129
|
if (input === '0') return true;
|
|
116
130
|
|
|
@@ -118,13 +132,13 @@ async function showMenu() {
|
|
|
118
132
|
if (index >= 0 && index < features.length) {
|
|
119
133
|
return true;
|
|
120
134
|
}
|
|
121
|
-
return '
|
|
135
|
+
return i18next.t('menu.invalid');
|
|
122
136
|
}
|
|
123
137
|
}
|
|
124
138
|
]);
|
|
125
139
|
|
|
126
140
|
if (choice === '0') {
|
|
127
|
-
console.log('
|
|
141
|
+
console.log(i18next.t('menu.bye'));
|
|
128
142
|
process.exit(0);
|
|
129
143
|
}
|
|
130
144
|
|
|
@@ -137,8 +151,6 @@ async function showMenu() {
|
|
|
137
151
|
console.error('Error:', error.message);
|
|
138
152
|
}
|
|
139
153
|
|
|
140
|
-
// Wait a bit or ask to continue?
|
|
141
|
-
// Usually just looping back is fine.
|
|
142
154
|
await showMenu();
|
|
143
155
|
}
|
|
144
156
|
|
|
@@ -183,6 +195,7 @@ async function handleAction(action) {
|
|
|
183
195
|
case 'jsonFormat':
|
|
184
196
|
await jsonFormatHandler();
|
|
185
197
|
break;
|
|
198
|
+
|
|
186
199
|
case 'hashing':
|
|
187
200
|
await hashingHandler();
|
|
188
201
|
break;
|
|
@@ -207,9 +220,54 @@ async function handleAction(action) {
|
|
|
207
220
|
case 'vscodeSnippet':
|
|
208
221
|
await vscodeSnippetHandler();
|
|
209
222
|
break;
|
|
223
|
+
case 'settings':
|
|
224
|
+
await handleSettings();
|
|
225
|
+
break;
|
|
210
226
|
default:
|
|
211
227
|
console.log('Feature not implemented yet.');
|
|
212
228
|
}
|
|
213
229
|
}
|
|
214
230
|
|
|
231
|
+
async function handleSettings() {
|
|
232
|
+
const languages = [
|
|
233
|
+
{ name: 'English', value: 'en' },
|
|
234
|
+
{ name: '中文 (Chinese)', value: 'zh' }
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
console.log(`\n${i18next.t('settings.selectLanguage')}:`);
|
|
238
|
+
languages.forEach((lang, index) => {
|
|
239
|
+
console.log(`${index + 1}. ${lang.name}`);
|
|
240
|
+
});
|
|
241
|
+
console.log(`0. ${i18next.t('settings.backToMenu')}`);
|
|
242
|
+
console.log(''); // Empty line
|
|
243
|
+
|
|
244
|
+
const { choice } = await inquirer.prompt([
|
|
245
|
+
{
|
|
246
|
+
type: 'input',
|
|
247
|
+
name: 'choice',
|
|
248
|
+
message: i18next.t('menu.prompt'),
|
|
249
|
+
validate: (input) => {
|
|
250
|
+
if (input === '0') return true;
|
|
251
|
+
const index = parseInt(input);
|
|
252
|
+
if (index >= 1 && index <= languages.length) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
return 'Invalid selection.';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
if (choice === '0') {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const lang = languages[parseInt(choice) - 1].value;
|
|
265
|
+
|
|
266
|
+
saveConfig({ language: lang });
|
|
267
|
+
|
|
268
|
+
await i18next.changeLanguage(lang);
|
|
269
|
+
|
|
270
|
+
console.log(i18next.t('settings.saved'));
|
|
271
|
+
}
|
|
272
|
+
|
|
215
273
|
main();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
menu: {
|
|
3
|
+
title: 'xw-devtool-cli Menu',
|
|
4
|
+
exit: 'Exit',
|
|
5
|
+
prompt: 'Please enter the feature key (0-9, a-z):',
|
|
6
|
+
invalid: 'Invalid selection. Please enter a valid menu key.',
|
|
7
|
+
bye: 'Bye!',
|
|
8
|
+
features: {
|
|
9
|
+
imgBase64: 'Image <-> Base64',
|
|
10
|
+
imgConvert: 'Image Format Convert',
|
|
11
|
+
placeholderImg: 'Placeholder Image Generator',
|
|
12
|
+
qrcode: 'QR Code Generator',
|
|
13
|
+
url: 'URL Encode/Decode',
|
|
14
|
+
base64: 'String Encode/Decode (Base64)',
|
|
15
|
+
unicode: 'Unicode Encode/Decode',
|
|
16
|
+
htmlEntities: 'HTML Entity Encode/Decode',
|
|
17
|
+
variableFormat: 'Variable Format Converter',
|
|
18
|
+
jsonFormat: 'JSON Format (Minify/Prettify)',
|
|
19
|
+
pinyin: 'Chinese to Pinyin',
|
|
20
|
+
timeFormat: 'Time Format / Timestamp',
|
|
21
|
+
timeCalc: 'Time Calculation (Diff/Offset)',
|
|
22
|
+
color: 'Color Converter (Hex <-> RGB)',
|
|
23
|
+
uuid: 'Get UUID',
|
|
24
|
+
hashing: 'Hash Calculator (MD5/SHA/SM3)',
|
|
25
|
+
mock: 'Mock Text',
|
|
26
|
+
specialChars: 'Special Characters (Symbols)',
|
|
27
|
+
emoji: 'Emoji Picker',
|
|
28
|
+
markdown: 'Markdown Snippets',
|
|
29
|
+
vscodeSnippet: 'VS Code Snippet Generator',
|
|
30
|
+
settings: 'Settings / Language'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
settings: {
|
|
34
|
+
selectLanguage: 'Select Language',
|
|
35
|
+
saved: 'Language saved. Please restart the tool or continue using the menu.',
|
|
36
|
+
backToMenu: 'Back to Menu'
|
|
37
|
+
},
|
|
38
|
+
url: {
|
|
39
|
+
title: 'URL Encode/Decode',
|
|
40
|
+
encode: 'Encode',
|
|
41
|
+
decode: 'Decode',
|
|
42
|
+
inputPrompt: 'Enter URL to {{mode}}:',
|
|
43
|
+
result: 'Result:',
|
|
44
|
+
error: 'Error processing URL:'
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
menu: {
|
|
3
|
+
title: 'xw-devtool-cli 菜单',
|
|
4
|
+
exit: '退出',
|
|
5
|
+
prompt: '请输入功能键 (0-9, a-z):',
|
|
6
|
+
invalid: '无效选择,请输入有效的菜单键。',
|
|
7
|
+
bye: '再见!',
|
|
8
|
+
features: {
|
|
9
|
+
imgBase64: '图片 <-> Base64',
|
|
10
|
+
imgConvert: '图片格式转换',
|
|
11
|
+
placeholderImg: '占位图生成器',
|
|
12
|
+
qrcode: '二维码生成器',
|
|
13
|
+
url: 'URL 编码/解码',
|
|
14
|
+
base64: '字符串 编码/解码 (Base64)',
|
|
15
|
+
unicode: 'Unicode 编码/解码',
|
|
16
|
+
htmlEntities: 'HTML 实体 编码/解码',
|
|
17
|
+
variableFormat: '变量命名格式转换',
|
|
18
|
+
jsonFormat: 'JSON 格式化 (压缩/美化)',
|
|
19
|
+
pinyin: '汉字转拼音',
|
|
20
|
+
timeFormat: '时间格式化 / 时间戳',
|
|
21
|
+
timeCalc: '时间计算 (差值/偏移)',
|
|
22
|
+
color: '颜色转换 (Hex <-> RGB)',
|
|
23
|
+
uuid: '生成 UUID',
|
|
24
|
+
hashing: '哈希计算 (MD5/SHA/SM3)',
|
|
25
|
+
mock: 'Mock 文本生成',
|
|
26
|
+
specialChars: '特殊字符 (符号)',
|
|
27
|
+
emoji: 'Emoji 选择器',
|
|
28
|
+
markdown: 'Markdown 片段',
|
|
29
|
+
vscodeSnippet: 'VS Code 代码片段生成',
|
|
30
|
+
settings: '设置 / 语言 (Settings)'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
settings: {
|
|
34
|
+
selectLanguage: '选择语言',
|
|
35
|
+
saved: '语言已保存。请继续使用。',
|
|
36
|
+
backToMenu: '返回主菜单'
|
|
37
|
+
},
|
|
38
|
+
url: {
|
|
39
|
+
title: 'URL 编码/解码',
|
|
40
|
+
encode: '编码',
|
|
41
|
+
decode: '解码',
|
|
42
|
+
inputPrompt: '请输入要{{mode}}的 URL:',
|
|
43
|
+
result: '结果:',
|
|
44
|
+
error: '处理 URL 时出错:'
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
|
|
5
|
+
const CONFIG_FILE = path.join(os.homedir(), '.xw-devtool-cli-config.json');
|
|
6
|
+
|
|
7
|
+
export function loadConfig() {
|
|
8
|
+
try {
|
|
9
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
10
|
+
const data = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
11
|
+
return JSON.parse(data);
|
|
12
|
+
}
|
|
13
|
+
} catch (e) {
|
|
14
|
+
// Ignore errors
|
|
15
|
+
}
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function saveConfig(config) {
|
|
20
|
+
try {
|
|
21
|
+
const current = loadConfig();
|
|
22
|
+
const newConfig = { ...current, ...config };
|
|
23
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2), 'utf8');
|
|
24
|
+
return true;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error('Failed to save config:', e);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|