@xiaozhi-client/version 1.10.9 → 2.0.0-beta.1
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 +414 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +41 -38
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/VersionUtils.ts +45 -44
- package/src/__tests__/VersionUtils.test.ts +8 -5
- package/tsup.config.ts +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# @xiaozhi-client/version
|
|
2
|
+
|
|
3
|
+
> 小智客户端版本管理工具,提供版本号获取、比较、验证等功能
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@xiaozhi-client/version)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## 简介
|
|
9
|
+
|
|
10
|
+
`@xiaozhi-client/version` 是一个轻量级的版本管理工具库,提供:
|
|
11
|
+
|
|
12
|
+
- **版本号获取** - 支持构建时注入和运行时读取两种方式
|
|
13
|
+
- **版本比较** - 语义化版本号比较功能
|
|
14
|
+
- **版本验证** - 验证版本号格式是否符合语义化版本规范
|
|
15
|
+
- **零依赖** - 无任何外部依赖
|
|
16
|
+
- **TypeScript** - 完整的类型定义支持
|
|
17
|
+
|
|
18
|
+
## 特性
|
|
19
|
+
|
|
20
|
+
### 核心功能
|
|
21
|
+
|
|
22
|
+
- **版本号常量** - `VERSION` 和 `APP_NAME` 常量,构建时自动注入
|
|
23
|
+
- **运行时读取** - 支持从 `package.json` 动态读取版本信息
|
|
24
|
+
- **版本比较** - 支持语义化版本号比较(如 `1.2.3` vs `1.2.4`)
|
|
25
|
+
- **格式验证** - 验证版本号是否符合语义化版本规范
|
|
26
|
+
- **缓存机制** - 内置缓存提升性能
|
|
27
|
+
|
|
28
|
+
## 安装
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 使用 npm
|
|
32
|
+
npm install @xiaozhi-client/version
|
|
33
|
+
|
|
34
|
+
# 使用 pnpm
|
|
35
|
+
pnpm add @xiaozhi-client/version
|
|
36
|
+
|
|
37
|
+
# 使用 yarn
|
|
38
|
+
yarn add @xiaozhi-client/version
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 快速开始
|
|
42
|
+
|
|
43
|
+
### 使用版本常量
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { VERSION, APP_NAME } from '@xiaozhi-client/version';
|
|
47
|
+
|
|
48
|
+
console.log(`应用名称: ${APP_NAME}`);
|
|
49
|
+
console.log(`版本号: ${VERSION}`);
|
|
50
|
+
// 输出: 应用名称: xiaozhi-client
|
|
51
|
+
// 输出: 版本号: 1.10.9
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 使用 VersionUtils
|
|
55
|
+
|
|
56
|
+
#### 获取版本信息
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { VersionUtils } from '@xiaozhi-client/version';
|
|
60
|
+
|
|
61
|
+
// 获取版本号
|
|
62
|
+
const version = VersionUtils.getVersion();
|
|
63
|
+
console.log(`当前版本: ${version}`);
|
|
64
|
+
|
|
65
|
+
// 获取完整版本信息
|
|
66
|
+
const versionInfo = VersionUtils.getVersionInfo();
|
|
67
|
+
console.log(versionInfo);
|
|
68
|
+
// 输出: {
|
|
69
|
+
// version: '1.10.9',
|
|
70
|
+
// name: 'xiaozhi-client',
|
|
71
|
+
// description: '小智 AI 客户端',
|
|
72
|
+
// author: 'shenjingnan'
|
|
73
|
+
// }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### 比较版本号
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { VersionUtils } from '@xiaozhi-client/version';
|
|
80
|
+
|
|
81
|
+
const result = VersionUtils.compareVersions('1.2.3', '1.2.4');
|
|
82
|
+
|
|
83
|
+
if (result === 1) {
|
|
84
|
+
console.log('第一个版本更新');
|
|
85
|
+
} else if (result === -1) {
|
|
86
|
+
console.log('第二个版本更新');
|
|
87
|
+
} else {
|
|
88
|
+
console.log('版本相同');
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### 验证版本格式
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { VersionUtils } from '@xiaozhi-client/version';
|
|
96
|
+
|
|
97
|
+
// 验证标准版本号
|
|
98
|
+
console.log(VersionUtils.isValidVersion('1.2.3')); // true
|
|
99
|
+
console.log(VersionUtils.isValidVersion('1.2.3-alpha')); // true
|
|
100
|
+
console.log(VersionUtils.isValidVersion('1.2.3-beta.1')); // true
|
|
101
|
+
console.log(VersionUtils.isValidVersion('1.2.3+build.1')); // true
|
|
102
|
+
console.log(VersionUtils.isValidVersion('invalid')); // false
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### 清除缓存
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { VersionUtils } from '@xiaozhi-client/version';
|
|
109
|
+
|
|
110
|
+
// 清除版本缓存(主要用于测试场景)
|
|
111
|
+
VersionUtils.clearCache();
|
|
112
|
+
|
|
113
|
+
// 重新获取版本信息
|
|
114
|
+
const freshVersion = VersionUtils.getVersion();
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## API 参考
|
|
118
|
+
|
|
119
|
+
### 常量
|
|
120
|
+
|
|
121
|
+
#### VERSION
|
|
122
|
+
|
|
123
|
+
当前版本号常量,构建时自动注入。
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
declare const VERSION: string;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### APP_NAME
|
|
130
|
+
|
|
131
|
+
应用名称常量,构建时自动注入。
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
declare const APP_NAME: string;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### VersionUtils 类
|
|
138
|
+
|
|
139
|
+
版本工具类,提供静态方法用于版本管理。
|
|
140
|
+
|
|
141
|
+
#### getVersion()
|
|
142
|
+
|
|
143
|
+
获取当前版本号。
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
static getVersion(): string
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**返回值**: 版本号字符串
|
|
150
|
+
|
|
151
|
+
**说明**:
|
|
152
|
+
- 优先使用构建时注入的版本号
|
|
153
|
+
- 如果是占位符,则运行时从 `package.json` 读取
|
|
154
|
+
- 内置缓存机制,重复调用不会重复读取
|
|
155
|
+
|
|
156
|
+
#### getVersionInfo()
|
|
157
|
+
|
|
158
|
+
获取完整版本信息。
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
static getVersionInfo(): VersionInfo
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**返回值**: 版本信息对象
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
interface VersionInfo {
|
|
168
|
+
version: string; // 版本号
|
|
169
|
+
name?: string; // 应用名称
|
|
170
|
+
description?: string; // 应用描述
|
|
171
|
+
author?: string; // 作者信息
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### compareVersions()
|
|
176
|
+
|
|
177
|
+
比较两个版本号。
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
static compareVersions(version1: string, version2: string): number
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**参数**:
|
|
184
|
+
- `version1` - 第一个版本号
|
|
185
|
+
- `version2` - 第二个版本号
|
|
186
|
+
|
|
187
|
+
**返回值**:
|
|
188
|
+
- `1` - version1 > version2
|
|
189
|
+
- `-1` - version1 < version2
|
|
190
|
+
- `0` - 版本相等
|
|
191
|
+
|
|
192
|
+
**示例**:
|
|
193
|
+
```typescript
|
|
194
|
+
VersionUtils.compareVersions('1.2.3', '1.2.4'); // -1
|
|
195
|
+
VersionUtils.compareVersions('1.2.4', '1.2.3'); // 1
|
|
196
|
+
VersionUtils.compareVersions('1.2.3', '1.2.3'); // 0
|
|
197
|
+
VersionUtils.compareVersions('1.10.0', '1.2.0'); // 1
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### isValidVersion()
|
|
201
|
+
|
|
202
|
+
检查版本号格式是否有效。
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
static isValidVersion(version: string): boolean
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**参数**:
|
|
209
|
+
- `version` - 版本号字符串
|
|
210
|
+
|
|
211
|
+
**返回值**: 是否为有效的语义化版本号
|
|
212
|
+
|
|
213
|
+
**支持的格式**:
|
|
214
|
+
- 标准版本号: `1.2.3`
|
|
215
|
+
- 带预发布标识: `1.2.3-alpha`, `1.2.3-beta.1`
|
|
216
|
+
- 带构建元数据: `1.2.3+build.123`
|
|
217
|
+
- 完整格式: `1.2.3-alpha.1+build.123`
|
|
218
|
+
|
|
219
|
+
#### clearCache()
|
|
220
|
+
|
|
221
|
+
清除版本缓存。
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
static clearCache(): void
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**说明**: 主要用于测试场景,清除后下次调用会重新读取版本信息。
|
|
228
|
+
|
|
229
|
+
## 类型定义
|
|
230
|
+
|
|
231
|
+
### VersionInfo
|
|
232
|
+
|
|
233
|
+
版本信息接口。
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
interface VersionInfo {
|
|
237
|
+
version: string; // 版本号(必需)
|
|
238
|
+
name?: string; // 应用名称(可选)
|
|
239
|
+
description?: string; // 应用描述(可选)
|
|
240
|
+
author?: string; // 作者信息(可选)
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 使用场景
|
|
245
|
+
|
|
246
|
+
### 检查版本更新
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { VersionUtils } from '@xiaozhi-client/version';
|
|
250
|
+
|
|
251
|
+
async function checkForUpdates() {
|
|
252
|
+
const currentVersion = VersionUtils.getVersion();
|
|
253
|
+
const latestVersion = await fetchLatestVersion();
|
|
254
|
+
|
|
255
|
+
if (VersionUtils.compareVersions(latestVersion, currentVersion) === 1) {
|
|
256
|
+
console.log('发现新版本,请更新!');
|
|
257
|
+
showUpdateNotification(latestVersion);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 版本兼容性检查
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { VersionUtils } from '@xiaozhi-client/version';
|
|
266
|
+
|
|
267
|
+
function checkCompatibility(requiredVersion: string): boolean {
|
|
268
|
+
const currentVersion = VersionUtils.getVersion();
|
|
269
|
+
|
|
270
|
+
if (!VersionUtils.isValidVersion(requiredVersion)) {
|
|
271
|
+
throw new Error('无效的版本号格式');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return VersionUtils.compareVersions(currentVersion, requiredVersion) >= 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 使用示例
|
|
278
|
+
if (checkCompatibility('1.10.0')) {
|
|
279
|
+
console.log('版本兼容,可以继续');
|
|
280
|
+
} else {
|
|
281
|
+
console.log('版本过低,请升级');
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### CLI 版本显示
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { VERSION, APP_NAME, VersionUtils } from '@xiaozhi-client/version';
|
|
289
|
+
|
|
290
|
+
function showVersion() {
|
|
291
|
+
const info = VersionUtils.getVersionInfo();
|
|
292
|
+
|
|
293
|
+
console.log(`${info.name} v${info.version}`);
|
|
294
|
+
if (info.description) {
|
|
295
|
+
console.log(info.description);
|
|
296
|
+
}
|
|
297
|
+
if (info.author) {
|
|
298
|
+
console.log(`作者: ${info.author}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 输出示例:
|
|
303
|
+
// xiaozhi-client v1.10.9
|
|
304
|
+
// 小智 AI 客户端
|
|
305
|
+
// 作者: shenjingnan
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## 版本号注入机制
|
|
309
|
+
|
|
310
|
+
本包支持两种版本号获取方式:
|
|
311
|
+
|
|
312
|
+
### 构建时注入(推荐)
|
|
313
|
+
|
|
314
|
+
构建时通过 `tsup` 的 `define` 选项注入版本号:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// tsup.config.ts
|
|
318
|
+
{
|
|
319
|
+
define: {
|
|
320
|
+
__VERSION__: `"${packageJson.version}"`,
|
|
321
|
+
__APP_NAME__: `"${packageJson.name}"`
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
优点:
|
|
327
|
+
- 构建后版本号固定
|
|
328
|
+
- 无运行时文件读取开销
|
|
329
|
+
- 适合生产环境
|
|
330
|
+
|
|
331
|
+
### 运行时读取
|
|
332
|
+
|
|
333
|
+
如果构建时未注入版本号,包会自动从 `package.json` 读取:
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// 逻辑:VERSION === "__VERSION__" → 运行时读取
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
优点:
|
|
340
|
+
- 开发环境方便
|
|
341
|
+
- 无需额外配置
|
|
342
|
+
|
|
343
|
+
## 开发指南
|
|
344
|
+
|
|
345
|
+
### 本地开发
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# 克隆仓库
|
|
349
|
+
git clone https://github.com/shenjingnan/xiaozhi-client.git
|
|
350
|
+
cd xiaozhi-client/packages/version
|
|
351
|
+
|
|
352
|
+
# 安装依赖
|
|
353
|
+
pnpm install
|
|
354
|
+
|
|
355
|
+
# 构建
|
|
356
|
+
pnpm build
|
|
357
|
+
|
|
358
|
+
# 运行测试
|
|
359
|
+
pnpm test
|
|
360
|
+
|
|
361
|
+
# 类型检查
|
|
362
|
+
pnpm type-check
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 构建产物
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
dist/
|
|
369
|
+
├── index.js # ESM 格式的编译产物
|
|
370
|
+
├── index.d.ts # TypeScript 类型声明
|
|
371
|
+
└── index.js.map # Source Map
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## 常见问题
|
|
375
|
+
|
|
376
|
+
### Q: 如何获取当前运行时的版本号?
|
|
377
|
+
|
|
378
|
+
A: 使用 `VersionUtils.getVersion()` 方法:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
const version = VersionUtils.getVersion();
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Q: 如何比较两个版本号?
|
|
385
|
+
|
|
386
|
+
A: 使用 `VersionUtils.compareVersions()` 方法:
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
const result = VersionUtils.compareVersions('1.2.3', '1.2.4');
|
|
390
|
+
// result: -1 (表示 1.2.3 < 1.2.4)
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Q: 为什么版本号是 `__VERSION__` 占位符?
|
|
394
|
+
|
|
395
|
+
A: 这表示构建时未正确注入版本号。请检查 `tsup.config.ts` 中的 `define` 配置,或使用运行时读取模式。
|
|
396
|
+
|
|
397
|
+
### Q: 版本号是否支持预发布标识?
|
|
398
|
+
|
|
399
|
+
A: 验证功能支持预发布标识格式(如 `1.2.3-alpha`),但比较功能仅比较数字部分。
|
|
400
|
+
|
|
401
|
+
## 许可证
|
|
402
|
+
|
|
403
|
+
[MIT](LICENSE)
|
|
404
|
+
|
|
405
|
+
## 相关资源
|
|
406
|
+
|
|
407
|
+
- [小智客户端](https://github.com/shenjingnan/xiaozhi-client)
|
|
408
|
+
- [语义化版本规范](https://semver.org/lang/zh-CN/)
|
|
409
|
+
- [问题反馈](https://github.com/shenjingnan/xiaozhi-client/issues)
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
**作者**: xiaozhi-client
|
|
414
|
+
**版本**: 1.10.9
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,14 @@ declare class VersionUtils {
|
|
|
53
53
|
* @returns 是否为有效的语义化版本号
|
|
54
54
|
*/
|
|
55
55
|
static isValidVersion(version: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* 查找 package.json 文件路径
|
|
58
|
+
*
|
|
59
|
+
* 尝试从多个可能的路径中查找 package.json 文件
|
|
60
|
+
*
|
|
61
|
+
* @returns package.json 文件路径,如果找不到则返回 null
|
|
62
|
+
*/
|
|
63
|
+
private static findPackageJsonPath;
|
|
56
64
|
/**
|
|
57
65
|
* 运行时从 package.json 读取版本号
|
|
58
66
|
*/
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// src/version-constants.ts
|
|
5
|
-
var VERSION = "
|
|
5
|
+
var VERSION = "2.0.0-beta.1";
|
|
6
6
|
var APP_NAME = "xiaozhi-client";
|
|
7
7
|
|
|
8
8
|
// src/VersionUtils.ts
|
|
@@ -73,6 +73,31 @@ var VersionUtils = class _VersionUtils {
|
|
|
73
73
|
const versionRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
|
|
74
74
|
return versionRegex.test(version);
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* 查找 package.json 文件路径
|
|
78
|
+
*
|
|
79
|
+
* 尝试从多个可能的路径中查找 package.json 文件
|
|
80
|
+
*
|
|
81
|
+
* @returns package.json 文件路径,如果找不到则返回 null
|
|
82
|
+
*/
|
|
83
|
+
static findPackageJsonPath() {
|
|
84
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
85
|
+
const currentDir = path.dirname(__filename);
|
|
86
|
+
const possiblePaths = [
|
|
87
|
+
// 从 packages/version/dist/version/index.js 到项目根目录的 package.json
|
|
88
|
+
path.join(currentDir, "..", "..", "..", "package.json"),
|
|
89
|
+
// 从 dist/version/index.js 到项目根目录的 package.json
|
|
90
|
+
path.join(currentDir, "..", "..", "package.json"),
|
|
91
|
+
// 全局安装环境
|
|
92
|
+
path.join(currentDir, "..", "..", "..", "..", "package.json")
|
|
93
|
+
];
|
|
94
|
+
for (const packagePath of possiblePaths) {
|
|
95
|
+
if (fs.existsSync(packagePath)) {
|
|
96
|
+
return packagePath;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
76
101
|
/**
|
|
77
102
|
* 运行时从 package.json 读取版本号
|
|
78
103
|
*/
|
|
@@ -81,23 +106,12 @@ var VersionUtils = class _VersionUtils {
|
|
|
81
106
|
return _VersionUtils.cachedVersion;
|
|
82
107
|
}
|
|
83
108
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
path.join(currentDir, "..", "..", "package.json"),
|
|
91
|
-
// 全局安装环境
|
|
92
|
-
path.join(currentDir, "..", "..", "..", "..", "package.json")
|
|
93
|
-
];
|
|
94
|
-
for (const packagePath of possiblePaths) {
|
|
95
|
-
if (fs.existsSync(packagePath)) {
|
|
96
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
97
|
-
if (packageJson.version) {
|
|
98
|
-
_VersionUtils.cachedVersion = packageJson.version;
|
|
99
|
-
return packageJson.version;
|
|
100
|
-
}
|
|
109
|
+
const packagePath = _VersionUtils.findPackageJsonPath();
|
|
110
|
+
if (packagePath) {
|
|
111
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
112
|
+
if (packageJson.version) {
|
|
113
|
+
_VersionUtils.cachedVersion = packageJson.version;
|
|
114
|
+
return packageJson.version;
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
117
|
_VersionUtils.cachedVersion = "unknown";
|
|
@@ -113,26 +127,15 @@ var VersionUtils = class _VersionUtils {
|
|
|
113
127
|
*/
|
|
114
128
|
static getRuntimeVersionInfo() {
|
|
115
129
|
try {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
];
|
|
126
|
-
for (const packagePath of possiblePaths) {
|
|
127
|
-
if (fs.existsSync(packagePath)) {
|
|
128
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
129
|
-
return {
|
|
130
|
-
version: packageJson.version || "unknown",
|
|
131
|
-
name: packageJson.name,
|
|
132
|
-
description: packageJson.description,
|
|
133
|
-
author: packageJson.author
|
|
134
|
-
};
|
|
135
|
-
}
|
|
130
|
+
const packagePath = _VersionUtils.findPackageJsonPath();
|
|
131
|
+
if (packagePath) {
|
|
132
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
133
|
+
return {
|
|
134
|
+
version: packageJson.version || "unknown",
|
|
135
|
+
name: packageJson.name,
|
|
136
|
+
description: packageJson.description,
|
|
137
|
+
author: packageJson.author
|
|
138
|
+
};
|
|
136
139
|
}
|
|
137
140
|
return { version: "unknown" };
|
|
138
141
|
} catch (error) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version-constants.ts","../src/VersionUtils.ts"],"sourcesContent":["/**\n * 版本号常量(构建时注入)\n *\n * 如果构建时能读取到 package.json,则为真实版本号\n * 否则为占位符,运行时从 package.json 读取\n */\nexport const VERSION = __VERSION__;\nexport const APP_NAME = __APP_NAME__;\n","/**\n * 版本管理工具\n *\n * 提供版本号获取、比较、验证等功能\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/version-constants.ts","../src/VersionUtils.ts"],"sourcesContent":["/**\n * 版本号常量(构建时注入)\n *\n * 如果构建时能读取到 package.json,则为真实版本号\n * 否则为占位符,运行时从 package.json 读取\n */\nexport const VERSION = __VERSION__;\nexport const APP_NAME = __APP_NAME__;\n","/**\n * 版本管理工具\n *\n * 提供版本号获取、比较、验证等功能\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { APP_NAME, VERSION } from \"./version-constants.js\";\n\n/**\n * 版本信息接口\n */\nexport interface VersionInfo {\n version: string;\n name?: string;\n description?: string;\n author?: string;\n}\n\n/**\n * 版本工具类\n */\nexport class VersionUtils {\n private static cachedVersion: string | null = null;\n private static cachedVersionInfo: VersionInfo | null = null;\n\n /**\n * 获取版本号\n *\n * 优先使用构建时注入的版本号常量\n * 如果是占位符,则运行时从 package.json 读取\n */\n static getVersion(): string {\n // 如果版本号是占位符,则运行时读取\n if (VERSION === \"__VERSION__\") {\n return VersionUtils.getRuntimeVersion();\n }\n\n // 使用构建时注入的版本号\n return VERSION;\n }\n\n /**\n * 获取完整版本信息\n */\n static getVersionInfo(): VersionInfo {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersionInfo) {\n return VersionUtils.cachedVersionInfo;\n }\n\n // 如果版本号是占位符,则运行时读取\n if (VERSION === \"__VERSION__\") {\n VersionUtils.cachedVersionInfo = VersionUtils.getRuntimeVersionInfo();\n return VersionUtils.cachedVersionInfo;\n }\n\n // 使用构建时注入的版本号\n VersionUtils.cachedVersionInfo = {\n version: VERSION,\n name: APP_NAME === \"__APP_NAME__\" ? undefined : APP_NAME,\n };\n\n return VersionUtils.cachedVersionInfo;\n }\n\n /**\n * 比较版本号\n *\n * @param version1 第一个版本号\n * @param version2 第二个版本号\n * @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等\n */\n static compareVersions(version1: string, version2: string): number {\n const v1Parts = version1.split(\".\").map(Number);\n const v2Parts = version2.split(\".\").map(Number);\n const maxLength = Math.max(v1Parts.length, v2Parts.length);\n\n for (let i = 0; i < maxLength; i++) {\n const v1Part = v1Parts[i] || 0;\n const v2Part = v2Parts[i] || 0;\n\n if (v1Part > v2Part) return 1;\n if (v1Part < v2Part) return -1;\n }\n\n return 0;\n }\n\n /**\n * 检查版本是否有效\n *\n * @param version 版本号字符串\n * @returns 是否为有效的语义化版本号\n */\n static isValidVersion(version: string): boolean {\n // 支持语义化版本号:1.2.3 或 1.2.3-alpha.1 或 1.2.3-beta.1+build.123\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$/;\n return versionRegex.test(version);\n }\n\n /**\n * 查找 package.json 文件路径\n *\n * 尝试从多个可能的路径中查找 package.json 文件\n *\n * @returns package.json 文件路径,如果找不到则返回 null\n */\n private static findPackageJsonPath(): string | null {\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n const possiblePaths = [\n // 从 packages/version/dist/version/index.js 到项目根目录的 package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 从 dist/version/index.js 到项目根目录的 package.json\n path.join(currentDir, \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n return packagePath;\n }\n }\n\n return null;\n }\n\n /**\n * 运行时从 package.json 读取版本号\n */\n private static getRuntimeVersion(): string {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n const packagePath = VersionUtils.findPackageJsonPath();\n if (packagePath) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n if (packageJson.version) {\n VersionUtils.cachedVersion = packageJson.version;\n return packageJson.version;\n }\n }\n\n // 如果都找不到,返回默认版本\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n } catch (error) {\n console.warn(\"无法从 package.json 读取版本信息:\", error);\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n }\n }\n\n /**\n * 运行时从 package.json 读取完整版本信息\n */\n private static getRuntimeVersionInfo(): VersionInfo {\n try {\n const packagePath = VersionUtils.findPackageJsonPath();\n if (packagePath) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n return {\n version: packageJson.version || \"unknown\",\n name: packageJson.name,\n description: packageJson.description,\n author: packageJson.author,\n };\n }\n\n return { version: \"unknown\" };\n } catch (error) {\n console.warn(\"无法读取版本信息:\", error);\n return { version: \"unknown\" };\n }\n }\n\n /**\n * 清除版本缓存\n *\n * 主要用于测试场景\n */\n static clearCache(): void {\n VersionUtils.cachedVersion = null;\n VersionUtils.cachedVersionInfo = null;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
package/src/VersionUtils.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import {
|
|
10
|
+
import { APP_NAME, VERSION } from "./version-constants.js";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* 版本信息接口
|
|
@@ -101,6 +101,35 @@ export class VersionUtils {
|
|
|
101
101
|
return versionRegex.test(version);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* 查找 package.json 文件路径
|
|
106
|
+
*
|
|
107
|
+
* 尝试从多个可能的路径中查找 package.json 文件
|
|
108
|
+
*
|
|
109
|
+
* @returns package.json 文件路径,如果找不到则返回 null
|
|
110
|
+
*/
|
|
111
|
+
private static findPackageJsonPath(): string | null {
|
|
112
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
113
|
+
const currentDir = path.dirname(__filename);
|
|
114
|
+
|
|
115
|
+
const possiblePaths = [
|
|
116
|
+
// 从 packages/version/dist/version/index.js 到项目根目录的 package.json
|
|
117
|
+
path.join(currentDir, "..", "..", "..", "package.json"),
|
|
118
|
+
// 从 dist/version/index.js 到项目根目录的 package.json
|
|
119
|
+
path.join(currentDir, "..", "..", "package.json"),
|
|
120
|
+
// 全局安装环境
|
|
121
|
+
path.join(currentDir, "..", "..", "..", "..", "package.json"),
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
for (const packagePath of possiblePaths) {
|
|
125
|
+
if (fs.existsSync(packagePath)) {
|
|
126
|
+
return packagePath;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
104
133
|
/**
|
|
105
134
|
* 运行时从 package.json 读取版本号
|
|
106
135
|
*/
|
|
@@ -111,27 +140,12 @@ export class VersionUtils {
|
|
|
111
140
|
}
|
|
112
141
|
|
|
113
142
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// 从 packages/version/dist/version/index.js 到项目根目录的 package.json
|
|
121
|
-
path.join(currentDir, "..", "..", "..", "package.json"),
|
|
122
|
-
// 从 dist/version/index.js 到项目根目录的 package.json
|
|
123
|
-
path.join(currentDir, "..", "..", "package.json"),
|
|
124
|
-
// 全局安装环境
|
|
125
|
-
path.join(currentDir, "..", "..", "..", "..", "package.json"),
|
|
126
|
-
];
|
|
127
|
-
|
|
128
|
-
for (const packagePath of possiblePaths) {
|
|
129
|
-
if (fs.existsSync(packagePath)) {
|
|
130
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
131
|
-
if (packageJson.version) {
|
|
132
|
-
VersionUtils.cachedVersion = packageJson.version;
|
|
133
|
-
return packageJson.version;
|
|
134
|
-
}
|
|
143
|
+
const packagePath = VersionUtils.findPackageJsonPath();
|
|
144
|
+
if (packagePath) {
|
|
145
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
146
|
+
if (packageJson.version) {
|
|
147
|
+
VersionUtils.cachedVersion = packageJson.version;
|
|
148
|
+
return packageJson.version;
|
|
135
149
|
}
|
|
136
150
|
}
|
|
137
151
|
|
|
@@ -150,28 +164,15 @@ export class VersionUtils {
|
|
|
150
164
|
*/
|
|
151
165
|
private static getRuntimeVersionInfo(): VersionInfo {
|
|
152
166
|
try {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
path.join(currentDir, "..", "..", "..", "..", "package.json"),
|
|
163
|
-
];
|
|
164
|
-
|
|
165
|
-
for (const packagePath of possiblePaths) {
|
|
166
|
-
if (fs.existsSync(packagePath)) {
|
|
167
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
168
|
-
return {
|
|
169
|
-
version: packageJson.version || "unknown",
|
|
170
|
-
name: packageJson.name,
|
|
171
|
-
description: packageJson.description,
|
|
172
|
-
author: packageJson.author,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
167
|
+
const packagePath = VersionUtils.findPackageJsonPath();
|
|
168
|
+
if (packagePath) {
|
|
169
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
170
|
+
return {
|
|
171
|
+
version: packageJson.version || "unknown",
|
|
172
|
+
name: packageJson.name,
|
|
173
|
+
description: packageJson.description,
|
|
174
|
+
author: packageJson.author,
|
|
175
|
+
};
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
return { version: "unknown" };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* VersionUtils 单元测试
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
6
6
|
import { VersionUtils } from "../VersionUtils.js";
|
|
7
7
|
|
|
8
8
|
describe("VersionUtils", () => {
|
|
@@ -21,8 +21,7 @@ describe("VersionUtils", () => {
|
|
|
21
21
|
it("应该返回有效的版本号格式", () => {
|
|
22
22
|
const version = VersionUtils.getVersion();
|
|
23
23
|
// 版本号应该是数字点分隔格式,或者 "unknown"
|
|
24
|
-
const isValid =
|
|
25
|
-
version === "unknown" || /^\d+\.\d+\.\d+/.test(version);
|
|
24
|
+
const isValid = version === "unknown" || /^\d+\.\d+\.\d+/.test(version);
|
|
26
25
|
expect(isValid).toBe(true);
|
|
27
26
|
});
|
|
28
27
|
|
|
@@ -151,7 +150,9 @@ describe("VersionUtils", () => {
|
|
|
151
150
|
|
|
152
151
|
it("应该接受带预发布和构建元数据的版本号", () => {
|
|
153
152
|
expect(VersionUtils.isValidVersion("1.0.0-alpha+001")).toBe(true);
|
|
154
|
-
expect(VersionUtils.isValidVersion("1.0.0-beta+exp.sha.5114f85")).toBe(
|
|
153
|
+
expect(VersionUtils.isValidVersion("1.0.0-beta+exp.sha.5114f85")).toBe(
|
|
154
|
+
true
|
|
155
|
+
);
|
|
155
156
|
});
|
|
156
157
|
|
|
157
158
|
it("应该拒绝无效的版本号", () => {
|
|
@@ -208,7 +209,9 @@ describe("VersionUtils", () => {
|
|
|
208
209
|
// 获取版本号,即使在某些环境中无法读取 package.json
|
|
209
210
|
// 也应该返回 "unknown" 或有效的版本号
|
|
210
211
|
const version = VersionUtils.getVersion();
|
|
211
|
-
expect(
|
|
212
|
+
expect(
|
|
213
|
+
["unknown", "1.9.7"].includes(version) || /^\d+\.\d+\.\d+/.test(version)
|
|
214
|
+
).toBe(true);
|
|
212
215
|
});
|
|
213
216
|
|
|
214
217
|
it("应该处理 getRuntimeVersionInfo 的错误情况", () => {
|