befly 2.3.3 → 3.0.0
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/apis/health/info.ts +64 -0
- package/apis/tool/tokenCheck.ts +51 -0
- package/bin/befly.ts +202 -0
- package/checks/conflict.ts +408 -0
- package/checks/{table.js → table.ts} +139 -61
- package/config/env.ts +218 -0
- package/config/reserved.ts +96 -0
- package/main.ts +101 -0
- package/package.json +44 -8
- package/plugins/{db.js → db.ts} +24 -11
- package/plugins/logger.ts +28 -0
- package/plugins/redis.ts +51 -0
- package/plugins/tool.ts +34 -0
- package/scripts/syncDb/apply.ts +171 -0
- package/scripts/syncDb/constants.ts +70 -0
- package/scripts/syncDb/ddl.ts +182 -0
- package/scripts/syncDb/helpers.ts +172 -0
- package/scripts/syncDb/index.ts +215 -0
- package/scripts/syncDb/schema.ts +199 -0
- package/scripts/syncDb/sqlite.ts +50 -0
- package/scripts/syncDb/state.ts +104 -0
- package/scripts/syncDb/table.ts +204 -0
- package/scripts/syncDb/tableCreate.ts +142 -0
- package/scripts/syncDb/tests/constants.test.ts +104 -0
- package/scripts/syncDb/tests/ddl.test.ts +134 -0
- package/scripts/syncDb/tests/helpers.test.ts +70 -0
- package/scripts/syncDb/types.ts +92 -0
- package/scripts/syncDb/version.ts +73 -0
- package/scripts/syncDb.ts +9 -0
- package/scripts/{syncDev.js → syncDev.ts} +41 -25
- package/system.ts +149 -0
- package/tables/_common.json +21 -0
- package/tables/admin.json +10 -0
- package/tsconfig.json +58 -0
- package/types/api.d.ts +246 -0
- package/types/befly.d.ts +234 -0
- package/types/common.d.ts +215 -0
- package/types/context.ts +167 -0
- package/types/crypto.d.ts +23 -0
- package/types/database.d.ts +278 -0
- package/types/index.d.ts +16 -0
- package/types/index.ts +459 -0
- package/types/jwt.d.ts +99 -0
- package/types/logger.d.ts +43 -0
- package/types/plugin.d.ts +109 -0
- package/types/redis.d.ts +44 -0
- package/types/tool.d.ts +67 -0
- package/types/validator.d.ts +45 -0
- package/utils/addonHelper.ts +60 -0
- package/utils/api.ts +23 -0
- package/utils/{colors.js → colors.ts} +79 -21
- package/utils/crypto.ts +308 -0
- package/utils/datetime.ts +51 -0
- package/utils/dbHelper.ts +142 -0
- package/utils/errorHandler.ts +68 -0
- package/utils/index.ts +46 -0
- package/utils/jwt.ts +493 -0
- package/utils/logger.ts +284 -0
- package/utils/objectHelper.ts +68 -0
- package/utils/pluginHelper.ts +62 -0
- package/utils/redisHelper.ts +338 -0
- package/utils/response.ts +38 -0
- package/utils/{sqlBuilder.js → sqlBuilder.ts} +233 -97
- package/utils/sqlHelper.ts +447 -0
- package/utils/tableHelper.ts +167 -0
- package/utils/tool.ts +230 -0
- package/utils/typeHelper.ts +101 -0
- package/utils/validate.ts +451 -0
- package/utils/{xml.js → xml.ts} +100 -74
- package/.npmrc +0 -3
- package/.prettierignore +0 -2
- package/.prettierrc +0 -11
- package/apis/health/info.js +0 -49
- package/apis/tool/tokenCheck.js +0 -29
- package/bin/befly.js +0 -109
- package/config/env.js +0 -64
- package/main.js +0 -579
- package/plugins/logger.js +0 -14
- package/plugins/redis.js +0 -32
- package/plugins/tool.js +0 -8
- package/scripts/syncDb.js +0 -752
- package/system.js +0 -118
- package/tables/common.json +0 -16
- package/tables/tool.json +0 -6
- package/utils/api.js +0 -27
- package/utils/crypto.js +0 -260
- package/utils/index.js +0 -334
- package/utils/jwt.js +0 -387
- package/utils/logger.js +0 -143
- package/utils/redisHelper.js +0 -74
- package/utils/sqlManager.js +0 -471
- package/utils/tool.js +0 -31
- package/utils/validate.js +0 -226
package/utils/tool.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool 工具类 - TypeScript 版本
|
|
3
|
+
* 提供数据处理的便捷方法
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { omitFields } from './index.js';
|
|
7
|
+
import type { BeflyContext } from '../types/befly.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 数据对象类型
|
|
11
|
+
*/
|
|
12
|
+
type DataObject = Record<string, any>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 工具类:通过构造函数注入 befly
|
|
16
|
+
*/
|
|
17
|
+
export class Tool {
|
|
18
|
+
private befly: BeflyContext;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 构造函数
|
|
22
|
+
* @param befly - Befly 上下文
|
|
23
|
+
*/
|
|
24
|
+
constructor(befly: BeflyContext) {
|
|
25
|
+
this.befly = befly;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 处理更新数据
|
|
30
|
+
* - 移除 id、created_at、deleted_at 字段
|
|
31
|
+
* - 添加 updated_at 时间戳
|
|
32
|
+
* @param data - 原始数据
|
|
33
|
+
* @returns 处理后的数据
|
|
34
|
+
*/
|
|
35
|
+
async updData(data: DataObject): Promise<DataObject> {
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const cleaned = omitFields(data ?? {}, ['id', 'created_at', 'deleted_at'], [undefined]);
|
|
38
|
+
return { ...cleaned, updated_at: now };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 处理插入数据
|
|
43
|
+
* - 生成唯一 ID
|
|
44
|
+
* - 添加 created_at 和 updated_at 时间戳
|
|
45
|
+
* - 移除 undefined 字段
|
|
46
|
+
* @param data - 原始数据(支持单个对象或数组)
|
|
47
|
+
* @returns 处理后的数据
|
|
48
|
+
*/
|
|
49
|
+
async insData(data: DataObject | DataObject[]): Promise<DataObject | DataObject[]> {
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const genId = async (): Promise<number> => await this.befly.redis.genTimeID();
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(data)) {
|
|
54
|
+
return await Promise.all(
|
|
55
|
+
data.map(async (item) => ({
|
|
56
|
+
...omitFields(item ?? {}, [], [undefined]),
|
|
57
|
+
id: await genId(),
|
|
58
|
+
created_at: now,
|
|
59
|
+
updated_at: now,
|
|
60
|
+
state: 0
|
|
61
|
+
}))
|
|
62
|
+
);
|
|
63
|
+
} else {
|
|
64
|
+
const cleaned = omitFields(data ?? {}, [], [undefined]);
|
|
65
|
+
return {
|
|
66
|
+
...cleaned,
|
|
67
|
+
id: await genId(),
|
|
68
|
+
created_at: now,
|
|
69
|
+
updated_at: now,
|
|
70
|
+
state: 0
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 处理删除数据(软删除)
|
|
77
|
+
* - 设置 deleted_at 时间戳
|
|
78
|
+
* - 添加 updated_at 时间戳
|
|
79
|
+
* @returns 处理后的数据
|
|
80
|
+
*/
|
|
81
|
+
async delData(): Promise<DataObject> {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
return {
|
|
84
|
+
deleted_at: now,
|
|
85
|
+
updated_at: now,
|
|
86
|
+
state: 1
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 批量生成 ID
|
|
92
|
+
* @param count - 生成数量
|
|
93
|
+
* @returns ID 数组
|
|
94
|
+
*/
|
|
95
|
+
async genIds(count: number): Promise<number[]> {
|
|
96
|
+
const ids: number[] = [];
|
|
97
|
+
for (let i = 0; i < count; i++) {
|
|
98
|
+
ids.push(await this.befly.redis.genTimeID());
|
|
99
|
+
}
|
|
100
|
+
return ids;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 清理数据对象
|
|
105
|
+
* - 移除 undefined、null、空字符串
|
|
106
|
+
* @param data - 原始数据
|
|
107
|
+
* @param removeNull - 是否移除 null
|
|
108
|
+
* @param removeEmptyString - 是否移除空字符串
|
|
109
|
+
* @returns 清理后的数据
|
|
110
|
+
*/
|
|
111
|
+
cleanData(data: DataObject, removeNull: boolean = true, removeEmptyString: boolean = true): DataObject {
|
|
112
|
+
const result: DataObject = {};
|
|
113
|
+
|
|
114
|
+
for (const [key, value] of Object.entries(data)) {
|
|
115
|
+
// 跳过 undefined
|
|
116
|
+
if (value === undefined) continue;
|
|
117
|
+
|
|
118
|
+
// 跳过 null(如果配置)
|
|
119
|
+
if (removeNull && value === null) continue;
|
|
120
|
+
|
|
121
|
+
// 跳过空字符串(如果配置)
|
|
122
|
+
if (removeEmptyString && value === '') continue;
|
|
123
|
+
|
|
124
|
+
result[key] = value;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 合并数据对象(深度合并)
|
|
132
|
+
* @param target - 目标对象
|
|
133
|
+
* @param sources - 源对象(可多个)
|
|
134
|
+
* @returns 合并后的对象
|
|
135
|
+
*/
|
|
136
|
+
mergeData(target: DataObject, ...sources: DataObject[]): DataObject {
|
|
137
|
+
const result = { ...target };
|
|
138
|
+
|
|
139
|
+
for (const source of sources) {
|
|
140
|
+
for (const [key, value] of Object.entries(source)) {
|
|
141
|
+
if (value !== undefined) {
|
|
142
|
+
result[key] = value;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 提取指定字段
|
|
152
|
+
* @param data - 原始数据
|
|
153
|
+
* @param fields - 字段列表
|
|
154
|
+
* @returns 提取后的数据
|
|
155
|
+
*/
|
|
156
|
+
pickFields(data: DataObject, fields: string[]): DataObject {
|
|
157
|
+
const result: DataObject = {};
|
|
158
|
+
|
|
159
|
+
for (const field of fields) {
|
|
160
|
+
if (field in data) {
|
|
161
|
+
result[field] = data[field];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 排除指定字段
|
|
170
|
+
* @param data - 原始数据
|
|
171
|
+
* @param fields - 字段列表
|
|
172
|
+
* @returns 排除后的数据
|
|
173
|
+
*/
|
|
174
|
+
omitFields(data: DataObject, fields: string[]): DataObject {
|
|
175
|
+
const result = { ...data };
|
|
176
|
+
|
|
177
|
+
for (const field of fields) {
|
|
178
|
+
delete result[field];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 重命名字段
|
|
186
|
+
* @param data - 原始数据
|
|
187
|
+
* @param mapping - 字段映射 { oldKey: newKey }
|
|
188
|
+
* @returns 重命名后的数据
|
|
189
|
+
*/
|
|
190
|
+
renameFields(data: DataObject, mapping: Record<string, string>): DataObject {
|
|
191
|
+
const result = { ...data };
|
|
192
|
+
|
|
193
|
+
for (const [oldKey, newKey] of Object.entries(mapping)) {
|
|
194
|
+
if (oldKey in result) {
|
|
195
|
+
result[newKey] = result[oldKey];
|
|
196
|
+
delete result[oldKey];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 转换字段类型
|
|
205
|
+
* @param data - 原始数据
|
|
206
|
+
* @param conversions - 转换规则 { field: 'number' | 'string' | 'boolean' }
|
|
207
|
+
* @returns 转换后的数据
|
|
208
|
+
*/
|
|
209
|
+
convertFields(data: DataObject, conversions: Record<string, 'number' | 'string' | 'boolean'>): DataObject {
|
|
210
|
+
const result = { ...data };
|
|
211
|
+
|
|
212
|
+
for (const [field, type] of Object.entries(conversions)) {
|
|
213
|
+
if (field in result && result[field] !== null && result[field] !== undefined) {
|
|
214
|
+
switch (type) {
|
|
215
|
+
case 'number':
|
|
216
|
+
result[field] = Number(result[field]);
|
|
217
|
+
break;
|
|
218
|
+
case 'string':
|
|
219
|
+
result[field] = String(result[field]);
|
|
220
|
+
break;
|
|
221
|
+
case 'boolean':
|
|
222
|
+
result[field] = Boolean(result[field]);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Befly 类型判断工具
|
|
3
|
+
* 提供各种类型检查和判断功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 类型判断
|
|
8
|
+
* @param value - 要判断的值
|
|
9
|
+
* @param type - 期望的类型
|
|
10
|
+
* @returns 是否匹配指定类型
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* isType(123, 'number') // true
|
|
14
|
+
* isType('hello', 'string') // true
|
|
15
|
+
* isType([], 'array') // true
|
|
16
|
+
* isType({}, 'object') // true
|
|
17
|
+
* isType(null, 'null') // true
|
|
18
|
+
* isType(undefined, 'undefined') // true
|
|
19
|
+
* isType(NaN, 'nan') // true
|
|
20
|
+
* isType(42, 'integer') // true
|
|
21
|
+
* isType(3.14, 'float') // true
|
|
22
|
+
* isType(10, 'positive') // true
|
|
23
|
+
* isType(-5, 'negative') // true
|
|
24
|
+
* isType(0, 'zero') // true
|
|
25
|
+
* isType('', 'empty') // true
|
|
26
|
+
* isType(null, 'empty') // true
|
|
27
|
+
* isType(true, 'truthy') // true
|
|
28
|
+
* isType(false, 'falsy') // true
|
|
29
|
+
* isType('str', 'primitive') // true
|
|
30
|
+
* isType({}, 'reference') // true
|
|
31
|
+
*/
|
|
32
|
+
export const isType = (value: any, type: string): boolean => {
|
|
33
|
+
const actualType = Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
|
|
34
|
+
const expectedType = String(type).toLowerCase();
|
|
35
|
+
|
|
36
|
+
// 语义类型单独处理
|
|
37
|
+
switch (expectedType) {
|
|
38
|
+
case 'function':
|
|
39
|
+
return typeof value === 'function';
|
|
40
|
+
case 'nan':
|
|
41
|
+
return typeof value === 'number' && Number.isNaN(value);
|
|
42
|
+
case 'empty':
|
|
43
|
+
return value === '' || value === null || value === undefined;
|
|
44
|
+
case 'integer':
|
|
45
|
+
return Number.isInteger(value);
|
|
46
|
+
case 'float':
|
|
47
|
+
return typeof value === 'number' && !Number.isInteger(value) && !Number.isNaN(value);
|
|
48
|
+
case 'positive':
|
|
49
|
+
return typeof value === 'number' && value > 0;
|
|
50
|
+
case 'negative':
|
|
51
|
+
return typeof value === 'number' && value < 0;
|
|
52
|
+
case 'zero':
|
|
53
|
+
return value === 0;
|
|
54
|
+
case 'truthy':
|
|
55
|
+
return !!value;
|
|
56
|
+
case 'falsy':
|
|
57
|
+
return !value;
|
|
58
|
+
case 'primitive':
|
|
59
|
+
return value !== Object(value);
|
|
60
|
+
case 'reference':
|
|
61
|
+
return value === Object(value);
|
|
62
|
+
default:
|
|
63
|
+
return actualType === expectedType;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 判断是否为空对象
|
|
69
|
+
* @param obj - 要判断的值
|
|
70
|
+
* @returns 是否为空对象
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* isEmptyObject({}) // true
|
|
74
|
+
* isEmptyObject({ a: 1 }) // false
|
|
75
|
+
* isEmptyObject([]) // false
|
|
76
|
+
* isEmptyObject(null) // false
|
|
77
|
+
*/
|
|
78
|
+
export const isEmptyObject = (obj: any): boolean => {
|
|
79
|
+
if (!isType(obj, 'object')) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return Object.keys(obj).length === 0;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 判断是否为空数组
|
|
87
|
+
* @param arr - 要判断的值
|
|
88
|
+
* @returns 是否为空数组
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* isEmptyArray([]) // true
|
|
92
|
+
* isEmptyArray([1, 2]) // false
|
|
93
|
+
* isEmptyArray({}) // false
|
|
94
|
+
* isEmptyArray(null) // false
|
|
95
|
+
*/
|
|
96
|
+
export const isEmptyArray = (arr: any): boolean => {
|
|
97
|
+
if (!isType(arr, 'array')) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return arr.length === 0;
|
|
101
|
+
};
|