befly-shared 1.2.7 → 1.3.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/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/fieldClear.js +0 -57
- package/dist/genShortId.js +0 -12
- package/dist/hashPassword.js +0 -22
- package/dist/index.js +0 -25
- 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/fieldClear.ts +0 -75
- package/src/genShortId.ts +0 -12
- package/src/hashPassword.ts +0 -27
- package/src/index.ts +0 -28
- 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/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/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 -22
- 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
package/src/addonHelper.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { join } from 'pathe';
|
|
3
|
-
import { statSync, existsSync } from 'node:fs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 扫描所有可用的 addon
|
|
7
|
-
* 优先从本地 addons/ 目录加载,其次从 node_modules/@befly-addon/ 加载
|
|
8
|
-
* @param cwd - 项目根目录,默认为 process.cwd()
|
|
9
|
-
* @returns addon 名称数组
|
|
10
|
-
*/
|
|
11
|
-
export const scanAddons = (cwd: string = process.cwd()): string[] => {
|
|
12
|
-
const addons = new Set<string>();
|
|
13
|
-
// const projectAddonsDir = join(cwd, 'addons');
|
|
14
|
-
|
|
15
|
-
// 1. 扫描本地 addons 目录(优先级高)
|
|
16
|
-
// if (existsSync(projectAddonsDir)) {
|
|
17
|
-
// try {
|
|
18
|
-
// const localAddons = fs.readdirSync(projectAddonsDir).filter((name) => {
|
|
19
|
-
// const fullPath = join(projectAddonsDir, name);
|
|
20
|
-
// try {
|
|
21
|
-
// const stat = statSync(fullPath);
|
|
22
|
-
// return stat.isDirectory() && !name.startsWith('_');
|
|
23
|
-
// } catch {
|
|
24
|
-
// return false;
|
|
25
|
-
// }
|
|
26
|
-
// });
|
|
27
|
-
// localAddons.forEach((name) => addons.add(name));
|
|
28
|
-
// } catch (err) {
|
|
29
|
-
// // 忽略本地目录读取错误
|
|
30
|
-
// }
|
|
31
|
-
// }
|
|
32
|
-
|
|
33
|
-
// 2. 扫描 node_modules/@befly-addon 目录
|
|
34
|
-
const beflyDir = join(cwd, 'node_modules', '@befly-addon');
|
|
35
|
-
if (existsSync(beflyDir)) {
|
|
36
|
-
try {
|
|
37
|
-
const npmAddons = fs.readdirSync(beflyDir).filter((name) => {
|
|
38
|
-
// 如果本地已存在,跳过 npm 包版本
|
|
39
|
-
if (addons.has(name)) return false;
|
|
40
|
-
|
|
41
|
-
const fullPath = join(beflyDir, name);
|
|
42
|
-
try {
|
|
43
|
-
const stat = statSync(fullPath);
|
|
44
|
-
return stat.isDirectory();
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
npmAddons.forEach((name) => addons.add(name));
|
|
50
|
-
} catch {
|
|
51
|
-
// 忽略 npm 目录读取错误
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return Array.from(addons).sort();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 获取 addon 的指定子目录路径
|
|
60
|
-
* 优先返回本地 addons 目录,其次返回 node_modules 目录
|
|
61
|
-
* @param name - addon 名称
|
|
62
|
-
* @param subDir - 子目录名称
|
|
63
|
-
* @param cwd - 项目根目录,默认为 process.cwd()
|
|
64
|
-
* @returns 完整路径
|
|
65
|
-
*/
|
|
66
|
-
export const getAddonDir = (name: string, subDir: string, cwd: string = process.cwd()): string => {
|
|
67
|
-
// 优先使用本地 addons 目录
|
|
68
|
-
// const projectAddonsDir = join(cwd, 'addons');
|
|
69
|
-
// const localPath = join(projectAddonsDir, name, subDir);
|
|
70
|
-
// if (existsSync(localPath)) {
|
|
71
|
-
// return localPath;
|
|
72
|
-
// }
|
|
73
|
-
|
|
74
|
-
// 降级使用 node_modules 目录
|
|
75
|
-
return join(cwd, 'node_modules', '@befly-addon', name, subDir);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 检查 addon 子目录是否存在
|
|
80
|
-
* @param name - addon 名称
|
|
81
|
-
* @param subDir - 子目录名称
|
|
82
|
-
* @param cwd - 项目根目录,默认为 process.cwd()
|
|
83
|
-
* @returns 是否存在
|
|
84
|
-
*/
|
|
85
|
-
export const addonDirExists = (name: string, subDir: string, cwd: string = process.cwd()): boolean => {
|
|
86
|
-
const dir = getAddonDir(name, subDir, cwd);
|
|
87
|
-
return existsSync(dir) && statSync(dir).isDirectory();
|
|
88
|
-
};
|
package/src/arrayKeysToCamel.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { keysToCamel } from './keysToCamel.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 数组对象字段名批量转小驼峰
|
|
5
|
-
* @param arr - 源数组
|
|
6
|
-
* @returns 字段名转为小驼峰格式的新数组
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* arrayKeysToCamel([
|
|
10
|
-
* { user_id: 1, user_name: 'John' },
|
|
11
|
-
* { user_id: 2, user_name: 'Jane' }
|
|
12
|
-
* ])
|
|
13
|
-
* // [{ userId: 1, userName: 'John' }, { userId: 2, userName: 'Jane' }]
|
|
14
|
-
*/
|
|
15
|
-
export const arrayKeysToCamel = <T = any>(arr: Record<string, any>[]): T[] => {
|
|
16
|
-
if (!arr || !Array.isArray(arr)) return arr as T[];
|
|
17
|
-
return arr.map((item) => keysToCamel<T>(item));
|
|
18
|
-
};
|
package/src/arrayToTree.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// arrayToTree 工具函数实现
|
|
2
|
-
|
|
3
|
-
export interface ArrayToTreeOptions<T = any> {
|
|
4
|
-
idField?: string; // 节点 id 字段名,默认 'id'
|
|
5
|
-
pidField?: string; // 父节点 id 字段名,默认 'pid'
|
|
6
|
-
childrenField?: string; // 子节点字段名,默认 'children'
|
|
7
|
-
rootPid?: any; // 根节点的父 id,默认 0
|
|
8
|
-
mapFn?: (node: T) => T; // 节点转换函数
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function arrayToTree<T = any>(items: T[], options: ArrayToTreeOptions<T> = {}): T[] {
|
|
12
|
-
const { idField = 'id', pidField = 'pid', childrenField = 'children', rootPid = 0, mapFn } = options;
|
|
13
|
-
const tree: T[] = [];
|
|
14
|
-
for (const item of items) {
|
|
15
|
-
const pid = (item as any)[pidField];
|
|
16
|
-
// 用 Object.is 判断,兼容 null/undefined/0
|
|
17
|
-
if (Object.is(pid, rootPid)) {
|
|
18
|
-
let node = { ...item };
|
|
19
|
-
if (mapFn) node = mapFn(node);
|
|
20
|
-
const children = arrayToTree(items, {
|
|
21
|
-
...options,
|
|
22
|
-
rootPid: (node as any)[idField]
|
|
23
|
-
});
|
|
24
|
-
if (children.length > 0) {
|
|
25
|
-
(node as any)[childrenField] = children;
|
|
26
|
-
}
|
|
27
|
-
tree.push(node);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return tree;
|
|
31
|
-
}
|
package/src/calcPerfTime.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 计算性能时间差
|
|
3
|
-
*/
|
|
4
|
-
export const calcPerfTime = (startTime: number, endTime: number = Bun.nanoseconds()): string => {
|
|
5
|
-
const elapsedMs = (endTime - startTime) / 1_000_000;
|
|
6
|
-
|
|
7
|
-
if (elapsedMs < 1000) {
|
|
8
|
-
return `${elapsedMs.toFixed(2)} 毫秒`;
|
|
9
|
-
} else {
|
|
10
|
-
const elapsedSeconds = elapsedMs / 1000;
|
|
11
|
-
return `${elapsedSeconds.toFixed(2)} 秒`;
|
|
12
|
-
}
|
|
13
|
-
};
|
package/src/configTypes.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 加载配置选项
|
|
3
|
-
*/
|
|
4
|
-
export interface LoadConfigOptions {
|
|
5
|
-
/** 当前工作目录,默认 process.cwd() */
|
|
6
|
-
cwd?: string;
|
|
7
|
-
/** 目录数组:要搜索的目录路径(相对于 cwd) */
|
|
8
|
-
dirs: string[];
|
|
9
|
-
/** 文件数组:要匹配的文件名 */
|
|
10
|
-
files: string[];
|
|
11
|
-
/** 文件扩展名,默认 ['.js', '.ts', '.json'] */
|
|
12
|
-
extensions?: string[];
|
|
13
|
-
/** 加载模式:'first' = 返回第一个找到的配置(默认),'merge' = 合并所有配置 */
|
|
14
|
-
mode?: 'merge' | 'first';
|
|
15
|
-
/** 指定要提取的字段路径数组,如 ['menus', 'database.host'],为空则返回完整对象 */
|
|
16
|
-
paths?: string[];
|
|
17
|
-
/** 默认配置,会与找到的配置合并(优先级最低) */
|
|
18
|
-
defaults?: Record<string, any>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Addon 配置合并选项(已废弃,仅用于向后兼容)
|
|
23
|
-
*/
|
|
24
|
-
export interface MergeConfigOptions {
|
|
25
|
-
/** 合并策略(已废弃,始终使用 deep) */
|
|
26
|
-
strategy?: 'deep' | 'shallow' | 'override';
|
|
27
|
-
/** 是否克隆数据(已废弃) */
|
|
28
|
-
clone?: boolean;
|
|
29
|
-
}
|
package/src/constants.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Befly 共享常量定义
|
|
3
|
-
* 运行时使用的常量(非纯类型)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ============================================
|
|
7
|
-
// API 响应码常量
|
|
8
|
-
// ============================================
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* API 响应码
|
|
12
|
-
*/
|
|
13
|
-
export const ApiCode = {
|
|
14
|
-
/** 成功 */
|
|
15
|
-
SUCCESS: 0,
|
|
16
|
-
/** 通用失败 */
|
|
17
|
-
FAIL: 1,
|
|
18
|
-
/** 未授权 */
|
|
19
|
-
UNAUTHORIZED: 401,
|
|
20
|
-
/** 禁止访问 */
|
|
21
|
-
FORBIDDEN: 403,
|
|
22
|
-
/** 未找到 */
|
|
23
|
-
NOT_FOUND: 404,
|
|
24
|
-
/** 服务器错误 */
|
|
25
|
-
SERVER_ERROR: 500
|
|
26
|
-
} as const;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* API 响应码类型
|
|
30
|
-
*/
|
|
31
|
-
export type ApiCodeType = (typeof ApiCode)[keyof typeof ApiCode];
|
|
32
|
-
|
|
33
|
-
// ============================================
|
|
34
|
-
// 错误消息常量
|
|
35
|
-
// ============================================
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 通用错误消息
|
|
39
|
-
*/
|
|
40
|
-
export const ErrorMessages = {
|
|
41
|
-
/** 未授权 */
|
|
42
|
-
UNAUTHORIZED: '请先登录',
|
|
43
|
-
/** 禁止访问 */
|
|
44
|
-
FORBIDDEN: '无访问权限',
|
|
45
|
-
/** 未找到 */
|
|
46
|
-
NOT_FOUND: '资源不存在',
|
|
47
|
-
/** 服务器错误 */
|
|
48
|
-
SERVER_ERROR: '服务器错误',
|
|
49
|
-
/** 参数错误 */
|
|
50
|
-
INVALID_PARAMS: '参数错误',
|
|
51
|
-
/** Token 过期 */
|
|
52
|
-
TOKEN_EXPIRED: 'Token 已过期',
|
|
53
|
-
/** Token 无效 */
|
|
54
|
-
TOKEN_INVALID: 'Token 无效'
|
|
55
|
-
} as const;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 错误消息类型
|
|
59
|
-
*/
|
|
60
|
-
export type ErrorMessageType = (typeof ErrorMessages)[keyof typeof ErrorMessages];
|
package/src/fieldClear.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
// fieldClear 工具函数实现
|
|
2
|
-
// 支持 pick/omit/keepValues/excludeValues,处理对象和数组
|
|
3
|
-
|
|
4
|
-
export interface FieldClearOptions {
|
|
5
|
-
pickKeys?: string[]; // 只保留这些字段
|
|
6
|
-
omitKeys?: string[]; // 排除这些字段
|
|
7
|
-
keepValues?: any[]; // 只保留这些值
|
|
8
|
-
excludeValues?: any[]; // 排除这些值
|
|
9
|
-
keepMap?: Record<string, any>; // 强制保留的键值对(优先级最高,忽略 excludeValues)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type FieldClearResult<T> = T extends Array<infer U> ? Array<FieldClearResult<U>> : T extends object ? { [K in keyof T]?: T[K] } : T;
|
|
13
|
-
|
|
14
|
-
function isObject(val: unknown): val is Record<string, any> {
|
|
15
|
-
return val !== null && typeof val === 'object' && !Array.isArray(val);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function isArray(val: unknown): val is any[] {
|
|
19
|
-
return Array.isArray(val);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function fieldClear<T = any>(data: T | T[], options: FieldClearOptions = {}): FieldClearResult<T> {
|
|
23
|
-
const { pickKeys, omitKeys, keepValues, excludeValues, keepMap } = options;
|
|
24
|
-
|
|
25
|
-
const filterObj = (obj: Record<string, any>) => {
|
|
26
|
-
let result: Record<string, any> = {};
|
|
27
|
-
let keys = Object.keys(obj);
|
|
28
|
-
if (pickKeys && pickKeys.length) {
|
|
29
|
-
keys = keys.filter((k) => pickKeys.includes(k));
|
|
30
|
-
}
|
|
31
|
-
if (omitKeys && omitKeys.length) {
|
|
32
|
-
keys = keys.filter((k) => !omitKeys.includes(k));
|
|
33
|
-
}
|
|
34
|
-
for (const key of keys) {
|
|
35
|
-
const value = obj[key];
|
|
36
|
-
|
|
37
|
-
// 1. 优先检查 keepMap
|
|
38
|
-
if (keepMap && key in keepMap) {
|
|
39
|
-
if (Object.is(keepMap[key], value)) {
|
|
40
|
-
result[key] = value;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 2. 检查 keepValues (只保留指定值)
|
|
46
|
-
if (keepValues && keepValues.length && !keepValues.includes(value)) {
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// 3. 检查 excludeValues (排除指定值)
|
|
51
|
-
if (excludeValues && excludeValues.length && excludeValues.includes(value)) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
result[key] = value;
|
|
55
|
-
}
|
|
56
|
-
return result;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
if (isArray(data)) {
|
|
60
|
-
return (data as any[])
|
|
61
|
-
.map((item) => (isObject(item) ? filterObj(item) : item))
|
|
62
|
-
.filter((item) => {
|
|
63
|
-
if (isObject(item)) {
|
|
64
|
-
// 只保留有内容的对象
|
|
65
|
-
return Object.keys(item).length > 0;
|
|
66
|
-
}
|
|
67
|
-
// 原始值直接保留
|
|
68
|
-
return true;
|
|
69
|
-
}) as FieldClearResult<T>;
|
|
70
|
-
}
|
|
71
|
-
if (isObject(data)) {
|
|
72
|
-
return filterObj(data as Record<string, any>) as FieldClearResult<T>;
|
|
73
|
-
}
|
|
74
|
-
return data as FieldClearResult<T>;
|
|
75
|
-
}
|
package/src/genShortId.ts
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(): string {
|
|
11
|
-
return Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
|
|
12
|
-
}
|
package/src/hashPassword.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 密码哈希工具
|
|
3
|
-
* 使用 SHA-256 + 盐值对密码进行单向哈希
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 使用 SHA-256 对密码进行哈希
|
|
8
|
-
* @param password - 原始密码
|
|
9
|
-
* @param salt - 盐值,默认为 befly
|
|
10
|
-
* @returns 哈希后的密码(十六进制字符串)
|
|
11
|
-
*/
|
|
12
|
-
export async function hashPassword(password: string, salt: string = 'befly'): Promise<string> {
|
|
13
|
-
const data = password + salt;
|
|
14
|
-
|
|
15
|
-
// 将字符串转换为 Uint8Array
|
|
16
|
-
const encoder = new TextEncoder();
|
|
17
|
-
const dataBuffer = encoder.encode(data);
|
|
18
|
-
|
|
19
|
-
// 使用 Web Crypto API 进行 SHA-256 哈希
|
|
20
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
|
|
21
|
-
|
|
22
|
-
// 将 ArrayBuffer 转换为十六进制字符串
|
|
23
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
24
|
-
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
25
|
-
|
|
26
|
-
return hashHex;
|
|
27
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Befly Shared 统一导出
|
|
3
|
-
* 跨包共享的工具函数、常量、类型定义
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// 常量(运行时)
|
|
7
|
-
export * from './constants.js';
|
|
8
|
-
|
|
9
|
-
// Redis 键和正则
|
|
10
|
-
export * from './redisKeys.js';
|
|
11
|
-
export * from './regex.js';
|
|
12
|
-
|
|
13
|
-
// 工具函数
|
|
14
|
-
export * from './addonHelper.js';
|
|
15
|
-
export * from './arrayKeysToCamel.js';
|
|
16
|
-
export * from './arrayToTree.js';
|
|
17
|
-
export * from './calcPerfTime.js';
|
|
18
|
-
export * from './configTypes.js';
|
|
19
|
-
export * from './genShortId.js';
|
|
20
|
-
export * from './scanConfig.js';
|
|
21
|
-
export * from './fieldClear.js';
|
|
22
|
-
export * from './keysToCamel.js';
|
|
23
|
-
export * from './keysToSnake.js';
|
|
24
|
-
export * from './layouts.js';
|
|
25
|
-
export * from './pickFields.js';
|
|
26
|
-
export * from './scanFiles.js';
|
|
27
|
-
export * from './scanViews.js';
|
|
28
|
-
export * from './withDefaultColumns.js';
|
package/src/keysToCamel.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
import { camelCase } from 'es-toolkit/string';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 对象字段名转小驼峰
|
|
6
|
-
* @param obj - 源对象
|
|
7
|
-
* @returns 字段名转为小驼峰格式的新对象
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* keysToCamel({ user_id: 123, user_name: 'John' }) // { userId: 123, userName: 'John' }
|
|
11
|
-
* keysToCamel({ created_at: 1697452800000 }) // { createdAt: 1697452800000 }
|
|
12
|
-
*/
|
|
13
|
-
export const keysToCamel = <T = any>(obj: Record<string, any>): T => {
|
|
14
|
-
if (!obj || !isPlainObject(obj)) return obj as T;
|
|
15
|
-
|
|
16
|
-
const result: any = {};
|
|
17
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
18
|
-
const camelKey = camelCase(key);
|
|
19
|
-
result[camelKey] = value;
|
|
20
|
-
}
|
|
21
|
-
return result;
|
|
22
|
-
};
|
package/src/keysToSnake.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
import { snakeCase } from 'es-toolkit/string';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 对象字段名转下划线
|
|
6
|
-
* @param obj - 源对象
|
|
7
|
-
* @returns 字段名转为下划线格式的新对象
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* keysToSnake({ userId: 123, userName: 'John' }) // { user_id: 123, user_name: 'John' }
|
|
11
|
-
* keysToSnake({ createdAt: 1697452800000 }) // { created_at: 1697452800000 }
|
|
12
|
-
*/
|
|
13
|
-
export const keysToSnake = <T = any>(obj: Record<string, any>): T => {
|
|
14
|
-
if (!obj || !isPlainObject(obj)) return obj as T;
|
|
15
|
-
|
|
16
|
-
const result: any = {};
|
|
17
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
18
|
-
const snakeKey = snakeCase(key);
|
|
19
|
-
result[snakeKey] = value;
|
|
20
|
-
}
|
|
21
|
-
return result;
|
|
22
|
-
};
|
package/src/layouts.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 路由配置接口
|
|
3
|
-
*/
|
|
4
|
-
export interface RouteConfig {
|
|
5
|
-
path?: string;
|
|
6
|
-
component?: any;
|
|
7
|
-
children?: RouteConfig[];
|
|
8
|
-
meta?: Record<string, any>;
|
|
9
|
-
[key: string]: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 布局配置接口
|
|
14
|
-
*/
|
|
15
|
-
export interface LayoutConfig {
|
|
16
|
-
path: string;
|
|
17
|
-
layoutName: string;
|
|
18
|
-
component: any;
|
|
19
|
-
children?: LayoutConfig[];
|
|
20
|
-
meta?: Record<string, any>;
|
|
21
|
-
[key: string]: any;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 自定义布局处理函数
|
|
26
|
-
* 根据文件名后缀判断使用哪个布局
|
|
27
|
-
* @param routes - 原始路由配置
|
|
28
|
-
* @param inheritLayout - 继承的布局名称(来自父级目录)
|
|
29
|
-
* @returns 处理后的布局配置(不包含实际的布局组件导入)
|
|
30
|
-
*/
|
|
31
|
-
export function Layouts(routes: RouteConfig[], inheritLayout: string = ''): LayoutConfig[] {
|
|
32
|
-
const result: LayoutConfig[] = [];
|
|
33
|
-
|
|
34
|
-
for (const route of routes) {
|
|
35
|
-
const currentPath = route.path || '';
|
|
36
|
-
|
|
37
|
-
// 检查当前路径是否有 _数字 格式
|
|
38
|
-
const pathMatch = currentPath.match(/_(\d+)$/);
|
|
39
|
-
const currentLayout = pathMatch ? pathMatch[1] : inheritLayout;
|
|
40
|
-
|
|
41
|
-
// 如果有子路由,说明这是中间节点(目录),不包裹布局,只递归处理子路由
|
|
42
|
-
if (route.children && route.children.length > 0) {
|
|
43
|
-
// 清理路径:如果是 xxx_数字 格式,去掉 _数字
|
|
44
|
-
const cleanPath = pathMatch ? currentPath.replace(/_\d+$/, '') : currentPath;
|
|
45
|
-
|
|
46
|
-
// 直接递归处理子路由,不添加当前层级到结果
|
|
47
|
-
const childConfigs = Layouts(route.children, currentLayout);
|
|
48
|
-
|
|
49
|
-
// 将子路由的路径前缀加上当前路径
|
|
50
|
-
for (const child of childConfigs) {
|
|
51
|
-
result.push({
|
|
52
|
-
...child,
|
|
53
|
-
path: cleanPath ? `${cleanPath}/${child.path}`.replace(/\/+/g, '/') : child.path
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// 没有子路由的叶子节点,需要包裹布局
|
|
60
|
-
const lastPart = currentPath;
|
|
61
|
-
|
|
62
|
-
// 匹配 _数字 格式(如 index_1, news_2)
|
|
63
|
-
const match = lastPart.match(/_(\d+)$/);
|
|
64
|
-
// 优先使用文件自己的布局,其次使用继承的布局,最后使用 default
|
|
65
|
-
const layoutName = match ? match[1] : currentLayout || 'default';
|
|
66
|
-
|
|
67
|
-
// 计算清理后的路径
|
|
68
|
-
let cleanPath;
|
|
69
|
-
if (lastPart === 'index' || (lastPart.startsWith('index_') && match)) {
|
|
70
|
-
// index 或 index_数字 → 改为空路径(由父级路径表示)
|
|
71
|
-
cleanPath = '';
|
|
72
|
-
} else if (match) {
|
|
73
|
-
// xxx_数字 → 去掉 _数字 后缀
|
|
74
|
-
cleanPath = lastPart.replace(/_\d+$/, '');
|
|
75
|
-
} else {
|
|
76
|
-
// 其他 → 保持原样
|
|
77
|
-
cleanPath = lastPart;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 返回布局配置(不执行实际导入)
|
|
81
|
-
result.push({
|
|
82
|
-
path: cleanPath,
|
|
83
|
-
layoutName: layoutName,
|
|
84
|
-
component: route.component,
|
|
85
|
-
meta: route.meta
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return result;
|
|
90
|
-
}
|
package/src/pickFields.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { isPlainObject } from 'es-toolkit/compat';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 挑选指定字段
|
|
5
|
-
*/
|
|
6
|
-
export const pickFields = <T extends Record<string, any>>(obj: T, keys: string[]): Partial<T> => {
|
|
7
|
-
if (!obj || (!isPlainObject(obj) && !Array.isArray(obj))) {
|
|
8
|
-
return {};
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const result: any = {};
|
|
12
|
-
for (const key of keys) {
|
|
13
|
-
if (key in obj) {
|
|
14
|
-
result[key] = obj[key];
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return result;
|
|
19
|
-
};
|
package/src/redisKeys.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Redis Key 统一管理
|
|
3
|
-
* 所有 Redis 缓存键在此统一定义,避免硬编码分散
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Redis Key 生成函数集合
|
|
8
|
-
*/
|
|
9
|
-
export const RedisKeys = {
|
|
10
|
-
/** 所有接口缓存 */
|
|
11
|
-
apisAll: () => 'befly:apis:all',
|
|
12
|
-
|
|
13
|
-
/** 所有菜单缓存 */
|
|
14
|
-
menusAll: () => 'befly:menus:all',
|
|
15
|
-
|
|
16
|
-
/** 角色信息缓存(完整角色对象) */
|
|
17
|
-
roleInfo: (roleCode: string) => `befly:role:info:${roleCode}`,
|
|
18
|
-
|
|
19
|
-
/** 角色接口权限缓存(Set 集合) */
|
|
20
|
-
roleApis: (roleCode: string) => `befly:role:apis:${roleCode}`,
|
|
21
|
-
|
|
22
|
-
/** 表结构缓存 */
|
|
23
|
-
tableColumns: (table: string) => `befly:table:columns:${table}`
|
|
24
|
-
} as const;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Redis TTL(过期时间)常量配置(单位:秒)
|
|
28
|
-
*/
|
|
29
|
-
export const RedisTTL = {
|
|
30
|
-
/** 表结构缓存 - 1小时 */
|
|
31
|
-
tableColumns: 3600,
|
|
32
|
-
|
|
33
|
-
/** 角色接口权限 - 24小时 */
|
|
34
|
-
roleApis: 86400,
|
|
35
|
-
|
|
36
|
-
/** 角色信息 - 24小时 */
|
|
37
|
-
roleInfo: 86400,
|
|
38
|
-
|
|
39
|
-
/** 接口列表 - 永久(不过期) */
|
|
40
|
-
apisAll: null,
|
|
41
|
-
|
|
42
|
-
/** 菜单列表 - 永久(不过期) */
|
|
43
|
-
menusAll: null
|
|
44
|
-
} as const;
|