befly 2.0.14 → 2.1.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/.gitignore +1 -0
- package/checks/table.js +106 -81
- package/config/env.js +1 -0
- package/main.js +43 -60
- package/package.json +10 -13
- package/plugins/db.js +137 -178
- package/scripts/syncDb.js +367 -0
- package/tables/common.json +14 -14
- package/tables/tool.json +4 -4
- package/utils/util.js +117 -19
- package/utils/validate.js +18 -119
- package/USEAGE.md +0 -5
- package/bin/befly.js +0 -176
- package/scripts/dbSync.js +0 -714
- package/scripts/release.js +0 -258
package/utils/validate.js
CHANGED
|
@@ -1,29 +1,6 @@
|
|
|
1
|
-
import { isType } from './util.js';
|
|
1
|
+
import { isType, parseFieldRule } from './util.js';
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
const parseFieldRule = (rule) => {
|
|
5
|
-
const allParts = rule.split('|');
|
|
6
|
-
|
|
7
|
-
// 现在支持7个部分:显示名|类型|最小值|最大值|默认值|是否索引|正则约束
|
|
8
|
-
if (allParts.length <= 7) {
|
|
9
|
-
// 如果少于7个部分,补齐缺失的部分为 null
|
|
10
|
-
while (allParts.length < 7) {
|
|
11
|
-
allParts.push('null');
|
|
12
|
-
}
|
|
13
|
-
return allParts;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// 如果超过7个部分,保留前6个,剩余的合并为最后的正则约束部分
|
|
17
|
-
return [
|
|
18
|
-
allParts[0], // 显示名
|
|
19
|
-
allParts[1], // 类型
|
|
20
|
-
allParts[2], // 最小值
|
|
21
|
-
allParts[3], // 最大值
|
|
22
|
-
allParts[4], // 默认值
|
|
23
|
-
allParts[5], // 是否索引
|
|
24
|
-
allParts.slice(6).join('|') // 正则约束(可能包含管道符)
|
|
25
|
-
];
|
|
26
|
-
};
|
|
3
|
+
// 移除本文件重复实现,统一复用 util.js 导出的校验函数与 parseFieldRule
|
|
27
4
|
|
|
28
5
|
/**
|
|
29
6
|
* 验证器类
|
|
@@ -161,96 +138,22 @@ export class Validator {
|
|
|
161
138
|
}
|
|
162
139
|
|
|
163
140
|
if (spec && spec.trim() !== '') {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
141
|
+
try {
|
|
142
|
+
const regExp = new RegExp(spec);
|
|
143
|
+
if (!regExp.test(String(value))) {
|
|
144
|
+
return `${name}(${fieldName})格式不正确`;
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
return `${name}(${fieldName})的正则表达式格式错误`;
|
|
170
148
|
}
|
|
171
149
|
}
|
|
172
150
|
|
|
173
151
|
return null;
|
|
174
152
|
} catch (error) {
|
|
175
|
-
return `${name}(${fieldName})
|
|
153
|
+
return `${name}(${fieldName})验证出错: ${error.message}`;
|
|
176
154
|
}
|
|
177
155
|
}
|
|
178
156
|
|
|
179
|
-
/**
|
|
180
|
-
* 判断是否为枚举格式
|
|
181
|
-
*/
|
|
182
|
-
isEnumSpec(spec) {
|
|
183
|
-
return spec && spec.startsWith('enum#');
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* 验证枚举值
|
|
188
|
-
*/
|
|
189
|
-
validateEnum(value, spec, name, fieldName, type) {
|
|
190
|
-
// 解析枚举值 "enum#1,2,3" -> ["1", "2", "3"]
|
|
191
|
-
const enumValues = spec
|
|
192
|
-
.substring(5)
|
|
193
|
-
.split(',')
|
|
194
|
-
.map((v) => v.trim());
|
|
195
|
-
|
|
196
|
-
if (type === 'number') {
|
|
197
|
-
// 数字类型:转换枚举值为数字进行比较
|
|
198
|
-
const numericEnumValues = enumValues.map((v) => parseFloat(v));
|
|
199
|
-
if (!numericEnumValues.includes(value)) {
|
|
200
|
-
return `${name}(${fieldName})必须是以下值之一: ${enumValues.join(', ')}`;
|
|
201
|
-
}
|
|
202
|
-
} else if (type === 'string') {
|
|
203
|
-
// 字符串类型:直接比较
|
|
204
|
-
if (!enumValues.includes(value)) {
|
|
205
|
-
return `${name}(${fieldName})必须是以下值之一: ${enumValues.join(', ')}`;
|
|
206
|
-
}
|
|
207
|
-
} else if (type === 'array') {
|
|
208
|
-
// 数组类型:检查每个元素是否在枚举值中
|
|
209
|
-
for (const item of value) {
|
|
210
|
-
if (!enumValues.includes(String(item))) {
|
|
211
|
-
return `${name}(${fieldName})中的元素"${item}"必须是以下值之一: ${enumValues.join(', ')}`;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* 验证数字表达式
|
|
221
|
-
*/
|
|
222
|
-
validateNumberExpression(value, name, spec, fieldName) {
|
|
223
|
-
const parts = spec.split('=');
|
|
224
|
-
if (parts.length !== 2) {
|
|
225
|
-
return `${name}(${fieldName})的计算规则必须包含等号`;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const leftExpression = parts[0].trim();
|
|
229
|
-
const rightValue = parseFloat(parts[1].trim());
|
|
230
|
-
|
|
231
|
-
if (isNaN(rightValue)) {
|
|
232
|
-
return `${name}(${fieldName})的计算规则右边必须是数字`;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const safePattern = /^[x\d\+\-\*\/\(\)\.\s]+$/;
|
|
236
|
-
if (!safePattern.test(leftExpression)) {
|
|
237
|
-
return `${name}(${fieldName})的表达式包含不安全的字符`;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
let processedExpression = leftExpression.replace(/x/g, value.toString());
|
|
241
|
-
const leftResult = new Function('return ' + processedExpression)();
|
|
242
|
-
|
|
243
|
-
if (typeof leftResult !== 'number' || !isFinite(leftResult)) {
|
|
244
|
-
return `${name}(${fieldName})的表达式计算结果不是有效数字`;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (Math.abs(leftResult - rightValue) > Number.EPSILON) {
|
|
248
|
-
return `${name}(${fieldName})不满足计算条件 ${spec}`;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
157
|
/**
|
|
255
158
|
* 验证字符串类型
|
|
256
159
|
*/
|
|
@@ -269,21 +172,19 @@ export class Validator {
|
|
|
269
172
|
}
|
|
270
173
|
|
|
271
174
|
if (spec && spec.trim() !== '') {
|
|
272
|
-
|
|
273
|
-
if (this.isEnumSpec(spec)) {
|
|
274
|
-
return this.validateEnum(value, spec, name, fieldName, 'string');
|
|
275
|
-
} else {
|
|
276
|
-
// 原有的正则表达式验证逻辑
|
|
175
|
+
try {
|
|
277
176
|
const regExp = new RegExp(spec);
|
|
278
177
|
if (!regExp.test(value)) {
|
|
279
178
|
return `${name}(${fieldName})格式不正确`;
|
|
280
179
|
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
return `${name}(${fieldName})的正则表达式格式错误`;
|
|
281
182
|
}
|
|
282
183
|
}
|
|
283
184
|
|
|
284
185
|
return null;
|
|
285
186
|
} catch (error) {
|
|
286
|
-
return `${name}(${fieldName})
|
|
187
|
+
return `${name}(${fieldName})验证出错: ${error.message}`;
|
|
287
188
|
}
|
|
288
189
|
}
|
|
289
190
|
|
|
@@ -305,23 +206,21 @@ export class Validator {
|
|
|
305
206
|
}
|
|
306
207
|
|
|
307
208
|
if (spec && spec.trim() !== '') {
|
|
308
|
-
|
|
309
|
-
if (this.isEnumSpec(spec)) {
|
|
310
|
-
return this.validateEnum(value, spec, name, fieldName, 'array');
|
|
311
|
-
} else {
|
|
312
|
-
// 原有的正则表达式验证逻辑
|
|
209
|
+
try {
|
|
313
210
|
const regExp = new RegExp(spec);
|
|
314
211
|
for (const item of value) {
|
|
315
212
|
if (!regExp.test(String(item))) {
|
|
316
213
|
return `${name}(${fieldName})中的元素"${item}"格式不正确`;
|
|
317
214
|
}
|
|
318
215
|
}
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return `${name}(${fieldName})的正则表达式格式错误`;
|
|
319
218
|
}
|
|
320
219
|
}
|
|
321
220
|
|
|
322
221
|
return null;
|
|
323
222
|
} catch (error) {
|
|
324
|
-
return `${name}(${fieldName})
|
|
223
|
+
return `${name}(${fieldName})验证出错: ${error.message}`;
|
|
325
224
|
}
|
|
326
225
|
}
|
|
327
226
|
}
|
package/USEAGE.md
DELETED
package/bin/befly.js
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Befly CLI 工具
|
|
5
|
-
* 提供命令行接口来执行 befly 框架的各种脚本
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { spawn } from 'node:child_process';
|
|
9
|
-
import { resolve, join, dirname } from 'node:path';
|
|
10
|
-
import { fileURLToPath } from 'node:url';
|
|
11
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
12
|
-
import { readdir } from 'node:fs/promises';
|
|
13
|
-
import { __dirroot, __dirscript } from '../system.js';
|
|
14
|
-
|
|
15
|
-
// 使用 system.js 中定义的路径变量
|
|
16
|
-
const BEFLY_ROOT = __dirroot;
|
|
17
|
-
const SCRIPTS_DIR = __dirscript;
|
|
18
|
-
|
|
19
|
-
// 显示帮助信息
|
|
20
|
-
const showHelp = async () => {
|
|
21
|
-
console.log(`
|
|
22
|
-
Befly CLI 工具 v2.0.12
|
|
23
|
-
|
|
24
|
-
用法:
|
|
25
|
-
befly <script-name> [args...]
|
|
26
|
-
|
|
27
|
-
可用的脚本:
|
|
28
|
-
`);
|
|
29
|
-
|
|
30
|
-
// 列出所有可用的脚本
|
|
31
|
-
if (existsSync(SCRIPTS_DIR)) {
|
|
32
|
-
try {
|
|
33
|
-
const fileList = await readdir(SCRIPTS_DIR);
|
|
34
|
-
const scripts = fileList
|
|
35
|
-
.filter((file) => file.endsWith('.js'))
|
|
36
|
-
.map((file) => file.replace('.js', ''))
|
|
37
|
-
.sort();
|
|
38
|
-
|
|
39
|
-
if (scripts.length > 0) {
|
|
40
|
-
scripts.forEach((script) => {
|
|
41
|
-
console.log(` befly ${script}`);
|
|
42
|
-
});
|
|
43
|
-
} else {
|
|
44
|
-
console.log(' (没有找到可用的脚本)');
|
|
45
|
-
}
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.log(` (无法读取脚本目录: ${error.message})`);
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
console.log(' (脚本目录不存在)');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
console.log(`
|
|
54
|
-
选项:
|
|
55
|
-
-h, --help 显示此帮助信息
|
|
56
|
-
-v, --version 显示版本信息
|
|
57
|
-
|
|
58
|
-
更多信息请访问: https://chensuiyi.me
|
|
59
|
-
`);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// 显示版本信息
|
|
63
|
-
const showVersion = () => {
|
|
64
|
-
try {
|
|
65
|
-
const packageJsonPath = join(BEFLY_ROOT, 'package.json');
|
|
66
|
-
if (existsSync(packageJsonPath)) {
|
|
67
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
68
|
-
console.log(`befly v${packageJson.version}`);
|
|
69
|
-
} else {
|
|
70
|
-
console.log('befly v2.0.12');
|
|
71
|
-
}
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.log('befly v2.0.12');
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// 执行脚本
|
|
78
|
-
const runScript = (scriptName, args = []) => {
|
|
79
|
-
// 检查脚本文件是否存在
|
|
80
|
-
const scriptPath = join(SCRIPTS_DIR, `${scriptName}.js`);
|
|
81
|
-
|
|
82
|
-
if (!existsSync(scriptPath)) {
|
|
83
|
-
console.error(`❌ 错误: 脚本 '${scriptName}' 不存在`);
|
|
84
|
-
console.error(`脚本路径: ${scriptPath}`);
|
|
85
|
-
console.error('');
|
|
86
|
-
console.error('运行 "befly --help" 查看可用的脚本列表');
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
console.log(`🚀 执行脚本: ${scriptName}`);
|
|
91
|
-
console.log(`📁 脚本路径: ${scriptPath}`);
|
|
92
|
-
|
|
93
|
-
// 检测运行环境,优先使用 bun,回退到 node
|
|
94
|
-
const isWindows = process.platform === 'win32';
|
|
95
|
-
let runtime = 'bun';
|
|
96
|
-
let runtimeArgs = ['run'];
|
|
97
|
-
|
|
98
|
-
// 如果 bun 不可用,回退到 node
|
|
99
|
-
const testBun = spawn(isWindows ? 'bun.exe' : 'bun', ['--version'], {
|
|
100
|
-
stdio: 'ignore',
|
|
101
|
-
shell: isWindows
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
testBun.on('error', () => {
|
|
105
|
-
runtime = 'node';
|
|
106
|
-
runtimeArgs = [];
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
testBun.on('close', (code) => {
|
|
110
|
-
if (code !== 0) {
|
|
111
|
-
runtime = 'node';
|
|
112
|
-
runtimeArgs = [];
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
console.log(`⚡ 使用运行时: ${runtime}`);
|
|
116
|
-
console.log('');
|
|
117
|
-
|
|
118
|
-
// 执行脚本
|
|
119
|
-
const child = spawn(isWindows ? `${runtime}.exe` : runtime, [...runtimeArgs, scriptPath, ...args], {
|
|
120
|
-
stdio: 'inherit',
|
|
121
|
-
shell: isWindows,
|
|
122
|
-
cwd: process.cwd() // 使用调用者的工作目录
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
child.on('error', (error) => {
|
|
126
|
-
console.error(`❌ 执行失败: ${error.message}`);
|
|
127
|
-
process.exit(1);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
child.on('close', (code) => {
|
|
131
|
-
if (code !== 0) {
|
|
132
|
-
console.error(`❌ 脚本执行失败,退出码: ${code}`);
|
|
133
|
-
process.exit(code);
|
|
134
|
-
} else {
|
|
135
|
-
console.log(`✅ 脚本执行完成`);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
// 主函数
|
|
142
|
-
const main = async () => {
|
|
143
|
-
const args = process.argv.slice(2);
|
|
144
|
-
|
|
145
|
-
// 没有参数或请求帮助
|
|
146
|
-
if (args.length === 0 || args.includes('-h') || args.includes('--help')) {
|
|
147
|
-
await showHelp();
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// 显示版本
|
|
152
|
-
if (args.includes('-v') || args.includes('--version')) {
|
|
153
|
-
showVersion();
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// 执行脚本
|
|
158
|
-
const scriptName = args[0];
|
|
159
|
-
const scriptArgs = args.slice(1);
|
|
160
|
-
|
|
161
|
-
runScript(scriptName, scriptArgs);
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// 错误处理
|
|
165
|
-
process.on('uncaughtException', (error) => {
|
|
166
|
-
console.error('❌ 未捕获的异常:', error.message);
|
|
167
|
-
process.exit(1);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
process.on('unhandledRejection', (reason, promise) => {
|
|
171
|
-
console.error('❌ 未处理的 Promise 拒绝:', reason);
|
|
172
|
-
process.exit(1);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// 启动 CLI
|
|
176
|
-
main();
|