befly-shared 1.3.2 → 1.3.4

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 CHANGED
@@ -1,23 +1,28 @@
1
1
  {
2
2
  "name": "befly-shared",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "private": false,
5
5
  "description": "Befly 纯函数与纯常量共享包(不包含 Node/浏览器特定实现)",
6
6
  "license": "Apache-2.0",
7
7
  "author": "chensuiyi <bimostyle@qq.com>",
8
8
  "files": [
9
9
  "package.json",
10
+ "types/",
10
11
  "utils/"
11
12
  ],
12
13
  "type": "module",
13
14
  "exports": {
14
- "./utils/*": "./utils/*.ts"
15
+ "./utils/*": "./utils/*.ts",
16
+ "./types/*": "./types/*.ts"
15
17
  },
16
18
  "scripts": {
17
19
  "test": "bun test"
18
20
  },
21
+ "dependencies": {
22
+ "es-toolkit": "^1.43.0"
23
+ },
19
24
  "engines": {
20
25
  "bun": ">=1.3.0"
21
26
  },
22
- "gitHead": "7dd54bc1ed484139fa52ce5408f1a6c166e2a928"
27
+ "gitHead": "564115664323c9d73351945129aa7d57d440eb58"
23
28
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * arrayToTree 类型定义(类型模块,仅供 type 引用)。
3
+ */
4
+
5
+ export type ArrayToTreeResult<T extends Record<string, any>> = {
6
+ flat: Array<T>;
7
+ tree: Array<T>;
8
+ map: Map<string, T>;
9
+ };
10
+
11
+ export type ArrayToTree = <T extends Record<string, any>>(items: T[], id?: string, pid?: string, children?: string, sort?: string) => ArrayToTreeResult<T>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * deepTransformKeys 类型定义(类型模块,仅供 type 引用)。
3
+ *
4
+ * 注意:types 模块不包含运行时实现;运行时请从 befly-shared/utils/* 引入。
5
+ */
6
+
7
+ export type KeyTransformer = (key: string) => string;
8
+
9
+ export type PresetTransform = "camel" | "snake" | "kebab" | "pascal" | "upper" | "lower";
10
+
11
+ export interface TransformOptions {
12
+ maxDepth?: number;
13
+ excludeKeys?: string[];
14
+ }
15
+
16
+ export type DeepTransformKeys = <T = any>(data: any, transformer: KeyTransformer | PresetTransform, options?: TransformOptions) => T;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * genShortId 类型定义(类型模块,仅供 type 引用)。
3
+ */
4
+
5
+ export type GenShortId = () => string;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * hashPassword 类型定义(类型模块,仅供 type 引用)。
3
+ */
4
+
5
+ export type HashPassword = (password: string, salt?: string) => Promise<string>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * normalizePathnameListInput 类型定义(类型模块,仅供 type 引用)。
3
+ */
4
+
5
+ export type NormalizePathnameListInput = (value: unknown, fieldLabel: string, forbidMethodPrefix: boolean) => string[];
@@ -0,0 +1,25 @@
1
+ /**
2
+ * scanViewsDir 相关纯函数的类型定义(类型模块,仅供 type 引用)。
3
+ */
4
+
5
+ export type ViewDirMeta = {
6
+ title: string;
7
+ order?: number;
8
+ };
9
+
10
+ export type MenuNodeLike<T> = {
11
+ name?: string;
12
+ path?: string;
13
+ sort?: number;
14
+ children?: T[];
15
+ };
16
+
17
+ export type CleanDirName = (name: string) => string;
18
+
19
+ export type NormalizeMenuPath = (path: string) => string;
20
+
21
+ export type NormalizeMenuTree = <T extends MenuNodeLike<T>>(menus: T[]) => T[];
22
+
23
+ export type ExtractScriptSetupBlock = (vueContent: string) => string | null;
24
+
25
+ export type ExtractDefinePageMetaFromScriptSetup = (scriptSetup: string) => ViewDirMeta | null;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * withDefaultColumns 类型定义(类型模块,仅供 type 引用)。
3
+ */
4
+
5
+ export type WithDefaultColumns = (columns: any[], customConfig?: Record<string, any>) => any[];
@@ -0,0 +1,27 @@
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
+ }
@@ -0,0 +1,58 @@
1
+ const HTTP_METHOD_PREFIX_RE = /^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/i;
2
+
3
+ /**
4
+ * 将未知输入规范化为 pathname 字符串数组。
5
+ *
6
+ * 规则(契约):
7
+ * - value 为“假值”(null/undefined/""/0/false/NaN)时返回空数组 []。
8
+ * - value 必须是 string[],否则抛错:`${fieldLabel} 必须是字符串数组`。
9
+ * - 数组元素必须满足:
10
+ * - 类型为 string
11
+ * - 不允许为空字符串
12
+ * - 不允许包含任何空白字符(空格/制表符/换行等)
13
+ * - 必须以 "/" 开头(pathname)
14
+ * - forbidMethodPrefix=true 时,禁止 "GET/POST/..." 等 method 前缀,并给出更明确的错误提示。
15
+ *
16
+ * 注意:该函数不会做任何隐式修复/转换(例如 trim/split/JSON.parse/去重/排序)。
17
+ */
18
+ export function normalizePathnameListInput(value: unknown, fieldLabel: string, forbidMethodPrefix: boolean): string[] {
19
+ // “假值”统一视为空数组:null/undefined/""/0/false/NaN
20
+ if (!value) return [];
21
+
22
+ if (!Array.isArray(value)) {
23
+ throw new Error(`${fieldLabel} 必须是字符串数组`);
24
+ }
25
+
26
+ const out: string[] = [];
27
+
28
+ for (let i = 0; i < value.length; i += 1) {
29
+ const item = value[i];
30
+ const itemLabel = `${fieldLabel}[${i}]`;
31
+
32
+ if (typeof item !== "string") {
33
+ throw new Error(`${itemLabel} 必须是字符串`);
34
+ }
35
+
36
+ if (item.length === 0) {
37
+ throw new Error(`${itemLabel} 不允许为空字符串`);
38
+ }
39
+
40
+ // 优先给出 method 前缀提示(更明确)
41
+ if (forbidMethodPrefix && HTTP_METHOD_PREFIX_RE.test(item)) {
42
+ throw new Error(`${itemLabel} 不允许包含 method 前缀,应为 url.pathname(例如 /api/app/xxx)`);
43
+ }
44
+
45
+ // 不做 trim 自动转换:含任何空白字符都视为不合法
46
+ if (/\s/.test(item)) {
47
+ throw new Error(`${itemLabel} 不允许包含空白字符(空格/制表符/换行等)`);
48
+ }
49
+
50
+ if (!item.startsWith("/")) {
51
+ throw new Error(`${itemLabel} 必须是 pathname(以 / 开头)`);
52
+ }
53
+
54
+ out.push(item);
55
+ }
56
+
57
+ return out;
58
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 为表格列添加默认配置(纯函数)。
3
+ *
4
+ * 设计目标:
5
+ * - 不依赖浏览器/Node 特定 API
6
+ * - 不修改入参 columns 的对象引用(会返回新数组,并对每个列对象做浅拷贝合并)
7
+ *
8
+ * 默认行为:
9
+ * - base 默认:{ width: 200, ellipsis: true }
10
+ * - 特殊列:operation/state/id
11
+ * - colKey 以 At/At2 结尾时:默认 { align: "center" }
12
+ * - customConfig 可覆盖/扩展默认 specialColumnConfig(浅合并/替换:若传入 operation 配置,将整体替换默认 operation 配置,默认 fixed="right" 不会被保留)
13
+ */
14
+ export function withDefaultColumns(columns: any[], customConfig?: Record<string, any>): any[] {
15
+ const safeColumns = Array.isArray(columns) ? columns : [];
16
+
17
+ const specialColumnConfig: Record<string, any> = Object.assign(
18
+ {
19
+ operation: { width: 100, align: "center", fixed: "right" },
20
+ state: { width: 100, align: "center" },
21
+ id: { width: 200, align: "center" }
22
+ },
23
+ customConfig || {}
24
+ );
25
+
26
+ return safeColumns.map((col) => {
27
+ const colKey = col && (col as any).colKey;
28
+
29
+ let specialConfig = colKey ? specialColumnConfig[colKey] : undefined;
30
+
31
+ if (!specialConfig && typeof colKey === "string" && (colKey.endsWith("At") || colKey.endsWith("At2"))) {
32
+ specialConfig = { align: "center" };
33
+ }
34
+
35
+ const base = {
36
+ width: 200,
37
+ ellipsis: true
38
+ };
39
+
40
+ const merged = Object.assign({}, base);
41
+ if (specialConfig) {
42
+ Object.assign(merged, specialConfig);
43
+ }
44
+ Object.assign(merged, col);
45
+
46
+ return merged;
47
+ });
48
+ }