Files
InfoRSI/.dependency-cruiser.cjs
T
iomgaa 97a43591a3 feat: 工具链与 vocab 模块(任务书 01)
- npm 包、TypeScript、node --test、dependency-cruiser;结构.md 第六部分的检查规则一次写全,临时违规实测均报错。
- vocab:基础类型与编号格式、规范序列化与哈希、角色/阶段/提交名单、指标与运行定义及结果、模型用量、16 种提交的 TypeBox 字段定义。
- 测试:规范序列化预期串手写,哈希预期值用 sha256sum 算出;每种提交一份合法样例。
- 结构.md 第八部分补 vocab 对外内容;WORK_LOG 记下用户决定。

用户决定(2026-10-01):"同意 A,vocab 上限改为 1100 行";"同意 A:解释的 cells 去掉 minItems,改为可选";"3、4、5、6:同意保留你的写法";答案路径与保障动手次数"tasks 只记读到的原始内容",对表由以后有位置表的模块现算。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:37:58 -04:00

130 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 模块之间的依赖规则,来源是 docs/结构.md 第二部分(模块表)和第六部分(检查规则)。
// 模块按 src/<模块名>/ 认;新建模块目录后自动受这些规则检查。规则只管 src 下的模块,tests/ 不受"只有某模块能用某外部包"的限制。
// 模块表"依赖"一列:每个模块除了自己和 vocab 以外,还能引用哪些模块。plugin 装配时可用各模块。
const ALLOWED = {
plugin: [
"flow", "export", "config", "materials", "submissions",
"ledger", "agents", "runner", "tasks", "workspace", "jev", "rules",
],
flow: [
"ledger", "rules", "materials", "submissions", "agents",
"runner", "tasks", "workspace", "config", "jev",
],
export: ["ledger", "rules", "materials"],
config: [],
materials: ["ledger", "rules"],
submissions: ["jev"],
ledger: [],
agents: [],
runner: [],
tasks: [],
workspace: [],
jev: [],
rules: [],
vocab: [],
};
const MODULES = Object.keys(ALLOWED);
const anyOf = (names) => `(${names.join("|")})`;
// 外部的东西各由哪些名字认出来。核心模块带不带 node: 前缀都认;
// npm 包装好后解析成 node_modules/ 下的路径,没装时是包名本身,两种都认。
const npm = (names) => `(^|node_modules/)${anyOf(names)}(/|$)`;
const SUBPROCESS = [
"^(node:)?(child_process|cluster)$",
npm(["cross-spawn", "execa"]),
];
const SQLITE = ["^node:sqlite$", npm(["better-sqlite3", "sqlite3"])];
const PI = npm(["@earendil-works/[^/]+"]);
const directionRules = MODULES.map((name) => ({
name: `direction-${name}`,
comment: `${name} 只能引用自己、vocab 和模块表里列出的模块:${ALLOWED[name].join("、") || "无"}`,
severity: "error",
from: { path: `^src/${name}/` },
to: { path: "^src/", pathNot: `^src/${anyOf([name, "vocab", ...ALLOWED[name]])}/` },
}));
module.exports = {
forbidden: [
{
name: "no-circular",
comment: "不许循环引用",
severity: "error",
from: {},
to: { circular: true },
},
{
name: "unknown-module",
comment: `src 下只有模块表里的模块目录:${MODULES.join("、")}`,
severity: "error",
from: { path: "^src/", pathNot: `^src/${anyOf(MODULES)}/` },
to: {},
},
...directionRules,
{
name: "through-index",
comment: "别的模块只能通过目录下的 index.ts 引用它",
severity: "error",
from: { path: "^src/([^/]+)/" },
to: { path: "^src/[^/]+/", pathNot: ["^src/$1/", "^src/[^/]+/index\\.ts$"] },
},
{
name: "outside-src",
comment: "src 下的文件只许引用 src/、node_modules/ 与 Node 内置模块,不能借 src 外的文件绕开规则",
severity: "error",
from: { path: "^src/" },
to: { pathNot: ["^src/", "^node_modules/"], dependencyTypesNot: ["core"] },
},
{
name: "pure-allowlist",
comment:
"rules 和 vocab 不碰文件、数据库、网络、子进程和 Pi:除了 src 下允许的模块," +
"只许引用 typebox 和 node:crypto",
severity: "error",
from: { path: "^src/(rules|vocab)/" },
to: { pathNot: ["^src/", "^node_modules/typebox/", "^(node:)?crypto$"] },
},
{
name: "sqlite-only-ledger",
comment: "只有 ledger 能用 SQLite",
severity: "error",
from: { path: "^src/", pathNot: "^src/ledger/" },
to: { path: SQLITE },
},
{
name: "pi-only-agents-plugin",
comment: "只有 agents 和 plugin 能用 Pi",
severity: "error",
from: { path: "^src/", pathNot: "^src/(agents|plugin)/" },
to: { path: PI },
},
{
name: "subprocess-only-runner-workspace",
comment: "只有 runner 和 workspace 能起子进程",
severity: "error",
from: { path: "^src/", pathNot: "^src/(runner|workspace)/" },
to: { path: SUBPROCESS },
},
{
name: "tasks-not-runner",
comment: "tasks 不许引用 runner:runner 只管怎么跑,tasks 只管怎么判,由 flow 串起来",
severity: "error",
from: { path: "^src/tasks/" },
to: { path: "^src/runner/" },
},
],
options: {
doNotFollow: { path: "node_modules" },
tsPreCompilationDeps: true,
tsConfig: { fileName: "tsconfig.json" },
// 按 Node 的 ESM 规则读 npm 包的 exports(dependency-cruiser 默认不读),
// 否则 typebox 这类只在 exports 里给入口的包解析不到。
enhancedResolveOptions: {
extensions: [".ts", ".js"],
exportsFields: ["exports"],
conditionNames: ["import", "node", "default"],
},
},
};