befly 3.77.1 → 3.77.2

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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "系统管理"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "接口管理"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "认证登录"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "仪表盘"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "字典项"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "字典类型"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "邮件"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "登录日志"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "菜单"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "操作日志"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "角色"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "资源"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "数据统计"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "title": "上传"
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.77.1",
3
+ "version": "3.77.2",
4
4
  "gitHead": "49c39d36695036e85fc64083cc43c1652fff96cb",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
@@ -1,4 +1,4 @@
1
- import { existsSync } from "node:fs";
1
+ import { existsSync, readdirSync } from "node:fs";
2
2
  import { join, normalize, parse, relative } from "node:path";
3
3
 
4
4
  import { createError } from "./error.js";
@@ -13,14 +13,14 @@ const selectFields = {
13
13
  };
14
14
 
15
15
  /**
16
- * 扫描接口目录下的 _meta.js 目录元数据(约定:_ 前缀文件不注册路由)。
16
+ * 扫描接口目录下的 _meta.json 目录元数据(约定:_ 前缀文件不注册路由)。
17
17
  * 返回 Map<目录 apiPath, 中文标题>,键与接口 apiPath 的目录部分对齐,供 scanSources 挂载 parentTitle。
18
18
  */
19
19
  export async function scanApiMetaTitles(dir, source) {
20
20
  const titles = new Map();
21
21
  if (!existsSync(dir)) return titles;
22
22
 
23
- const glob = new Bun.Glob("**/_meta.js");
23
+ const glob = new Bun.Glob("**/_meta.json");
24
24
  const files = await Array.fromAsync(
25
25
  glob.scan({
26
26
  cwd: dir,
@@ -119,3 +119,23 @@ export async function scanFiles(dir, source, type, pattern) {
119
119
  throw createError(`扫描失败: source=${source} type=${type} dir=${dir} pattern=${pattern}`, { cause: error, code: "runtime" });
120
120
  }
121
121
  }
122
+
123
+ // 枚举接口目录下全部子目录(任意深度,跳过 _ 前缀段),返回目录 apiPath 集合,
124
+ // 供启动校验"每个目录必须有 _meta.js"使用
125
+ export function scanApiDirPaths(dir, source) {
126
+ const result = new Set();
127
+ if (!existsSync(dir)) return result;
128
+ const prefix = source === "core" ? "/api/core/" : "/api/";
129
+
130
+ function collect(current, relativeDir) {
131
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
132
+ if (!entry.isDirectory() || entry.name.startsWith("_")) continue;
133
+ const childRelative = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;
134
+ result.add(`${prefix}${childRelative}`);
135
+ collect(join(current, entry.name), childRelative);
136
+ }
137
+ }
138
+
139
+ collect(dir, "");
140
+ return result;
141
+ }
@@ -16,11 +16,11 @@ import {
16
16
  appCornDir
17
17
  } from "../paths.js";
18
18
  import { createError } from "./error.js";
19
- import { scanApiMetaTitles, scanFiles } from "./scanFiles.js";
19
+ import { scanApiDirPaths, scanApiMetaTitles, scanFiles } from "./scanFiles.js";
20
20
 
21
21
  // 逐级拼接目录显示标题:每级目录有 _meta.js 标题用标题,没有用目录名,以 / 连接
22
22
  // 例:/api/admin/product/insert + 标题映射 -> "后台管理/product"
23
- export function composeTitlePath(apiPath, metaTitles, missingCollector) {
23
+ export function composeTitlePath(apiPath, metaTitles) {
24
24
  const segments = apiPath.split("/").filter(Boolean);
25
25
  const start = segments[1] === "core" ? 2 : 1;
26
26
  const dirs = segments.slice(start, -1);
@@ -30,13 +30,7 @@ export function composeTitlePath(apiPath, metaTitles, missingCollector) {
30
30
  let current = `/${segments.slice(0, start).join("/")}`;
31
31
  for (const dir of dirs) {
32
32
  current = `${current}/${dir}`;
33
- const title = metaTitles.get(current);
34
- if (title) {
35
- parts.push(title);
36
- } else {
37
- parts.push(dir);
38
- if (missingCollector) missingCollector.add(current);
39
- }
33
+ parts.push(metaTitles.get(current) || dir);
40
34
  }
41
35
  return parts.join("/");
42
36
  }
@@ -142,23 +136,36 @@ export const scanSources = async ({ beflyMode = "auto" } = {}) => {
142
136
  corns.push(item);
143
137
  }
144
138
 
145
- // 处理接口(读取目录 _meta.js 标题挂载 parentTitle);
146
- // 每一级接口目录都必须有中文标题,缺失即启动失败并列出清单
147
- const [allCoreApis, coreMetaTitles, allAppApis, appMetaTitles] = await Promise.all([scanFiles(coreApiDir, "core", "api", "**/*.js"), scanApiMetaTitles(coreApiDir, "core"), scanFiles(appApiDir, "app", "api", "**/*.js"), scanApiMetaTitles(appApiDir, "app")]);
139
+ // 处理接口(读取目录 _meta.js 标题挂载 parentTitle
140
+ const [allCoreApis, coreMetaTitles, coreDirPaths, allAppApis, appMetaTitles, appDirPaths] = await Promise.all([
141
+ scanFiles(coreApiDir, "core", "api", "**/*.js"),
142
+ scanApiMetaTitles(coreApiDir, "core"),
143
+ scanApiDirPaths(coreApiDir, "core"),
144
+ scanFiles(appApiDir, "app", "api", "**/*.js"),
145
+ scanApiMetaTitles(appApiDir, "app"),
146
+ scanApiDirPaths(appApiDir, "app")
147
+ ]);
148
148
 
149
- const missingTitleDirs = new Set();
150
149
  for (const item of allCoreApis) {
151
- item.parentTitle = composeTitlePath(item.apiPath, coreMetaTitles, missingTitleDirs);
150
+ item.parentTitle = composeTitlePath(item.apiPath, coreMetaTitles);
152
151
  apis.push(item);
153
152
  }
154
153
  for (const item of allAppApis) {
155
154
  assertAppApiNamespace(item);
156
- item.parentTitle = composeTitlePath(item.apiPath, appMetaTitles, missingTitleDirs);
155
+ item.parentTitle = composeTitlePath(item.apiPath, appMetaTitles);
157
156
  apis.push(item);
158
157
  }
159
158
 
159
+ // 每个接口目录(含空目录,_ 前缀隔离目录除外)都必须有 _meta.js 中文标题
160
+ const missingTitleDirs = new Set();
161
+ for (const dirPath of coreDirPaths) {
162
+ if (!coreMetaTitles.has(dirPath)) missingTitleDirs.add(dirPath);
163
+ }
164
+ for (const dirPath of appDirPaths) {
165
+ if (!appMetaTitles.has(dirPath)) missingTitleDirs.add(dirPath);
166
+ }
160
167
  if (missingTitleDirs.size > 0) {
161
- throw createError(`以下接口目录缺少 _meta.js 中文标题:${Array.from(missingTitleDirs).toSorted().join("、")}`, {
168
+ throw createError(`以下接口目录缺少 _meta.json 中文标题:${Array.from(missingTitleDirs).toSorted().join("、")}`, {
162
169
  code: "policy",
163
170
  subsystem: "scan",
164
171
  operation: "scanSources"
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "系统管理"
3
- };
package/apis/api/_meta.js DELETED
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "接口管理"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "认证登录"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "仪表盘"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "字典项"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "字典类型"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "邮件"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "登录日志"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "菜单"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "操作日志"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "角色"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "资源"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "数据统计"
3
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- title: "上传"
3
- };