xw-devtool-cli 1.0.13 → 1.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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  一个基于 Node.js 的开发者命令行工具箱,旨在提供开箱即用的常用开发工具,帮助开发者快速处理日常任务。
4
4
 
5
- 主要功能包括:Base64 编解码、图片格式转换、图片与 Base64 互转、Mock 数据生成、时间戳/日期格式化、时间计算、URL 编解码、UUID 生成、汉字转拼音、颜色转换、变量格式转换、哈希计算、二维码生成、特殊符号大全等。所有结果均自动复制到剪贴板,极大提升开发效率。
5
+ 主要功能包括:Base64 编解码、图片格式转换、图片与 Base64 互转、Mock 数据生成、时间戳/日期格式化、时间计算、URL 编解码、UUID 生成、汉字转拼音、颜色转换、变量格式转换、哈希计算、二维码生成、特殊符号大全、Markdown 语法工具等。所有结果均自动复制到剪贴板,极大提升开发效率。
6
6
 
7
7
  ## ✨ 功能特性
8
8
 
@@ -30,6 +30,7 @@
30
30
  - **特殊符号大全**:包含常用符号、箭头、数学符号、货币、希腊字母等 170+ 个符号,支持一键复制。
31
31
  - **Emoji 输入**:支持分类查看和选择常用 Emoji,一键复制到剪贴板。
32
32
  - **HTML 实体工具**:支持 HTML 实体编码与解码 (如 `&` <-> `&amp;`)。
33
+ - **Markdown 语法工具**:提供常用 Markdown 语法模板 (Headers, Lists, Tables, Code 等),一键复制。
33
34
  - **占位图生成**:自定义尺寸、背景色、文字颜色和格式生成占位图。
34
35
  - **便捷操作**:
35
36
  - 支持文件选择对话框 (Windows)。
@@ -72,15 +73,17 @@ xw-devtool
72
73
  7. Unicode Encode/Decode
73
74
  8. HTML Entity Encode/Decode
74
75
  9. Variable Format Converter
75
- a. Chinese to Pinyin
76
- b. Time Format / Timestamp
77
- c. Time Calculation (Diff/Offset)
78
- d. Color Converter (Hex <-> RGB)
79
- e. Get UUID
80
- f. Hash Calculator (MD5/SHA/SM3)
81
- g. Mock Text
82
- h. Special Characters (Symbols)
83
- i. Emoji Picker
76
+ a. JSON Format (Minify/Prettify)
77
+ b. Chinese to Pinyin
78
+ c. Time Format / Timestamp
79
+ d. Time Calculation (Diff/Offset)
80
+ e. Color Converter (Hex <-> RGB)
81
+ f. Get UUID
82
+ g. Hash Calculator (MD5/SHA/SM3)
83
+ h. Mock Text
84
+ i. Special Characters (Symbols)
85
+ j. Emoji Picker
86
+ k. Markdown Snippets
84
87
  0. Exit
85
88
  =================================
86
89
  ```
@@ -165,53 +168,83 @@ i. Emoji Picker
165
168
  - 自动展示 CamelCase, PascalCase, SnakeCase, KebabCase, ConstantCase 五种格式。
166
169
  - 选择一种格式自动复制。
167
170
 
168
- ### 10. 中文转拼音
171
+ ### 10. JSON 格式化
169
172
  - 选择 `a` 进入。
173
+ - 支持三种模式:
174
+ - **Minify**: 压缩 JSON (去除空格和换行)。
175
+ - **Prettify (2 spaces)**: 美化 JSON (2 空格缩进)。
176
+ - **Prettify (4 spaces)**: 美化 JSON (4 空格缩进)。
177
+ - 支持自动修复简单的非标准 JSON (如 key 缺少引号的 JS 对象)。
178
+ - 支持从剪贴板、文件或手动输入读取。
179
+ - **注意**:为防止长文本刷屏,结果**仅自动复制到剪贴板**,不会在终端打印。
180
+
181
+ ### 11. 中文转拼音
182
+ - 选择 `b` 进入。
170
183
  - 输入中文字符串(支持直接回车读取剪贴板)。
171
184
  - 输出对应的拼音(无声调)。
172
185
 
173
- ### 11. 时间格式化 (Time Format)
174
- - 选择 `b` 进入。
186
+ ### 12. 时间格式化 (Time Format)
187
+ - 选择 `c` 进入。
175
188
  - 支持时间戳转日期字符串,或日期字符串转时间戳。
176
189
  - 直接回车可获取当前时间戳。
177
190
 
178
- ### 12. 时间计算 (Time Calculation)
179
- - 选择 `c` 进入。
191
+ ### 13. 时间计算 (Time Calculation)
192
+ - 选择 `d` 进入。
180
193
  - **Diff**: 计算两个日期之间的时间差 (天、小时、分、秒)。
194
+ - **操作步骤**:
195
+ 1. 输入 **开始日期** (支持 `YYYY-MM-DD HH:mm:ss` 等多种格式,默认为当前时间)。
196
+ 2. 输入 **结束日期** (默认为当前时间)。
197
+ 3. 查看时间差结果 (显示总天数、总小时数及详细的 `x天x小时x分x秒`)。
181
198
  - **Offset**: 计算指定偏移量后的日期。
182
- - 支持单位:Years, Months, Weeks, Days, Hours, Minutes, Seconds。
183
- - 支持操作:Add (+), Subtract (-)。
199
+ - **操作步骤**:
200
+ 1. 输入 **基准日期** (默认为当前时间)。
201
+ 2. 选择 **时间单位** (Days, Hours, Minutes, Seconds, etc.)。
202
+ 3. 选择 **操作类型** (Add / Subtract)。
203
+ 4. 输入 **数量** (Amount)。
204
+ 5. 查看计算后的新日期。
184
205
  - 示例:计算 "当前时间 3 天后" 或 "2025-01-01 5 小时前"。
185
206
 
186
- ### 13. 颜色转换 (Hex <-> RGB)
187
- - 选择 `d` 进入。
207
+ ### 14. 颜色转换 (Hex <-> RGB)
208
+ - 选择 `e` 进入。
188
209
  - 输入 Hex 颜色值 (如 #333) 或 RGB 值 (如 rgb(51,51,51))。
189
210
  - 自动转换并显示对应格式。
190
211
 
191
- ### 14. Get UUID
192
- - 选择 `e` 进入。
212
+ ### 15. Get UUID
213
+ - 选择 `f` 进入。
193
214
  - 自动生成一个 UUID v4 并复制到剪贴板。
194
215
 
195
- ### 15. 哈希计算 (Encryption)
196
- - 选择 `f` 进入。
216
+ ### 16. 哈希计算 (Encryption)
217
+ - 选择 `g` 进入。
197
218
  - 输入文本(支持直接回车读取剪贴板)。
198
219
  - 同时计算并显示 MD5, SHA1, SHA256, SHA512, SM3 哈希值。
199
220
 
200
- ### 16. Mock 数据生成
201
- - 选择 `g` 进入。
221
+ ### 17. Mock 数据生成
222
+ - 选择 `h` 进入。
202
223
  - 提供多种数据类型:英文段落、中文字符、身份证号、邮箱、手机号等。
203
224
  - 支持指定生成数量。
204
225
 
205
- ### 17. 特殊符号大全
206
- - 选择 `h` 进入。
226
+ ### 18. 特殊符号大全
227
+ - 选择 `i` 进入。
207
228
  - 网格化展示常用特殊符号。
208
229
  - 输入符号对应的编号即可一键复制。
209
230
 
210
- ### 18. Emoji 输入
211
- - 选择 `i` 进入。
231
+ ### 19. Emoji 输入
232
+ - 选择 `j` 进入。
212
233
  - 分类展示常用 Emoji (表情、手势、动物、食物等)。
213
234
  - 输入编号选择并复制 Emoji 到剪贴板。
214
235
 
236
+ ### 20. Markdown 语法工具 (Markdown Snippets)
237
+ - 选择 `k` 进入。
238
+ - 提供常用的 Markdown 语法模板,分类包括:
239
+ - **Headers**: 标题 (H1-H6)。
240
+ - **Emphasis**: 加粗、斜体、删除线。
241
+ - **Lists**: 无序列表、有序列表、任务列表。
242
+ - **Links & Images**: 链接、图片插入。
243
+ - **Code**: 行内代码、代码块。
244
+ - **Tables**: 表格模板。
245
+ - **Others**: 引用、分割线、折叠详情等。
246
+ - 选择对应语法后,模板将自动复制到剪贴板。
247
+
215
248
  ## 📄 License
216
249
 
217
250
  ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xw-devtool-cli",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "type": "module",
5
5
  "description": "基于node的开发者助手cli",
6
6
  "main": "index.js",
@@ -20,17 +20,35 @@
20
20
  "keywords": [
21
21
  "cli",
22
22
  "devtools",
23
+ "developer-tools",
24
+ "toolbox",
25
+ "utility",
23
26
  "base64",
24
- "url",
27
+ "url-encode",
28
+ "unicode",
29
+ "html-entities",
25
30
  "uuid",
26
31
  "pinyin",
27
32
  "mock",
33
+ "mock-data",
28
34
  "timestamp",
29
35
  "time",
36
+ "date-calculation",
30
37
  "image",
38
+ "image-conversion",
31
39
  "webp",
32
40
  "jpg",
33
- "png"
41
+ "png",
42
+ "placeholder-image",
43
+ "qrcode",
44
+ "json-format",
45
+ "variable-case",
46
+ "hash",
47
+ "encryption",
48
+ "md5",
49
+ "color-converter",
50
+ "emoji",
51
+ "markdown"
34
52
  ],
35
53
  "author": "npmxw",
36
54
  "license": "ISC",
@@ -0,0 +1,83 @@
1
+ import inquirer from 'inquirer';
2
+ import { copy } from '../utils/clipboard.js';
3
+ import { selectFromMenu } from '../utils/menu.js';
4
+ import fs from 'fs';
5
+
6
+ export async function jsonFormatHandler() {
7
+ const mode = await selectFromMenu('JSON Format', [
8
+ { name: 'Minify (Compact)', value: 'minify' },
9
+ { name: 'Prettify (2 spaces)', value: 'prettify-2' },
10
+ { name: 'Prettify (4 spaces)', value: 'prettify-4' }
11
+ ]);
12
+
13
+ const inputSource = await selectFromMenu('Select Input Source', [
14
+ { name: 'Clipboard (Paste automatically)', value: 'clipboard' },
15
+ { name: 'Manual Input', value: 'manual' },
16
+ { name: 'File', value: 'file' }
17
+ ]);
18
+
19
+ let input = '';
20
+ if (inputSource === 'clipboard') {
21
+ const clipboardy = (await import('clipboardy')).default;
22
+ input = await clipboardy.read();
23
+ } else if (inputSource === 'file') {
24
+ const { filePath } = await inquirer.prompt([
25
+ {
26
+ type: 'input',
27
+ name: 'filePath',
28
+ message: 'Enter file path:'
29
+ }
30
+ ]);
31
+ try {
32
+ input = fs.readFileSync(filePath.replace(/"/g, ''), 'utf-8');
33
+ } catch (e) {
34
+ console.error('Error reading file:', e.message);
35
+ return;
36
+ }
37
+ } else {
38
+ const { manualInput } = await inquirer.prompt([
39
+ {
40
+ type: 'input',
41
+ name: 'manualInput',
42
+ message: 'Enter JSON string:'
43
+ }
44
+ ]);
45
+ input = manualInput;
46
+ }
47
+
48
+ try {
49
+ // Try to parse relaxed JSON (like JS objects) if possible, but standard JSON.parse is safer for strict JSON
50
+ // We can try to evaluate if it fails parsing, but that's risky.
51
+ // Let's stick to standard JSON parsing first.
52
+ let jsonObj;
53
+ try {
54
+ jsonObj = JSON.parse(input);
55
+ } catch (e) {
56
+ // If strict parse fails, try to be more lenient if it's a JS object string
57
+ // e.g. { a: 1 } instead of { "a": 1 }
58
+ // Using Function constructor is safer than eval but still risky.
59
+ // For a dev tool, it might be acceptable if warned.
60
+ // Let's try a simple regex fix for common cases (keys without quotes)
61
+ try {
62
+ // This is a very basic attempt to fix unquoted keys
63
+ const fixed = input.replace(/([{,]\s*)([a-zA-Z0-9_]+?)\s*:/g, '$1"$2":');
64
+ jsonObj = JSON.parse(fixed);
65
+ } catch (e2) {
66
+ throw new Error('Invalid JSON format');
67
+ }
68
+ }
69
+
70
+ let output = '';
71
+ if (mode === 'minify') {
72
+ output = JSON.stringify(jsonObj);
73
+ } else if (mode === 'prettify-2') {
74
+ output = JSON.stringify(jsonObj, null, 2);
75
+ } else {
76
+ output = JSON.stringify(jsonObj, null, 4);
77
+ }
78
+
79
+ await copy(output);
80
+ } catch (e) {
81
+ console.error('Error processing JSON:', e.message);
82
+ }
83
+ }
@@ -0,0 +1,75 @@
1
+ import { selectFromMenu } from '../utils/menu.js';
2
+ import { copy } from '../utils/clipboard.js';
3
+ import inquirer from 'inquirer';
4
+
5
+ const MARKDOWN_SNIPPETS = {
6
+ 'headers': [
7
+ { name: 'H1 Header (#)', value: '# Header 1' },
8
+ { name: 'H2 Header (##)', value: '## Header 2' },
9
+ { name: 'H3 Header (###)', value: '### Header 3' },
10
+ { name: 'H4 Header (####)', value: '#### Header 4' },
11
+ ],
12
+ 'emphasis': [
13
+ { name: 'Bold (**text**)', value: '**Bold Text**' },
14
+ { name: 'Italic (*text*)', value: '*Italic Text*' },
15
+ { name: 'Bold Italic (***text***)', value: '***Bold Italic Text***' },
16
+ { name: 'Strikethrough (~~text~~)', value: '~~Strikethrough Text~~' },
17
+ ],
18
+ 'lists': [
19
+ { name: 'Unordered List (-)', value: '- Item 1\n- Item 2\n- Item 3' },
20
+ { name: 'Ordered List (1.)', value: '1. Item 1\n2. Item 2\n3. Item 3' },
21
+ { name: 'Task List (- [ ])', value: '- [ ] To Do\n- [x] Done' },
22
+ ],
23
+ 'links_images': [
24
+ { name: 'Link [text](url)', value: '[Link Text](https://example.com)' },
25
+ { name: 'Image ![alt](url)', value: '![Alt Text](https://example.com/image.jpg)' },
26
+ { name: 'Link with Title', value: '[Link Text](https://example.com "Title")' },
27
+ ],
28
+ 'code': [
29
+ { name: 'Inline Code (`text`)', value: '`code`' },
30
+ { name: 'Code Block (```)', value: '```javascript\nconsole.log("Hello World");\n```' },
31
+ ],
32
+ 'tables': [
33
+ { name: 'Table (3x3)', value: '| Header 1 | Header 2 | Header 3 |\n| :--- | :---: | ---: |\n| Left | Center | Right |\n| Item 1 | Item 2 | Item 3 |' },
34
+ ],
35
+ 'others': [
36
+ { name: 'Blockquote (>)', value: '> This is a quote.' },
37
+ { name: 'Horizontal Rule (---)', value: '---' },
38
+ { name: 'Details/Summary (<details>)', value: '<details>\n<summary>Click to expand</summary>\n\nHidden content here.\n</details>' },
39
+ ]
40
+ };
41
+
42
+ export async function markdownHandler() {
43
+ while (true) {
44
+ const category = await selectFromMenu('Markdown Snippets', [
45
+ { name: 'Headers (H1-H6)', value: 'headers' },
46
+ { name: 'Emphasis (Bold, Italic...)', value: 'emphasis' },
47
+ { name: 'Lists (Bullet, Numbered, Task)', value: 'lists' },
48
+ { name: 'Links & Images', value: 'links_images' },
49
+ { name: 'Code (Inline, Block)', value: 'code' },
50
+ { name: 'Tables', value: 'tables' },
51
+ { name: 'Others (Quote, HR, Details)', value: 'others' },
52
+ { name: 'Back to Main Menu', value: 'back' }
53
+ ]);
54
+
55
+ if (category === 'back') {
56
+ break;
57
+ }
58
+
59
+ const snippets = MARKDOWN_SNIPPETS[category];
60
+ const snippetValue = await selectFromMenu('Select Snippet', [
61
+ ...snippets,
62
+ { name: 'Back', value: 'back' }
63
+ ]);
64
+
65
+ if (snippetValue === 'back') {
66
+ continue;
67
+ }
68
+
69
+ await copy(snippetValue);
70
+
71
+ // Optional: ask if user wants to continue or exit
72
+ // For now, loop back to category selection is consistent with other tools or just exit?
73
+ // Let's loop back to categories to allow picking another one.
74
+ }
75
+ }
package/src/index.js CHANGED
@@ -12,12 +12,14 @@ import { uuidHandler } from './commands/uuid.js';
12
12
  import { pinyinHandler } from './commands/pinyin.js';
13
13
  import { colorHandler } from './commands/color.js';
14
14
  import { variableFormatHandler } from './commands/variableFormat.js';
15
+ import { jsonFormatHandler } from './commands/jsonFormat.js';
15
16
  import { hashingHandler } from './commands/hashing.js';
16
17
  import { qrcodeHandler } from './commands/qrcode.js';
17
18
  import { specialCharsHandler } from './commands/specialChars.js';
18
19
  import { emojiHandler } from './commands/emoji.js';
19
20
  import { htmlEntitiesHandler } from './commands/htmlEntities.js';
20
21
  import { placeholderImgHandler } from './commands/placeholderImg.js';
22
+ import { markdownHandler } from './commands/markdown.js';
21
23
 
22
24
  process.on('SIGINT', () => {
23
25
  console.log('\nBye!');
@@ -47,6 +49,7 @@ const features = [
47
49
  { name: 'Unicode Encode/Decode', value: 'unicode' },
48
50
  { name: 'HTML Entity Encode/Decode', value: 'htmlEntities' },
49
51
  { name: 'Variable Format Converter', value: 'variableFormat' },
52
+ { name: 'JSON Format (Minify/Prettify)', value: 'jsonFormat' },
50
53
  { name: 'Chinese to Pinyin', value: 'pinyin' },
51
54
 
52
55
  // Utils (Time, Color, UUID, Hash)
@@ -59,7 +62,8 @@ const features = [
59
62
  // Content/Mocking
60
63
  { name: 'Mock Text', value: 'mock' },
61
64
  { name: 'Special Characters (Symbols)', value: 'specialChars' },
62
- { name: 'Emoji Picker', value: 'emoji' }
65
+ { name: 'Emoji Picker', value: 'emoji' },
66
+ { name: 'Markdown Snippets', value: 'markdown' }
63
67
  ];
64
68
 
65
69
  async function main() {
@@ -174,6 +178,9 @@ async function handleAction(action) {
174
178
  case 'variableFormat':
175
179
  await variableFormatHandler();
176
180
  break;
181
+ case 'jsonFormat':
182
+ await jsonFormatHandler();
183
+ break;
177
184
  case 'hashing':
178
185
  await hashingHandler();
179
186
  break;
@@ -192,6 +199,9 @@ async function handleAction(action) {
192
199
  case 'placeholderImg':
193
200
  await placeholderImgHandler();
194
201
  break;
202
+ case 'markdown':
203
+ await markdownHandler();
204
+ break;
195
205
  default:
196
206
  console.log('Feature not implemented yet.');
197
207
  }