befly-shared 1.2.8 → 1.3.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/package.json +13 -30
- package/utils/arrayToTree.ts +135 -0
- package/utils/buildTreeByParentPath.ts +127 -0
- package/utils/scanViewsDir.ts +148 -0
- package/README.md +0 -439
- package/dist/addonHelper.js +0 -83
- package/dist/arrayKeysToCamel.js +0 -18
- package/dist/arrayToTree.js +0 -23
- package/dist/calcPerfTime.js +0 -13
- package/dist/configTypes.js +0 -1
- package/dist/constants.js +0 -46
- package/dist/deepTransformKeys.js +0 -139
- package/dist/fieldClear.js +0 -57
- package/dist/genShortId.js +0 -12
- package/dist/hashPassword.js +0 -22
- package/dist/index.js +0 -26
- package/dist/keysToCamel.js +0 -21
- package/dist/keysToSnake.js +0 -21
- package/dist/layouts.js +0 -59
- package/dist/pickFields.js +0 -16
- package/dist/redisKeys.js +0 -34
- package/dist/regex.js +0 -202
- package/dist/scanConfig.js +0 -83
- package/dist/scanFiles.js +0 -39
- package/dist/scanViews.js +0 -48
- package/dist/withDefaultColumns.js +0 -32
- package/src/addonHelper.ts +0 -88
- package/src/arrayKeysToCamel.ts +0 -18
- package/src/arrayToTree.ts +0 -31
- package/src/calcPerfTime.ts +0 -13
- package/src/configTypes.ts +0 -29
- package/src/constants.ts +0 -60
- package/src/deepTransformKeys.ts +0 -172
- package/src/fieldClear.ts +0 -75
- package/src/genShortId.ts +0 -12
- package/src/hashPassword.ts +0 -27
- package/src/index.ts +0 -29
- package/src/keysToCamel.ts +0 -22
- package/src/keysToSnake.ts +0 -22
- package/src/layouts.ts +0 -90
- package/src/pickFields.ts +0 -19
- package/src/redisKeys.ts +0 -44
- package/src/regex.ts +0 -225
- package/src/scanConfig.ts +0 -106
- package/src/scanFiles.ts +0 -49
- package/src/scanViews.ts +0 -55
- package/src/withDefaultColumns.ts +0 -36
- package/tests/addonHelper.test.ts +0 -55
- package/tests/arrayKeysToCamel.test.ts +0 -21
- package/tests/arrayToTree.test.ts +0 -98
- package/tests/calcPerfTime.test.ts +0 -19
- package/tests/deepTransformKeys.test.ts +0 -466
- package/tests/fieldClear.test.ts +0 -39
- package/tests/keysToCamel.test.ts +0 -22
- package/tests/keysToSnake.test.ts +0 -22
- package/tests/layouts.test.ts +0 -93
- package/tests/pickFields.test.ts +0 -22
- package/tests/regex.test.ts +0 -308
- package/tests/scanFiles.test.ts +0 -58
- package/tests/types.test.ts +0 -289
- package/types/addon.d.ts +0 -50
- package/types/addonConfigMerge.d.ts +0 -17
- package/types/addonHelper.d.ts +0 -24
- package/types/api.d.ts +0 -63
- package/types/arrayKeysToCamel.d.ts +0 -13
- package/types/arrayToTree.d.ts +0 -8
- package/types/calcPerfTime.d.ts +0 -4
- package/types/common.d.ts +0 -8
- package/types/configMerge.d.ts +0 -49
- package/types/configTypes.d.ts +0 -28
- package/types/constants.d.ts +0 -48
- package/types/context.d.ts +0 -38
- package/types/crypto.d.ts +0 -23
- package/types/database.d.ts +0 -55
- package/types/deepTransformKeys.d.ts +0 -84
- package/types/fieldClear.d.ts +0 -16
- package/types/genShortId.d.ts +0 -10
- package/types/hashPassword.d.ts +0 -11
- package/types/index.d.ts +0 -23
- package/types/jwt.d.ts +0 -99
- package/types/keysToCamel.d.ts +0 -10
- package/types/keysToSnake.d.ts +0 -10
- package/types/layouts.d.ts +0 -29
- package/types/loadAndMergeConfig.d.ts +0 -7
- package/types/logger.d.ts +0 -22
- package/types/menu.d.ts +0 -49
- package/types/mergeConfig.d.ts +0 -7
- package/types/pickFields.d.ts +0 -4
- package/types/redisKeys.d.ts +0 -34
- package/types/regex.d.ts +0 -145
- package/types/scanConfig.d.ts +0 -7
- package/types/scanFiles.d.ts +0 -12
- package/types/scanViews.d.ts +0 -11
- package/types/table.d.ts +0 -49
- package/types/tool.d.ts +0 -67
- package/types/types.d.ts +0 -44
- package/types/validate.d.ts +0 -69
- package/types/withDefaultColumns.d.ts +0 -7
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
import { camelCase, snakeCase, kebabCase, pascalCase } from 'es-toolkit/string';
|
|
3
|
-
/**
|
|
4
|
-
* 深度递归遍历数据结构,转换所有键名
|
|
5
|
-
* 支持嵌套对象和数组,自动防止循环引用和栈溢出
|
|
6
|
-
*
|
|
7
|
-
* @param data - 源数据(对象、数组或其他类型)
|
|
8
|
-
* @param transformer - 转换函数或预设方式
|
|
9
|
-
* @param options - 转换选项
|
|
10
|
-
* @returns 键名转换后的新数据
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* // 小驼峰
|
|
14
|
-
* deepTransformKeys({ user_id: 123, user_info: { first_name: 'John' } }, 'camel')
|
|
15
|
-
* // { userId: 123, userInfo: { firstName: 'John' } }
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // 下划线
|
|
19
|
-
* deepTransformKeys({ userId: 123, userInfo: { firstName: 'John' } }, 'snake')
|
|
20
|
-
* // { user_id: 123, user_info: { first_name: 'John' } }
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // 短横线
|
|
24
|
-
* deepTransformKeys({ userId: 123, userInfo: { firstName: 'John' } }, 'kebab')
|
|
25
|
-
* // { 'user-id': 123, 'user-info': { 'first-name': 'John' } }
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* // 大驼峰
|
|
29
|
-
* deepTransformKeys({ user_id: 123 }, 'pascal')
|
|
30
|
-
* // { UserId: 123 }
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* // 大写
|
|
34
|
-
* deepTransformKeys({ userId: 123 }, 'upper')
|
|
35
|
-
* // { USERID: 123 }
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* // 小写
|
|
39
|
-
* deepTransformKeys({ UserId: 123 }, 'lower')
|
|
40
|
-
* // { userid: 123 }
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* // 自定义转换函数
|
|
44
|
-
* deepTransformKeys({ user_id: 123 }, (key) => `prefix_${key}`)
|
|
45
|
-
* // { prefix_user_id: 123 }
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* // 限制递归深度
|
|
49
|
-
* deepTransformKeys(deepData, 'camel', { maxDepth: 10 })
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* // 排除特定键名
|
|
53
|
-
* deepTransformKeys({ _id: '123', user_name: 'John' }, 'camel', { excludeKeys: ['_id'] })
|
|
54
|
-
* // { _id: '123', userName: 'John' }
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* // 嵌套数组和对象
|
|
58
|
-
* deepTransformKeys({
|
|
59
|
-
* user_list: [{ user_id: 1, user_tags: [{ tag_name: 'vip' }] }]
|
|
60
|
-
* }, 'camel')
|
|
61
|
-
* // { userList: [{ userId: 1, userTags: [{ tagName: 'vip' }] }] }
|
|
62
|
-
*/
|
|
63
|
-
export const deepTransformKeys = (data, transformer, options = {}) => {
|
|
64
|
-
const { maxDepth = 100, excludeKeys = [] } = options;
|
|
65
|
-
// 获取实际的转换函数
|
|
66
|
-
let transformFn;
|
|
67
|
-
if (typeof transformer === 'function') {
|
|
68
|
-
transformFn = transformer;
|
|
69
|
-
}
|
|
70
|
-
else if (transformer === 'camel') {
|
|
71
|
-
transformFn = camelCase;
|
|
72
|
-
}
|
|
73
|
-
else if (transformer === 'snake') {
|
|
74
|
-
transformFn = snakeCase;
|
|
75
|
-
}
|
|
76
|
-
else if (transformer === 'kebab') {
|
|
77
|
-
transformFn = kebabCase;
|
|
78
|
-
}
|
|
79
|
-
else if (transformer === 'pascal') {
|
|
80
|
-
transformFn = pascalCase;
|
|
81
|
-
}
|
|
82
|
-
else if (transformer === 'upper') {
|
|
83
|
-
transformFn = (key) => key.toUpperCase();
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
transformFn = (key) => key.toLowerCase();
|
|
87
|
-
}
|
|
88
|
-
// 用于检测循环引用的 WeakSet
|
|
89
|
-
const visited = new WeakSet();
|
|
90
|
-
// 创建排除键名集合,提升查找性能
|
|
91
|
-
const excludeSet = new Set(excludeKeys);
|
|
92
|
-
// 递归转换函数
|
|
93
|
-
const transform = (value, depth) => {
|
|
94
|
-
// 处理 null 和 undefined
|
|
95
|
-
if (value === null || value === undefined) {
|
|
96
|
-
return value;
|
|
97
|
-
}
|
|
98
|
-
// 处理数组
|
|
99
|
-
if (Array.isArray(value)) {
|
|
100
|
-
// 检测循环引用
|
|
101
|
-
if (visited.has(value)) {
|
|
102
|
-
return value;
|
|
103
|
-
}
|
|
104
|
-
visited.add(value);
|
|
105
|
-
// 检查深度限制:如果达到限制,返回原数组
|
|
106
|
-
if (maxDepth > 0 && depth >= maxDepth) {
|
|
107
|
-
visited.delete(value);
|
|
108
|
-
return value;
|
|
109
|
-
}
|
|
110
|
-
const result = value.map((item) => transform(item, depth + 1));
|
|
111
|
-
visited.delete(value);
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
// 处理对象
|
|
115
|
-
if (isPlainObject(value)) {
|
|
116
|
-
// 检测循环引用
|
|
117
|
-
if (visited.has(value)) {
|
|
118
|
-
return value;
|
|
119
|
-
}
|
|
120
|
-
visited.add(value);
|
|
121
|
-
// 检查深度限制:如果达到限制,返回原对象
|
|
122
|
-
if (maxDepth > 0 && depth >= maxDepth) {
|
|
123
|
-
visited.delete(value);
|
|
124
|
-
return value;
|
|
125
|
-
}
|
|
126
|
-
const result = {};
|
|
127
|
-
for (const [key, val] of Object.entries(value)) {
|
|
128
|
-
// 检查是否在排除列表中
|
|
129
|
-
const transformedKey = excludeSet.has(key) ? key : transformFn(key);
|
|
130
|
-
result[transformedKey] = transform(val, depth + 1);
|
|
131
|
-
}
|
|
132
|
-
visited.delete(value);
|
|
133
|
-
return result;
|
|
134
|
-
}
|
|
135
|
-
// 其他类型(字符串、数字、布尔值等)直接返回
|
|
136
|
-
return value;
|
|
137
|
-
};
|
|
138
|
-
return transform(data, 0);
|
|
139
|
-
};
|
package/dist/fieldClear.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// fieldClear 工具函数实现
|
|
2
|
-
// 支持 pick/omit/keepValues/excludeValues,处理对象和数组
|
|
3
|
-
function isObject(val) {
|
|
4
|
-
return val !== null && typeof val === 'object' && !Array.isArray(val);
|
|
5
|
-
}
|
|
6
|
-
function isArray(val) {
|
|
7
|
-
return Array.isArray(val);
|
|
8
|
-
}
|
|
9
|
-
export function fieldClear(data, options = {}) {
|
|
10
|
-
const { pickKeys, omitKeys, keepValues, excludeValues, keepMap } = options;
|
|
11
|
-
const filterObj = (obj) => {
|
|
12
|
-
let result = {};
|
|
13
|
-
let keys = Object.keys(obj);
|
|
14
|
-
if (pickKeys && pickKeys.length) {
|
|
15
|
-
keys = keys.filter((k) => pickKeys.includes(k));
|
|
16
|
-
}
|
|
17
|
-
if (omitKeys && omitKeys.length) {
|
|
18
|
-
keys = keys.filter((k) => !omitKeys.includes(k));
|
|
19
|
-
}
|
|
20
|
-
for (const key of keys) {
|
|
21
|
-
const value = obj[key];
|
|
22
|
-
// 1. 优先检查 keepMap
|
|
23
|
-
if (keepMap && key in keepMap) {
|
|
24
|
-
if (Object.is(keepMap[key], value)) {
|
|
25
|
-
result[key] = value;
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// 2. 检查 keepValues (只保留指定值)
|
|
30
|
-
if (keepValues && keepValues.length && !keepValues.includes(value)) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
// 3. 检查 excludeValues (排除指定值)
|
|
34
|
-
if (excludeValues && excludeValues.length && excludeValues.includes(value)) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
result[key] = value;
|
|
38
|
-
}
|
|
39
|
-
return result;
|
|
40
|
-
};
|
|
41
|
-
if (isArray(data)) {
|
|
42
|
-
return data
|
|
43
|
-
.map((item) => (isObject(item) ? filterObj(item) : item))
|
|
44
|
-
.filter((item) => {
|
|
45
|
-
if (isObject(item)) {
|
|
46
|
-
// 只保留有内容的对象
|
|
47
|
-
return Object.keys(item).length > 0;
|
|
48
|
-
}
|
|
49
|
-
// 原始值直接保留
|
|
50
|
-
return true;
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (isObject(data)) {
|
|
54
|
-
return filterObj(data);
|
|
55
|
-
}
|
|
56
|
-
return data;
|
|
57
|
-
}
|
package/dist/genShortId.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 生成短 ID
|
|
3
|
-
* 由时间戳(base36)+ 随机字符组成,约 13 位
|
|
4
|
-
* - 前 8 位:时间戳(可排序)
|
|
5
|
-
* - 后 5 位:随机字符(防冲突)
|
|
6
|
-
* @returns 短 ID 字符串
|
|
7
|
-
* @example
|
|
8
|
-
* genShortId() // "lxyz1a2b3c4"
|
|
9
|
-
*/
|
|
10
|
-
export function genShortId() {
|
|
11
|
-
return Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
|
|
12
|
-
}
|
package/dist/hashPassword.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 密码哈希工具
|
|
3
|
-
* 使用 SHA-256 + 盐值对密码进行单向哈希
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* 使用 SHA-256 对密码进行哈希
|
|
7
|
-
* @param password - 原始密码
|
|
8
|
-
* @param salt - 盐值,默认为 befly
|
|
9
|
-
* @returns 哈希后的密码(十六进制字符串)
|
|
10
|
-
*/
|
|
11
|
-
export async function hashPassword(password, salt = 'befly') {
|
|
12
|
-
const data = password + salt;
|
|
13
|
-
// 将字符串转换为 Uint8Array
|
|
14
|
-
const encoder = new TextEncoder();
|
|
15
|
-
const dataBuffer = encoder.encode(data);
|
|
16
|
-
// 使用 Web Crypto API 进行 SHA-256 哈希
|
|
17
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
|
|
18
|
-
// 将 ArrayBuffer 转换为十六进制字符串
|
|
19
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
20
|
-
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
21
|
-
return hashHex;
|
|
22
|
-
}
|
package/dist/index.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Befly Shared 统一导出
|
|
3
|
-
* 跨包共享的工具函数、常量、类型定义
|
|
4
|
-
*/
|
|
5
|
-
// 常量(运行时)
|
|
6
|
-
export * from './constants.js';
|
|
7
|
-
// Redis 键和正则
|
|
8
|
-
export * from './redisKeys.js';
|
|
9
|
-
export * from './regex.js';
|
|
10
|
-
// 工具函数
|
|
11
|
-
export * from './addonHelper.js';
|
|
12
|
-
export * from './arrayKeysToCamel.js';
|
|
13
|
-
export * from './arrayToTree.js';
|
|
14
|
-
export * from './calcPerfTime.js';
|
|
15
|
-
export * from './configTypes.js';
|
|
16
|
-
export * from './deepTransformKeys.js';
|
|
17
|
-
export * from './genShortId.js';
|
|
18
|
-
export * from './scanConfig.js';
|
|
19
|
-
export * from './fieldClear.js';
|
|
20
|
-
export * from './keysToCamel.js';
|
|
21
|
-
export * from './keysToSnake.js';
|
|
22
|
-
export * from './layouts.js';
|
|
23
|
-
export * from './pickFields.js';
|
|
24
|
-
export * from './scanFiles.js';
|
|
25
|
-
export * from './scanViews.js';
|
|
26
|
-
export * from './withDefaultColumns.js';
|
package/dist/keysToCamel.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
import { camelCase } from 'es-toolkit/string';
|
|
3
|
-
/**
|
|
4
|
-
* 对象字段名转小驼峰
|
|
5
|
-
* @param obj - 源对象
|
|
6
|
-
* @returns 字段名转为小驼峰格式的新对象
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* keysToCamel({ user_id: 123, user_name: 'John' }) // { userId: 123, userName: 'John' }
|
|
10
|
-
* keysToCamel({ created_at: 1697452800000 }) // { createdAt: 1697452800000 }
|
|
11
|
-
*/
|
|
12
|
-
export const keysToCamel = (obj) => {
|
|
13
|
-
if (!obj || !isPlainObject(obj))
|
|
14
|
-
return obj;
|
|
15
|
-
const result = {};
|
|
16
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
17
|
-
const camelKey = camelCase(key);
|
|
18
|
-
result[camelKey] = value;
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
};
|
package/dist/keysToSnake.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
import { snakeCase } from 'es-toolkit/string';
|
|
3
|
-
/**
|
|
4
|
-
* 对象字段名转下划线
|
|
5
|
-
* @param obj - 源对象
|
|
6
|
-
* @returns 字段名转为下划线格式的新对象
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* keysToSnake({ userId: 123, userName: 'John' }) // { user_id: 123, user_name: 'John' }
|
|
10
|
-
* keysToSnake({ createdAt: 1697452800000 }) // { created_at: 1697452800000 }
|
|
11
|
-
*/
|
|
12
|
-
export const keysToSnake = (obj) => {
|
|
13
|
-
if (!obj || !isPlainObject(obj))
|
|
14
|
-
return obj;
|
|
15
|
-
const result = {};
|
|
16
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
17
|
-
const snakeKey = snakeCase(key);
|
|
18
|
-
result[snakeKey] = value;
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
};
|
package/dist/layouts.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 自定义布局处理函数
|
|
3
|
-
* 根据文件名后缀判断使用哪个布局
|
|
4
|
-
* @param routes - 原始路由配置
|
|
5
|
-
* @param inheritLayout - 继承的布局名称(来自父级目录)
|
|
6
|
-
* @returns 处理后的布局配置(不包含实际的布局组件导入)
|
|
7
|
-
*/
|
|
8
|
-
export function Layouts(routes, inheritLayout = '') {
|
|
9
|
-
const result = [];
|
|
10
|
-
for (const route of routes) {
|
|
11
|
-
const currentPath = route.path || '';
|
|
12
|
-
// 检查当前路径是否有 _数字 格式
|
|
13
|
-
const pathMatch = currentPath.match(/_(\d+)$/);
|
|
14
|
-
const currentLayout = pathMatch ? pathMatch[1] : inheritLayout;
|
|
15
|
-
// 如果有子路由,说明这是中间节点(目录),不包裹布局,只递归处理子路由
|
|
16
|
-
if (route.children && route.children.length > 0) {
|
|
17
|
-
// 清理路径:如果是 xxx_数字 格式,去掉 _数字
|
|
18
|
-
const cleanPath = pathMatch ? currentPath.replace(/_\d+$/, '') : currentPath;
|
|
19
|
-
// 直接递归处理子路由,不添加当前层级到结果
|
|
20
|
-
const childConfigs = Layouts(route.children, currentLayout);
|
|
21
|
-
// 将子路由的路径前缀加上当前路径
|
|
22
|
-
for (const child of childConfigs) {
|
|
23
|
-
result.push({
|
|
24
|
-
...child,
|
|
25
|
-
path: cleanPath ? `${cleanPath}/${child.path}`.replace(/\/+/g, '/') : child.path
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
// 没有子路由的叶子节点,需要包裹布局
|
|
31
|
-
const lastPart = currentPath;
|
|
32
|
-
// 匹配 _数字 格式(如 index_1, news_2)
|
|
33
|
-
const match = lastPart.match(/_(\d+)$/);
|
|
34
|
-
// 优先使用文件自己的布局,其次使用继承的布局,最后使用 default
|
|
35
|
-
const layoutName = match ? match[1] : currentLayout || 'default';
|
|
36
|
-
// 计算清理后的路径
|
|
37
|
-
let cleanPath;
|
|
38
|
-
if (lastPart === 'index' || (lastPart.startsWith('index_') && match)) {
|
|
39
|
-
// index 或 index_数字 → 改为空路径(由父级路径表示)
|
|
40
|
-
cleanPath = '';
|
|
41
|
-
}
|
|
42
|
-
else if (match) {
|
|
43
|
-
// xxx_数字 → 去掉 _数字 后缀
|
|
44
|
-
cleanPath = lastPart.replace(/_\d+$/, '');
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
// 其他 → 保持原样
|
|
48
|
-
cleanPath = lastPart;
|
|
49
|
-
}
|
|
50
|
-
// 返回布局配置(不执行实际导入)
|
|
51
|
-
result.push({
|
|
52
|
-
path: cleanPath,
|
|
53
|
-
layoutName: layoutName,
|
|
54
|
-
component: route.component,
|
|
55
|
-
meta: route.meta
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
return result;
|
|
59
|
-
}
|
package/dist/pickFields.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
/**
|
|
3
|
-
* 挑选指定字段
|
|
4
|
-
*/
|
|
5
|
-
export const pickFields = (obj, keys) => {
|
|
6
|
-
if (!obj || (!isPlainObject(obj) && !Array.isArray(obj))) {
|
|
7
|
-
return {};
|
|
8
|
-
}
|
|
9
|
-
const result = {};
|
|
10
|
-
for (const key of keys) {
|
|
11
|
-
if (key in obj) {
|
|
12
|
-
result[key] = obj[key];
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return result;
|
|
16
|
-
};
|
package/dist/redisKeys.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Redis Key 统一管理
|
|
3
|
-
* 所有 Redis 缓存键在此统一定义,避免硬编码分散
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Redis Key 生成函数集合
|
|
7
|
-
*/
|
|
8
|
-
export const RedisKeys = {
|
|
9
|
-
/** 所有接口缓存 */
|
|
10
|
-
apisAll: () => 'befly:apis:all',
|
|
11
|
-
/** 所有菜单缓存 */
|
|
12
|
-
menusAll: () => 'befly:menus:all',
|
|
13
|
-
/** 角色信息缓存(完整角色对象) */
|
|
14
|
-
roleInfo: (roleCode) => `befly:role:info:${roleCode}`,
|
|
15
|
-
/** 角色接口权限缓存(Set 集合) */
|
|
16
|
-
roleApis: (roleCode) => `befly:role:apis:${roleCode}`,
|
|
17
|
-
/** 表结构缓存 */
|
|
18
|
-
tableColumns: (table) => `befly:table:columns:${table}`
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Redis TTL(过期时间)常量配置(单位:秒)
|
|
22
|
-
*/
|
|
23
|
-
export const RedisTTL = {
|
|
24
|
-
/** 表结构缓存 - 1小时 */
|
|
25
|
-
tableColumns: 3600,
|
|
26
|
-
/** 角色接口权限 - 24小时 */
|
|
27
|
-
roleApis: 86400,
|
|
28
|
-
/** 角色信息 - 24小时 */
|
|
29
|
-
roleInfo: 86400,
|
|
30
|
-
/** 接口列表 - 永久(不过期) */
|
|
31
|
-
apisAll: null,
|
|
32
|
-
/** 菜单列表 - 永久(不过期) */
|
|
33
|
-
menusAll: null
|
|
34
|
-
};
|
package/dist/regex.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 内置正则表达式别名
|
|
3
|
-
* 用于表单验证和数据校验
|
|
4
|
-
* 命名规范:小驼峰格式
|
|
5
|
-
*/
|
|
6
|
-
export const RegexAliases = {
|
|
7
|
-
// ============================================
|
|
8
|
-
// 数字类型
|
|
9
|
-
// ============================================
|
|
10
|
-
/** 正整数(不含0) */
|
|
11
|
-
number: '^\\d+$',
|
|
12
|
-
/** 整数(含负数) */
|
|
13
|
-
integer: '^-?\\d+$',
|
|
14
|
-
/** 浮点数 */
|
|
15
|
-
float: '^-?\\d+(\\.\\d+)?$',
|
|
16
|
-
/** 正整数(不含0) */
|
|
17
|
-
positive: '^[1-9]\\d*$',
|
|
18
|
-
/** 负整数 */
|
|
19
|
-
negative: '^-\\d+$',
|
|
20
|
-
/** 零 */
|
|
21
|
-
zero: '^0$',
|
|
22
|
-
// ============================================
|
|
23
|
-
// 字符串类型
|
|
24
|
-
// ============================================
|
|
25
|
-
/** 纯字母 */
|
|
26
|
-
word: '^[a-zA-Z]+$',
|
|
27
|
-
/** 字母和数字 */
|
|
28
|
-
alphanumeric: '^[a-zA-Z0-9]+$',
|
|
29
|
-
/** 字母、数字和下划线 */
|
|
30
|
-
alphanumeric_: '^[a-zA-Z0-9_]+$',
|
|
31
|
-
/** 字母、数字、下划线和短横线 */
|
|
32
|
-
alphanumericDash_: '^[a-zA-Z0-9_-]+$',
|
|
33
|
-
/** 小写字母 */
|
|
34
|
-
lowercase: '^[a-z]+$',
|
|
35
|
-
/** 大写字母 */
|
|
36
|
-
uppercase: '^[A-Z]+$',
|
|
37
|
-
// ============================================
|
|
38
|
-
// 中文
|
|
39
|
-
// ============================================
|
|
40
|
-
/** 纯中文 */
|
|
41
|
-
chinese: '^[\\u4e00-\\u9fa5]+$',
|
|
42
|
-
/** 中文和字母 */
|
|
43
|
-
chineseWord: '^[\\u4e00-\\u9fa5a-zA-Z]+$',
|
|
44
|
-
// ============================================
|
|
45
|
-
// 常用格式
|
|
46
|
-
// ============================================
|
|
47
|
-
/** 邮箱地址 */
|
|
48
|
-
email: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
|
|
49
|
-
/** 中国大陆手机号 */
|
|
50
|
-
phone: '^1[3-9]\\d{9}$',
|
|
51
|
-
/** 固定电话(区号-号码) */
|
|
52
|
-
telephone: '^0\\d{2,3}-?\\d{7,8}$',
|
|
53
|
-
/** URL 地址 */
|
|
54
|
-
url: '^https?://',
|
|
55
|
-
/** IPv4 地址 */
|
|
56
|
-
ip: '^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$',
|
|
57
|
-
/** IPv6 地址 */
|
|
58
|
-
ipv6: '^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$',
|
|
59
|
-
/** 域名 */
|
|
60
|
-
domain: '^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$',
|
|
61
|
-
// ============================================
|
|
62
|
-
// 特殊格式
|
|
63
|
-
// ============================================
|
|
64
|
-
/** UUID */
|
|
65
|
-
uuid: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
|
|
66
|
-
/** 十六进制字符串 */
|
|
67
|
-
hex: '^[0-9a-fA-F]+$',
|
|
68
|
-
/** Base64 编码 */
|
|
69
|
-
base64: '^[A-Za-z0-9+/=]+$',
|
|
70
|
-
/** MD5 哈希 */
|
|
71
|
-
md5: '^[a-f0-9]{32}$',
|
|
72
|
-
/** SHA1 哈希 */
|
|
73
|
-
sha1: '^[a-f0-9]{40}$',
|
|
74
|
-
/** SHA256 哈希 */
|
|
75
|
-
sha256: '^[a-f0-9]{64}$',
|
|
76
|
-
// ============================================
|
|
77
|
-
// 日期时间
|
|
78
|
-
// ============================================
|
|
79
|
-
/** 日期 YYYY-MM-DD */
|
|
80
|
-
date: '^\\d{4}-\\d{2}-\\d{2}$',
|
|
81
|
-
/** 时间 HH:MM:SS */
|
|
82
|
-
time: '^\\d{2}:\\d{2}:\\d{2}$',
|
|
83
|
-
/** ISO 日期时间 */
|
|
84
|
-
datetime: '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}',
|
|
85
|
-
/** 年份 */
|
|
86
|
-
year: '^\\d{4}$',
|
|
87
|
-
/** 月份 01-12 */
|
|
88
|
-
month: '^(0[1-9]|1[0-2])$',
|
|
89
|
-
/** 日期 01-31 */
|
|
90
|
-
day: '^(0[1-9]|[12]\\d|3[01])$',
|
|
91
|
-
// ============================================
|
|
92
|
-
// 代码相关
|
|
93
|
-
// ============================================
|
|
94
|
-
/** 变量名 */
|
|
95
|
-
variable: '^[a-zA-Z_][a-zA-Z0-9_]*$',
|
|
96
|
-
/** 常量名(全大写) */
|
|
97
|
-
constant: '^[A-Z][A-Z0-9_]*$',
|
|
98
|
-
/** 包名(小写+连字符) */
|
|
99
|
-
package: '^[a-z][a-z0-9-]*$',
|
|
100
|
-
// ============================================
|
|
101
|
-
// 证件相关
|
|
102
|
-
// ============================================
|
|
103
|
-
/** 中国身份证号(18位) */
|
|
104
|
-
idCard: '^\\d{17}[\\dXx]$',
|
|
105
|
-
/** 护照号 */
|
|
106
|
-
passport: '^[a-zA-Z0-9]{5,17}$',
|
|
107
|
-
// ============================================
|
|
108
|
-
// 账号相关(国内常用)
|
|
109
|
-
// ============================================
|
|
110
|
-
/** 银行卡号(16-19位数字) */
|
|
111
|
-
bankCard: '^\\d{16,19}$',
|
|
112
|
-
/** 微信号(6-20位,字母开头,可包含字母、数字、下划线、减号) */
|
|
113
|
-
wechat: '^[a-zA-Z][a-zA-Z0-9_-]{5,19}$',
|
|
114
|
-
/** QQ号(5-11位数字,首位非0) */
|
|
115
|
-
qq: '^[1-9]\\d{4,10}$',
|
|
116
|
-
/** 支付宝账号(手机号或邮箱) */
|
|
117
|
-
alipay: '^(1[3-9]\\d{9}|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$',
|
|
118
|
-
/** 用户名(4-20位,字母开头,可包含字母、数字、下划线) */
|
|
119
|
-
username: '^[a-zA-Z][a-zA-Z0-9_]{3,19}$',
|
|
120
|
-
/** 昵称(2-20位,支持中文、字母、数字) */
|
|
121
|
-
nickname: '^[\\u4e00-\\u9fa5a-zA-Z0-9]{2,20}$',
|
|
122
|
-
// ============================================
|
|
123
|
-
// 密码强度
|
|
124
|
-
// ============================================
|
|
125
|
-
/** 弱密码(至少6位) */
|
|
126
|
-
passwordWeak: '^.{6,}$',
|
|
127
|
-
/** 中等密码(至少8位,包含字母和数字) */
|
|
128
|
-
passwordMedium: '^(?=.*[a-zA-Z])(?=.*\\d).{8,}$',
|
|
129
|
-
/** 强密码(至少8位,包含大小写字母、数字和特殊字符) */
|
|
130
|
-
passwordStrong: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*]).{8,}$',
|
|
131
|
-
// ============================================
|
|
132
|
-
// 其他常用
|
|
133
|
-
// ============================================
|
|
134
|
-
/** 车牌号(新能源+普通) */
|
|
135
|
-
licensePlate: '^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$',
|
|
136
|
-
/** 邮政编码 */
|
|
137
|
-
postalCode: '^\\d{6}$',
|
|
138
|
-
/** 版本号(语义化版本) */
|
|
139
|
-
semver: '^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$',
|
|
140
|
-
/** 颜色值(十六进制) */
|
|
141
|
-
colorHex: '^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$',
|
|
142
|
-
// ============================================
|
|
143
|
-
// 空值
|
|
144
|
-
// ============================================
|
|
145
|
-
/** 空字符串 */
|
|
146
|
-
empty: '^$',
|
|
147
|
-
/** 非空 */
|
|
148
|
-
notempty: '.+'
|
|
149
|
-
};
|
|
150
|
-
// ============================================
|
|
151
|
-
// 正则表达式缓存(性能优化)
|
|
152
|
-
// ============================================
|
|
153
|
-
const regexCache = new Map();
|
|
154
|
-
/**
|
|
155
|
-
* 获取正则表达式字符串
|
|
156
|
-
* @param name 正则别名(以 @ 开头)或自定义正则字符串
|
|
157
|
-
* @returns 正则表达式字符串
|
|
158
|
-
*/
|
|
159
|
-
export function getRegex(name) {
|
|
160
|
-
if (name.startsWith('@')) {
|
|
161
|
-
const alias = name.slice(1);
|
|
162
|
-
return RegexAliases[alias] || name;
|
|
163
|
-
}
|
|
164
|
-
return name;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* 获取编译后的正则表达式对象(带缓存)
|
|
168
|
-
* @param pattern 正则别名或正则字符串
|
|
169
|
-
* @param flags 正则标志(如 'i', 'g')
|
|
170
|
-
* @returns 编译后的 RegExp 对象
|
|
171
|
-
*/
|
|
172
|
-
export function getCompiledRegex(pattern, flags) {
|
|
173
|
-
const regexStr = getRegex(pattern);
|
|
174
|
-
const cacheKey = `${regexStr}:${flags || ''}`;
|
|
175
|
-
let cached = regexCache.get(cacheKey);
|
|
176
|
-
if (!cached) {
|
|
177
|
-
cached = new RegExp(regexStr, flags);
|
|
178
|
-
regexCache.set(cacheKey, cached);
|
|
179
|
-
}
|
|
180
|
-
return cached;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* 验证值是否匹配正则(使用缓存)
|
|
184
|
-
* @param value 要验证的值
|
|
185
|
-
* @param pattern 正则别名或正则字符串
|
|
186
|
-
* @returns 是否匹配
|
|
187
|
-
*/
|
|
188
|
-
export function matchRegex(value, pattern) {
|
|
189
|
-
return getCompiledRegex(pattern).test(value);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* 清除正则缓存
|
|
193
|
-
*/
|
|
194
|
-
export function clearRegexCache() {
|
|
195
|
-
regexCache.clear();
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* 获取缓存大小
|
|
199
|
-
*/
|
|
200
|
-
export function getRegexCacheSize() {
|
|
201
|
-
return regexCache.size;
|
|
202
|
-
}
|