@xiaozhi-client/version 1.9.7-beta.21
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/LICENSE +21 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +158 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
- package/src/VersionUtils.ts +193 -0
- package/src/__tests__/VersionUtils.test.ts +225 -0
- package/src/global.d.ts +7 -0
- package/src/index.ts +11 -0
- package/src/version-constants.ts +8 -0
- package/tsconfig.json +27 -0
- package/tsup.config.ts +48 -0
- package/vitest.config.ts +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 shenjingnan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 版本号常量(构建时注入)
|
|
3
|
+
*
|
|
4
|
+
* 如果构建时能读取到 package.json,则为真实版本号
|
|
5
|
+
* 否则为占位符,运行时从 package.json 读取
|
|
6
|
+
*/
|
|
7
|
+
declare const VERSION: string;
|
|
8
|
+
declare const APP_NAME: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 版本管理工具
|
|
12
|
+
*
|
|
13
|
+
* 提供版本号获取、比较、验证等功能
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* 版本信息接口
|
|
17
|
+
*/
|
|
18
|
+
interface VersionInfo {
|
|
19
|
+
version: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
author?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 版本工具类
|
|
26
|
+
*/
|
|
27
|
+
declare class VersionUtils {
|
|
28
|
+
private static cachedVersion;
|
|
29
|
+
private static cachedVersionInfo;
|
|
30
|
+
/**
|
|
31
|
+
* 获取版本号
|
|
32
|
+
*
|
|
33
|
+
* 优先使用构建时注入的版本号常量
|
|
34
|
+
* 如果是占位符,则运行时从 package.json 读取
|
|
35
|
+
*/
|
|
36
|
+
static getVersion(): string;
|
|
37
|
+
/**
|
|
38
|
+
* 获取完整版本信息
|
|
39
|
+
*/
|
|
40
|
+
static getVersionInfo(): VersionInfo;
|
|
41
|
+
/**
|
|
42
|
+
* 比较版本号
|
|
43
|
+
*
|
|
44
|
+
* @param version1 第一个版本号
|
|
45
|
+
* @param version2 第二个版本号
|
|
46
|
+
* @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等
|
|
47
|
+
*/
|
|
48
|
+
static compareVersions(version1: string, version2: string): number;
|
|
49
|
+
/**
|
|
50
|
+
* 检查版本是否有效
|
|
51
|
+
*
|
|
52
|
+
* @param version 版本号字符串
|
|
53
|
+
* @returns 是否为有效的语义化版本号
|
|
54
|
+
*/
|
|
55
|
+
static isValidVersion(version: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* 运行时从 package.json 读取版本号
|
|
58
|
+
*/
|
|
59
|
+
private static getRuntimeVersion;
|
|
60
|
+
/**
|
|
61
|
+
* 运行时从 package.json 读取完整版本信息
|
|
62
|
+
*/
|
|
63
|
+
private static getRuntimeVersionInfo;
|
|
64
|
+
/**
|
|
65
|
+
* 清除版本缓存
|
|
66
|
+
*
|
|
67
|
+
* 主要用于测试场景
|
|
68
|
+
*/
|
|
69
|
+
static clearCache(): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { APP_NAME, VERSION, type VersionInfo, VersionUtils };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/version-constants.ts
|
|
5
|
+
var VERSION = "1.9.7-beta.21";
|
|
6
|
+
var APP_NAME = "xiaozhi-client";
|
|
7
|
+
|
|
8
|
+
// src/VersionUtils.ts
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
var VersionUtils = class _VersionUtils {
|
|
13
|
+
static {
|
|
14
|
+
__name(this, "VersionUtils");
|
|
15
|
+
}
|
|
16
|
+
static cachedVersion = null;
|
|
17
|
+
static cachedVersionInfo = null;
|
|
18
|
+
/**
|
|
19
|
+
* 获取版本号
|
|
20
|
+
*
|
|
21
|
+
* 优先使用构建时注入的版本号常量
|
|
22
|
+
* 如果是占位符,则运行时从 package.json 读取
|
|
23
|
+
*/
|
|
24
|
+
static getVersion() {
|
|
25
|
+
if (VERSION === "__VERSION__") {
|
|
26
|
+
return _VersionUtils.getRuntimeVersion();
|
|
27
|
+
}
|
|
28
|
+
return VERSION;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 获取完整版本信息
|
|
32
|
+
*/
|
|
33
|
+
static getVersionInfo() {
|
|
34
|
+
if (_VersionUtils.cachedVersionInfo) {
|
|
35
|
+
return _VersionUtils.cachedVersionInfo;
|
|
36
|
+
}
|
|
37
|
+
if (VERSION === "__VERSION__") {
|
|
38
|
+
_VersionUtils.cachedVersionInfo = _VersionUtils.getRuntimeVersionInfo();
|
|
39
|
+
return _VersionUtils.cachedVersionInfo;
|
|
40
|
+
}
|
|
41
|
+
_VersionUtils.cachedVersionInfo = {
|
|
42
|
+
version: VERSION,
|
|
43
|
+
name: APP_NAME === "__APP_NAME__" ? void 0 : APP_NAME
|
|
44
|
+
};
|
|
45
|
+
return _VersionUtils.cachedVersionInfo;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 比较版本号
|
|
49
|
+
*
|
|
50
|
+
* @param version1 第一个版本号
|
|
51
|
+
* @param version2 第二个版本号
|
|
52
|
+
* @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等
|
|
53
|
+
*/
|
|
54
|
+
static compareVersions(version1, version2) {
|
|
55
|
+
const v1Parts = version1.split(".").map(Number);
|
|
56
|
+
const v2Parts = version2.split(".").map(Number);
|
|
57
|
+
const maxLength = Math.max(v1Parts.length, v2Parts.length);
|
|
58
|
+
for (let i = 0; i < maxLength; i++) {
|
|
59
|
+
const v1Part = v1Parts[i] || 0;
|
|
60
|
+
const v2Part = v2Parts[i] || 0;
|
|
61
|
+
if (v1Part > v2Part) return 1;
|
|
62
|
+
if (v1Part < v2Part) return -1;
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 检查版本是否有效
|
|
68
|
+
*
|
|
69
|
+
* @param version 版本号字符串
|
|
70
|
+
* @returns 是否为有效的语义化版本号
|
|
71
|
+
*/
|
|
72
|
+
static isValidVersion(version) {
|
|
73
|
+
const versionRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
|
|
74
|
+
return versionRegex.test(version);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 运行时从 package.json 读取版本号
|
|
78
|
+
*/
|
|
79
|
+
static getRuntimeVersion() {
|
|
80
|
+
if (_VersionUtils.cachedVersion) {
|
|
81
|
+
return _VersionUtils.cachedVersion;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
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
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
97
|
+
if (packageJson.version) {
|
|
98
|
+
_VersionUtils.cachedVersion = packageJson.version;
|
|
99
|
+
return packageJson.version;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
_VersionUtils.cachedVersion = "unknown";
|
|
104
|
+
return "unknown";
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.warn("\u65E0\u6CD5\u4ECE package.json \u8BFB\u53D6\u7248\u672C\u4FE1\u606F:", error);
|
|
107
|
+
_VersionUtils.cachedVersion = "unknown";
|
|
108
|
+
return "unknown";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 运行时从 package.json 读取完整版本信息
|
|
113
|
+
*/
|
|
114
|
+
static getRuntimeVersionInfo() {
|
|
115
|
+
try {
|
|
116
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
117
|
+
const currentDir = path.dirname(__filename);
|
|
118
|
+
const possiblePaths = [
|
|
119
|
+
// 从 packages/version/dist/version/index.js 到项目根目录的 package.json
|
|
120
|
+
path.join(currentDir, "..", "..", "..", "package.json"),
|
|
121
|
+
// 从 dist/version/index.js 到项目根目录的 package.json
|
|
122
|
+
path.join(currentDir, "..", "..", "package.json"),
|
|
123
|
+
// 全局安装环境
|
|
124
|
+
path.join(currentDir, "..", "..", "..", "..", "package.json")
|
|
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
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { version: "unknown" };
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.warn("\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C\u4FE1\u606F:", error);
|
|
140
|
+
return { version: "unknown" };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 清除版本缓存
|
|
145
|
+
*
|
|
146
|
+
* 主要用于测试场景
|
|
147
|
+
*/
|
|
148
|
+
static clearCache() {
|
|
149
|
+
_VersionUtils.cachedVersion = null;
|
|
150
|
+
_VersionUtils.cachedVersionInfo = null;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
export {
|
|
154
|
+
APP_NAME,
|
|
155
|
+
VERSION,
|
|
156
|
+
VersionUtils
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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 { VERSION, APP_NAME } 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 private static getRuntimeVersion(): string {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n // 尝试多个可能的 package.json 路径\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 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 // 如果都找不到,返回默认版本\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 __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 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\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
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xiaozhi-client/version",
|
|
3
|
+
"version": "1.9.7-beta.21",
|
|
4
|
+
"private": false,
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/shenjingnan/xiaozhi-client.git",
|
|
8
|
+
"directory": "packages/version"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^24.3.0",
|
|
25
|
+
"typescript": "^5.9.2",
|
|
26
|
+
"vitest": "^3.0.5"
|
|
27
|
+
},
|
|
28
|
+
"nx": {
|
|
29
|
+
"targets": {
|
|
30
|
+
"build": {
|
|
31
|
+
"dependsOn": [
|
|
32
|
+
"^build"
|
|
33
|
+
],
|
|
34
|
+
"outputs": [
|
|
35
|
+
"{projectRoot}/dist"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"test": {
|
|
39
|
+
"outputs": [
|
|
40
|
+
"{workspaceRoot}/coverage/version"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup",
|
|
47
|
+
"test": "vitest",
|
|
48
|
+
"type-check": "tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 版本管理工具
|
|
3
|
+
*
|
|
4
|
+
* 提供版本号获取、比较、验证等功能
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { VERSION, APP_NAME } from "./version-constants.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 版本信息接口
|
|
14
|
+
*/
|
|
15
|
+
export interface VersionInfo {
|
|
16
|
+
version: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
author?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 版本工具类
|
|
24
|
+
*/
|
|
25
|
+
export class VersionUtils {
|
|
26
|
+
private static cachedVersion: string | null = null;
|
|
27
|
+
private static cachedVersionInfo: VersionInfo | null = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 获取版本号
|
|
31
|
+
*
|
|
32
|
+
* 优先使用构建时注入的版本号常量
|
|
33
|
+
* 如果是占位符,则运行时从 package.json 读取
|
|
34
|
+
*/
|
|
35
|
+
static getVersion(): string {
|
|
36
|
+
// 如果版本号是占位符,则运行时读取
|
|
37
|
+
if (VERSION === "__VERSION__") {
|
|
38
|
+
return VersionUtils.getRuntimeVersion();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 使用构建时注入的版本号
|
|
42
|
+
return VERSION;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 获取完整版本信息
|
|
47
|
+
*/
|
|
48
|
+
static getVersionInfo(): VersionInfo {
|
|
49
|
+
// 如果有缓存,直接返回
|
|
50
|
+
if (VersionUtils.cachedVersionInfo) {
|
|
51
|
+
return VersionUtils.cachedVersionInfo;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 如果版本号是占位符,则运行时读取
|
|
55
|
+
if (VERSION === "__VERSION__") {
|
|
56
|
+
VersionUtils.cachedVersionInfo = VersionUtils.getRuntimeVersionInfo();
|
|
57
|
+
return VersionUtils.cachedVersionInfo;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 使用构建时注入的版本号
|
|
61
|
+
VersionUtils.cachedVersionInfo = {
|
|
62
|
+
version: VERSION,
|
|
63
|
+
name: APP_NAME === "__APP_NAME__" ? undefined : APP_NAME,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return VersionUtils.cachedVersionInfo;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 比较版本号
|
|
71
|
+
*
|
|
72
|
+
* @param version1 第一个版本号
|
|
73
|
+
* @param version2 第二个版本号
|
|
74
|
+
* @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等
|
|
75
|
+
*/
|
|
76
|
+
static compareVersions(version1: string, version2: string): number {
|
|
77
|
+
const v1Parts = version1.split(".").map(Number);
|
|
78
|
+
const v2Parts = version2.split(".").map(Number);
|
|
79
|
+
const maxLength = Math.max(v1Parts.length, v2Parts.length);
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < maxLength; i++) {
|
|
82
|
+
const v1Part = v1Parts[i] || 0;
|
|
83
|
+
const v2Part = v2Parts[i] || 0;
|
|
84
|
+
|
|
85
|
+
if (v1Part > v2Part) return 1;
|
|
86
|
+
if (v1Part < v2Part) return -1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 检查版本是否有效
|
|
94
|
+
*
|
|
95
|
+
* @param version 版本号字符串
|
|
96
|
+
* @returns 是否为有效的语义化版本号
|
|
97
|
+
*/
|
|
98
|
+
static isValidVersion(version: string): boolean {
|
|
99
|
+
// 支持语义化版本号:1.2.3 或 1.2.3-alpha.1 或 1.2.3-beta.1+build.123
|
|
100
|
+
const versionRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
|
|
101
|
+
return versionRegex.test(version);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 运行时从 package.json 读取版本号
|
|
106
|
+
*/
|
|
107
|
+
private static getRuntimeVersion(): string {
|
|
108
|
+
// 如果有缓存,直接返回
|
|
109
|
+
if (VersionUtils.cachedVersion) {
|
|
110
|
+
return VersionUtils.cachedVersion;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// 在 ES 模块环境中获取当前目录
|
|
115
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
116
|
+
const currentDir = path.dirname(__filename);
|
|
117
|
+
|
|
118
|
+
// 尝试多个可能的 package.json 路径
|
|
119
|
+
const possiblePaths = [
|
|
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
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 如果都找不到,返回默认版本
|
|
139
|
+
VersionUtils.cachedVersion = "unknown";
|
|
140
|
+
return "unknown";
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.warn("无法从 package.json 读取版本信息:", error);
|
|
143
|
+
VersionUtils.cachedVersion = "unknown";
|
|
144
|
+
return "unknown";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 运行时从 package.json 读取完整版本信息
|
|
150
|
+
*/
|
|
151
|
+
private static getRuntimeVersionInfo(): VersionInfo {
|
|
152
|
+
try {
|
|
153
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
154
|
+
const currentDir = path.dirname(__filename);
|
|
155
|
+
|
|
156
|
+
const possiblePaths = [
|
|
157
|
+
// 从 packages/version/dist/version/index.js 到项目根目录的 package.json
|
|
158
|
+
path.join(currentDir, "..", "..", "..", "package.json"),
|
|
159
|
+
// 从 dist/version/index.js 到项目根目录的 package.json
|
|
160
|
+
path.join(currentDir, "..", "..", "package.json"),
|
|
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
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { version: "unknown" };
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.warn("无法读取版本信息:", error);
|
|
180
|
+
return { version: "unknown" };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 清除版本缓存
|
|
186
|
+
*
|
|
187
|
+
* 主要用于测试场景
|
|
188
|
+
*/
|
|
189
|
+
static clearCache(): void {
|
|
190
|
+
VersionUtils.cachedVersion = null;
|
|
191
|
+
VersionUtils.cachedVersionInfo = null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VersionUtils 单元测试
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
6
|
+
import { VersionUtils } from "../VersionUtils.js";
|
|
7
|
+
|
|
8
|
+
describe("VersionUtils", () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// 清除缓存以确保每个测试独立运行
|
|
11
|
+
VersionUtils.clearCache();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe("getVersion", () => {
|
|
15
|
+
it("应该返回版本号字符串", () => {
|
|
16
|
+
const version = VersionUtils.getVersion();
|
|
17
|
+
expect(typeof version).toBe("string");
|
|
18
|
+
expect(version.length).toBeGreaterThan(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("应该返回有效的版本号格式", () => {
|
|
22
|
+
const version = VersionUtils.getVersion();
|
|
23
|
+
// 版本号应该是数字点分隔格式,或者 "unknown"
|
|
24
|
+
const isValid =
|
|
25
|
+
version === "unknown" || /^\d+\.\d+\.\d+/.test(version);
|
|
26
|
+
expect(isValid).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("多次调用应该返回相同结果(缓存生效)", () => {
|
|
30
|
+
const version1 = VersionUtils.getVersion();
|
|
31
|
+
const version2 = VersionUtils.getVersion();
|
|
32
|
+
expect(version1).toBe(version2);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("清除缓存后应该重新读取版本号", () => {
|
|
36
|
+
const version1 = VersionUtils.getVersion();
|
|
37
|
+
VersionUtils.clearCache();
|
|
38
|
+
const version2 = VersionUtils.getVersion();
|
|
39
|
+
expect(version1).toBe(version2);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("getVersionInfo", () => {
|
|
44
|
+
it("应该返回包含版本号的对象", () => {
|
|
45
|
+
const info = VersionUtils.getVersionInfo();
|
|
46
|
+
expect(info).toHaveProperty("version");
|
|
47
|
+
expect(typeof info.version).toBe("string");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("应该可能包含应用名称", () => {
|
|
51
|
+
const info = VersionUtils.getVersionInfo();
|
|
52
|
+
// name 可能存在也可能不存在,取决于构建配置
|
|
53
|
+
if (info.name) {
|
|
54
|
+
expect(typeof info.name).toBe("string");
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("应该可能包含描述信息", () => {
|
|
59
|
+
const info = VersionUtils.getVersionInfo();
|
|
60
|
+
// description 可能存在也可能不存在
|
|
61
|
+
if (info.description) {
|
|
62
|
+
expect(typeof info.description).toBe("string");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("应该可能包含作者信息", () => {
|
|
67
|
+
const info = VersionUtils.getVersionInfo();
|
|
68
|
+
// author 可能存在也可能不存在
|
|
69
|
+
if (info.author) {
|
|
70
|
+
expect(typeof info.author).toBe("string" || typeof info.author === "object");
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("多次调用应该返回相同结果(缓存生效)", () => {
|
|
75
|
+
const info1 = VersionUtils.getVersionInfo();
|
|
76
|
+
const info2 = VersionUtils.getVersionInfo();
|
|
77
|
+
expect(info1).toEqual(info2);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("compareVersions", () => {
|
|
82
|
+
it("应该正确比较相等的版本号", () => {
|
|
83
|
+
const result = VersionUtils.compareVersions("1.0.0", "1.0.0");
|
|
84
|
+
expect(result).toBe(0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("应该正确比较主版本号差异", () => {
|
|
88
|
+
const result = VersionUtils.compareVersions("2.0.0", "1.0.0");
|
|
89
|
+
expect(result).toBe(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("应该正确比较次版本号差异", () => {
|
|
93
|
+
const result = VersionUtils.compareVersions("1.2.0", "1.1.0");
|
|
94
|
+
expect(result).toBe(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("应该正确比较补丁版本号差异", () => {
|
|
98
|
+
const result = VersionUtils.compareVersions("1.0.1", "1.0.0");
|
|
99
|
+
expect(result).toBe(1);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("应该正确处理小于的情况", () => {
|
|
103
|
+
const result = VersionUtils.compareVersions("1.0.0", "2.0.0");
|
|
104
|
+
expect(result).toBe(-1);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("应该正确处理不同长度的版本号", () => {
|
|
108
|
+
const result = VersionUtils.compareVersions("1.0", "1.0.0");
|
|
109
|
+
expect(result).toBe(0);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("应该正确处理较短的版本号", () => {
|
|
113
|
+
const result = VersionUtils.compareVersions("1.0.0", "1.0");
|
|
114
|
+
expect(result).toBe(0);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("应该正确处理带预发布标签的版本号", () => {
|
|
118
|
+
// 注意:当前实现不处理预发布标签,仅比较数字部分
|
|
119
|
+
const result = VersionUtils.compareVersions("1.0.0-alpha", "1.0.0");
|
|
120
|
+
// 预发布标签会被 split(".") 处理,可能产生非数字部分
|
|
121
|
+
// 这里测试数字部分的比较
|
|
122
|
+
expect(typeof result).toBe("number");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("应该正确处理复杂版本号比较", () => {
|
|
126
|
+
expect(VersionUtils.compareVersions("1.2.3", "1.2.4")).toBe(-1);
|
|
127
|
+
expect(VersionUtils.compareVersions("1.2.4", "1.2.3")).toBe(1);
|
|
128
|
+
expect(VersionUtils.compareVersions("2.0.0", "1.9.9")).toBe(1);
|
|
129
|
+
expect(VersionUtils.compareVersions("0.1.0", "0.0.9")).toBe(1);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("isValidVersion", () => {
|
|
134
|
+
it("应该接受有效的标准版本号", () => {
|
|
135
|
+
expect(VersionUtils.isValidVersion("1.0.0")).toBe(true);
|
|
136
|
+
expect(VersionUtils.isValidVersion("0.0.1")).toBe(true);
|
|
137
|
+
expect(VersionUtils.isValidVersion("10.20.30")).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("应该接受带预发布标签的版本号", () => {
|
|
141
|
+
expect(VersionUtils.isValidVersion("1.0.0-alpha")).toBe(true);
|
|
142
|
+
expect(VersionUtils.isValidVersion("1.0.0-beta.1")).toBe(true);
|
|
143
|
+
expect(VersionUtils.isValidVersion("1.0.0-rc.1")).toBe(true);
|
|
144
|
+
expect(VersionUtils.isValidVersion("2.0.0-alpha.1.beta.2")).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("应该接受带构建元数据的版本号", () => {
|
|
148
|
+
expect(VersionUtils.isValidVersion("1.0.0+build.1")).toBe(true);
|
|
149
|
+
expect(VersionUtils.isValidVersion("1.0.0+20130313144700")).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("应该接受带预发布和构建元数据的版本号", () => {
|
|
153
|
+
expect(VersionUtils.isValidVersion("1.0.0-alpha+001")).toBe(true);
|
|
154
|
+
expect(VersionUtils.isValidVersion("1.0.0-beta+exp.sha.5114f85")).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("应该拒绝无效的版本号", () => {
|
|
158
|
+
expect(VersionUtils.isValidVersion("1")).toBe(false);
|
|
159
|
+
expect(VersionUtils.isValidVersion("1.0")).toBe(false);
|
|
160
|
+
expect(VersionUtils.isValidVersion("v1.0.0")).toBe(false);
|
|
161
|
+
expect(VersionUtils.isValidVersion("")).toBe(false);
|
|
162
|
+
expect(VersionUtils.isValidVersion("invalid")).toBe(false);
|
|
163
|
+
expect(VersionUtils.isValidVersion("1.0.0-")).toBe(false); // 只有连字符
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("应该拒绝边界情况", () => {
|
|
167
|
+
expect(VersionUtils.isValidVersion(".1.0.0")).toBe(false);
|
|
168
|
+
expect(VersionUtils.isValidVersion("1.0.0.")).toBe(false);
|
|
169
|
+
expect(VersionUtils.isValidVersion("..")).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe("clearCache", () => {
|
|
174
|
+
it("应该清除版本缓存", () => {
|
|
175
|
+
// 获取版本号(建立缓存)
|
|
176
|
+
const version1 = VersionUtils.getVersion();
|
|
177
|
+
|
|
178
|
+
// 清除缓存
|
|
179
|
+
VersionUtils.clearCache();
|
|
180
|
+
|
|
181
|
+
// 再次获取版本号
|
|
182
|
+
const version2 = VersionUtils.getVersion();
|
|
183
|
+
|
|
184
|
+
// 应该返回相同值,但是重新读取的
|
|
185
|
+
expect(version1).toBe(version2);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("应该清除版本信息缓存", () => {
|
|
189
|
+
// 获取版本信息(建立缓存)
|
|
190
|
+
const info1 = VersionUtils.getVersionInfo();
|
|
191
|
+
|
|
192
|
+
// 清除缓存
|
|
193
|
+
VersionUtils.clearCache();
|
|
194
|
+
|
|
195
|
+
// 再次获取版本信息
|
|
196
|
+
const info2 = VersionUtils.getVersionInfo();
|
|
197
|
+
|
|
198
|
+
// 应该返回相同值,但是重新读取的
|
|
199
|
+
expect(info1).toEqual(info2);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe("边界情况测试", () => {
|
|
204
|
+
it("应该处理 getRuntimeVersion 的错误情况", () => {
|
|
205
|
+
// 清除缓存
|
|
206
|
+
VersionUtils.clearCache();
|
|
207
|
+
|
|
208
|
+
// 获取版本号,即使在某些环境中无法读取 package.json
|
|
209
|
+
// 也应该返回 "unknown" 或有效的版本号
|
|
210
|
+
const version = VersionUtils.getVersion();
|
|
211
|
+
expect(["unknown", "1.9.7"].includes(version) || /^\d+\.\d+\.\d+/.test(version)).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("应该处理 getRuntimeVersionInfo 的错误情况", () => {
|
|
215
|
+
// 清除缓存
|
|
216
|
+
VersionUtils.clearCache();
|
|
217
|
+
|
|
218
|
+
// 获取版本信息,即使在某些环境中无法读取 package.json
|
|
219
|
+
// 也应该返回包含至少 version 字段的对象
|
|
220
|
+
const info = VersionUtils.getVersionInfo();
|
|
221
|
+
expect(info).toHaveProperty("version");
|
|
222
|
+
expect(typeof info.version).toBe("string");
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
package/src/global.d.ts
ADDED
package/src/index.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": false,
|
|
9
|
+
"outDir": "../../dist/version",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noImplicitAny": true,
|
|
12
|
+
"strictNullChecks": true,
|
|
13
|
+
"strictFunctionTypes": true,
|
|
14
|
+
"noImplicitReturns": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noImplicitOverride": true,
|
|
17
|
+
"useUnknownInCatchVariables": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"declaration": true,
|
|
20
|
+
"declarationMap": true,
|
|
21
|
+
"sourceMap": true,
|
|
22
|
+
"skipLibCheck": true,
|
|
23
|
+
"resolveJsonModule": true
|
|
24
|
+
},
|
|
25
|
+
"include": ["src/**/*"],
|
|
26
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
|
27
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { defineConfig } from "tsup";
|
|
5
|
+
|
|
6
|
+
// 获取当前文件所在目录
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
// 读取根目录 package.json 获取版本号
|
|
10
|
+
const rootPkgPath = resolve(__dirname, "../../package.json");
|
|
11
|
+
const pkg = JSON.parse(readFileSync(rootPkgPath, "utf-8"));
|
|
12
|
+
|
|
13
|
+
export default defineConfig({
|
|
14
|
+
entry: {
|
|
15
|
+
index: resolve(__dirname, "src/index.ts"),
|
|
16
|
+
},
|
|
17
|
+
format: ["esm"],
|
|
18
|
+
target: "node18",
|
|
19
|
+
outDir: "dist",
|
|
20
|
+
clean: true,
|
|
21
|
+
sourcemap: true,
|
|
22
|
+
dts: true,
|
|
23
|
+
minify: false,
|
|
24
|
+
splitting: false,
|
|
25
|
+
bundle: true,
|
|
26
|
+
keepNames: true,
|
|
27
|
+
platform: "node",
|
|
28
|
+
// 使用版本包自己的 tsconfig.json
|
|
29
|
+
tsconfig: resolve(__dirname, "tsconfig.json"),
|
|
30
|
+
esbuildOptions: (options) => {
|
|
31
|
+
options.resolveExtensions = [".ts", ".js", ".json"];
|
|
32
|
+
|
|
33
|
+
// 构建时注入版本号常量
|
|
34
|
+
// 如果构建时能读取到版本号,则注入真实值
|
|
35
|
+
// 否则注入占位符,运行时从 package.json 读取
|
|
36
|
+
const versionValue = pkg.version || "__VERSION__";
|
|
37
|
+
const appNameValue = pkg.name || "__APP_NAME__";
|
|
38
|
+
|
|
39
|
+
options.define = {
|
|
40
|
+
...options.define,
|
|
41
|
+
__VERSION__: JSON.stringify(versionValue),
|
|
42
|
+
__APP_NAME__: JSON.stringify(appNameValue),
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
outExtension: () => ({
|
|
46
|
+
js: ".js",
|
|
47
|
+
}),
|
|
48
|
+
});
|
package/vitest.config.ts
ADDED