xw-devtool-cli 1.0.11 → 1.0.13

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 生成、汉字转拼音、颜色转换、变量格式转换、哈希计算、二维码生成、特殊符号大全等。所有结果均自动复制到剪贴板,极大提升开发效率。
6
6
 
7
7
  ## ✨ 功能特性
8
8
 
@@ -17,6 +17,7 @@
17
17
  - **时间工具**:
18
18
  - **时间格式化**:时间戳/日期字符串 -> `YYYY-MM-DD HH:mm:ss`。
19
19
  - **获取时间戳**:快速获取当前毫秒级时间戳。
20
+ - **时间计算**:计算日期差值或日期偏移 (Add/Subtract)。
20
21
  - **开发辅助工具**:
21
22
  - **URL 编解码**:Encode/Decode URL。
22
23
  - **Unicode 编解码**:文本与 Unicode 转义序列 (\uXXXX) 互转。
@@ -73,12 +74,13 @@ xw-devtool
73
74
  9. Variable Format Converter
74
75
  a. Chinese to Pinyin
75
76
  b. Time Format / Timestamp
76
- c. Color Converter (Hex <-> RGB)
77
- d. Get UUID
78
- e. Hash Calculator (MD5/SHA/SM3)
79
- f. Mock Text
80
- g. Special Characters (Symbols)
81
- h. Emoji Picker
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
82
84
  0. Exit
83
85
  =================================
84
86
  ```
@@ -143,7 +145,9 @@ h. Emoji Picker
143
145
 
144
146
  ### 7. Unicode 编码/解码
145
147
  - 选择 `7` 进入。
146
- - **Encode**: 将文本转换为 Unicode 转义序列 (如 `\u4F60\u597D`)。
148
+ - **Encode**: 将文本转换为 Unicode 转义序列。支持两种模式:
149
+ - **Non-ASCII Only**: 仅编码中文、符号等非 ASCII 字符 (推荐,保留英文可读性)。
150
+ - **All Characters**: 编码所有字符 (包括英文字母)。
147
151
  - **Decode**: 将 Unicode 转义序列还原为文本。
148
152
  - 结果自动复制到剪贴板。
149
153
 
@@ -171,32 +175,40 @@ h. Emoji Picker
171
175
  - 支持时间戳转日期字符串,或日期字符串转时间戳。
172
176
  - 直接回车可获取当前时间戳。
173
177
 
174
- ### 12. 颜色转换 (Hex <-> RGB)
178
+ ### 12. 时间计算 (Time Calculation)
175
179
  - 选择 `c` 进入。
180
+ - **Diff**: 计算两个日期之间的时间差 (天、小时、分、秒)。
181
+ - **Offset**: 计算指定偏移量后的日期。
182
+ - 支持单位:Years, Months, Weeks, Days, Hours, Minutes, Seconds。
183
+ - 支持操作:Add (+), Subtract (-)。
184
+ - 示例:计算 "当前时间 3 天后" 或 "2025-01-01 5 小时前"。
185
+
186
+ ### 13. 颜色转换 (Hex <-> RGB)
187
+ - 选择 `d` 进入。
176
188
  - 输入 Hex 颜色值 (如 #333) 或 RGB 值 (如 rgb(51,51,51))。
177
189
  - 自动转换并显示对应格式。
178
190
 
179
- ### 13. Get UUID
180
- - 选择 `d` 进入。
191
+ ### 14. Get UUID
192
+ - 选择 `e` 进入。
181
193
  - 自动生成一个 UUID v4 并复制到剪贴板。
182
194
 
183
- ### 14. 哈希计算 (Encryption)
184
- - 选择 `e` 进入。
195
+ ### 15. 哈希计算 (Encryption)
196
+ - 选择 `f` 进入。
185
197
  - 输入文本(支持直接回车读取剪贴板)。
186
198
  - 同时计算并显示 MD5, SHA1, SHA256, SHA512, SM3 哈希值。
187
199
 
188
- ### 15. Mock 数据生成
189
- - 选择 `f` 进入。
200
+ ### 16. Mock 数据生成
201
+ - 选择 `g` 进入。
190
202
  - 提供多种数据类型:英文段落、中文字符、身份证号、邮箱、手机号等。
191
203
  - 支持指定生成数量。
192
204
 
193
- ### 16. 特殊符号大全
194
- - 选择 `g` 进入。
205
+ ### 17. 特殊符号大全
206
+ - 选择 `h` 进入。
195
207
  - 网格化展示常用特殊符号。
196
208
  - 输入符号对应的编号即可一键复制。
197
209
 
198
- ### 17. Emoji 输入
199
- - 选择 `h` 进入。
210
+ ### 18. Emoji 输入
211
+ - 选择 `i` 进入。
200
212
  - 分类展示常用 Emoji (表情、手势、动物、食物等)。
201
213
  - 输入编号选择并复制 Emoji 到剪贴板。
202
214
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xw-devtool-cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "type": "module",
5
5
  "description": "基于node的开发者助手cli",
6
6
  "main": "index.js",
@@ -0,0 +1,151 @@
1
+ import inquirer from 'inquirer';
2
+ import dayjs from 'dayjs';
3
+ import duration from 'dayjs/plugin/duration.js';
4
+ import { copy } from '../utils/clipboard.js';
5
+ import { selectFromMenu } from '../utils/menu.js';
6
+
7
+ dayjs.extend(duration);
8
+
9
+ export async function timeCalcHandler() {
10
+ const mode = await selectFromMenu('Time Calculation', [
11
+ { name: 'Diff (Calculate difference between two dates)', value: 'diff' },
12
+ { name: 'Add/Subtract (Calculate new date from offset)', value: 'offset' }
13
+ ]);
14
+
15
+ if (mode === 'diff') {
16
+ await handleDiff();
17
+ } else {
18
+ await handleOffset();
19
+ }
20
+ }
21
+
22
+ async function handleDiff() {
23
+ const answers = await inquirer.prompt([
24
+ {
25
+ type: 'input',
26
+ name: 'start',
27
+ message: 'Enter Start Date (YYYY-MM-DD HH:mm:ss or timestamp):',
28
+ default: dayjs().format('YYYY-MM-DD HH:mm:ss')
29
+ },
30
+ {
31
+ type: 'input',
32
+ name: 'end',
33
+ message: 'Enter End Date (YYYY-MM-DD HH:mm:ss or timestamp):',
34
+ default: dayjs().format('YYYY-MM-DD HH:mm:ss')
35
+ }
36
+ ]);
37
+
38
+ const start = parseDate(answers.start);
39
+ const end = parseDate(answers.end);
40
+
41
+ if (!start.isValid() || !end.isValid()) {
42
+ console.error('Invalid date format.');
43
+ return;
44
+ }
45
+
46
+ const diffMs = end.diff(start);
47
+ const dur = dayjs.duration(diffMs);
48
+
49
+ const result = [
50
+ `Start: ${start.format('YYYY-MM-DD HH:mm:ss')}`,
51
+ `End: ${end.format('YYYY-MM-DD HH:mm:ss')}`,
52
+ '---------------------------------',
53
+ `Total Days: ${dur.asDays().toFixed(2)}`,
54
+ `Total Hours: ${dur.asHours().toFixed(2)}`,
55
+ `Total Minutes: ${dur.asMinutes().toFixed(2)}`,
56
+ `Total Seconds: ${dur.asSeconds().toFixed(0)}`,
57
+ '---------------------------------',
58
+ `Human Readable: ${formatDuration(dur)}`
59
+ ].join('\n');
60
+
61
+ console.log(`\n${result}\n`);
62
+ await copy(result);
63
+ }
64
+
65
+ async function handleOffset() {
66
+ const { startInput } = await inquirer.prompt([
67
+ {
68
+ type: 'input',
69
+ name: 'startInput',
70
+ message: 'Enter Start Date:',
71
+ default: dayjs().format('YYYY-MM-DD HH:mm:ss')
72
+ }
73
+ ]);
74
+
75
+ const start = parseDate(startInput);
76
+ if (!start.isValid()) {
77
+ console.error('Invalid date format.');
78
+ return;
79
+ }
80
+
81
+ const operator = await selectFromMenu('Select Operation', [
82
+ { name: 'Add (+)', value: 'add' },
83
+ { name: 'Subtract (-)', value: 'subtract' }
84
+ ]);
85
+
86
+ const unit = await selectFromMenu('Select Unit', [
87
+ { name: 'Days', value: 'day' },
88
+ { name: 'Hours', value: 'hour' },
89
+ { name: 'Minutes', value: 'minute' },
90
+ { name: 'Seconds', value: 'second' },
91
+ { name: 'Weeks', value: 'week' },
92
+ { name: 'Months', value: 'month' },
93
+ { name: 'Years', value: 'year' }
94
+ ]);
95
+
96
+ const { amount } = await inquirer.prompt([
97
+ {
98
+ type: 'number',
99
+ name: 'amount',
100
+ message: `Enter Amount of ${unit}s (number):`,
101
+ validate: val => !isNaN(val) || 'Please enter a number'
102
+ }
103
+ ]);
104
+
105
+ let resultDate;
106
+ if (operator === 'add') {
107
+ resultDate = start.add(amount, unit);
108
+ } else {
109
+ resultDate = start.subtract(amount, unit);
110
+ }
111
+
112
+ const result = resultDate.format('YYYY-MM-DD HH:mm:ss');
113
+ console.log(`\nResult Date: ${result}\n`);
114
+ await copy(result);
115
+ }
116
+
117
+ function parseDate(input) {
118
+ if (!input) return dayjs();
119
+ if (/^\d+$/.test(input)) {
120
+ const ts = parseInt(input);
121
+ if (input.length === 10) return dayjs.unix(ts);
122
+ return dayjs(ts);
123
+ }
124
+ return dayjs(input);
125
+ }
126
+
127
+ function formatDuration(dur) {
128
+ const parts = [];
129
+ const years = Math.floor(dur.asYears());
130
+ if (years > 0) parts.push(`${years} years`);
131
+
132
+ // Calculate remaining duration after removing years is tricky with dayjs duration directly
133
+ // simplified approach:
134
+
135
+ const d = Math.abs(dur.asMilliseconds());
136
+ const seconds = Math.floor((d / 1000) % 60);
137
+ const minutes = Math.floor((d / (1000 * 60)) % 60);
138
+ const hours = Math.floor((d / (1000 * 60 * 60)) % 24);
139
+ const days = Math.floor(d / (1000 * 60 * 60 * 24));
140
+
141
+ // Note: This simple day calc doesn't account for variable month lengths perfectly if we wanted "X months Y days"
142
+ // But for "X days Y hours..." it's accurate enough for absolute diff.
143
+
144
+ let str = '';
145
+ if (days > 0) str += `${days} days `;
146
+ if (hours > 0) str += `${hours} hours `;
147
+ if (minutes > 0) str += `${minutes} mins `;
148
+ if (seconds > 0) str += `${seconds} secs`;
149
+
150
+ return str.trim() || '0 secs';
151
+ }
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ import { unicodeHandler } from './commands/unicode.js';
6
6
  import { imgBase64Handler } from './commands/imgBase64.js';
7
7
  import { imgConvertHandler } from './commands/imgConvert.js';
8
8
  import { timeFormatHandler } from './commands/timeFormat.js';
9
+ import { timeCalcHandler } from './commands/timeCalc.js';
9
10
  import { mockHandler } from './commands/mock.js';
10
11
  import { uuidHandler } from './commands/uuid.js';
11
12
  import { pinyinHandler } from './commands/pinyin.js';
@@ -50,6 +51,7 @@ const features = [
50
51
 
51
52
  // Utils (Time, Color, UUID, Hash)
52
53
  { name: 'Time Format / Timestamp', value: 'timeFormat' },
54
+ { name: 'Time Calculation (Diff/Offset)', value: 'timeCalc' },
53
55
  { name: 'Color Converter (Hex <-> RGB)', value: 'color' },
54
56
  { name: 'Get UUID', value: 'uuid' },
55
57
  { name: 'Hash Calculator (MD5/SHA/SM3)', value: 'hashing' },
@@ -154,6 +156,9 @@ async function handleAction(action) {
154
156
  case 'timeFormat':
155
157
  await timeFormatHandler();
156
158
  break;
159
+ case 'timeCalc':
160
+ await timeCalcHandler();
161
+ break;
157
162
  case 'mock':
158
163
  await mockHandler();
159
164
  break;