/* eslint-disable */ /** * JCAI 依赖门禁 —— 编码规范 §11.4。 * * 结构:基线八条(no-circular / no-cross-module-internal / app-not-into-internal / * domain-is-pure / usecase-not-to-adapter / web-not-to-api / packages-are-leaves / * no-orphans)+ JCAI 增补四条(framework-only-in-adapter / tier-order / * activities-isolated / apps-not-into-activities)。 * * tier-order 的逐层展开由 tools/gen-depcruise-tiers.ts 从 tools/module-tiers.json 生成。 * **约束报错时,改代码,不改约束(§11)。** */ const tierRules = require('./tools/depcruise-tiers.generated.cjs'); const MODULES = '^apps/api/src/modules'; /** domain 层的 npm 白名单(§5.3):zod / decimal.js / date-fns + 仓内纯包 */ const DOMAIN_NPM_ALLOWLIST = 'node_modules/(zod|decimal\\.js|date-fns)(/|$)'; module.exports = { forbidden: [ // ── 基线八条 ──────────────────────────────────────────────────────────── { name: 'no-circular', comment: '依赖方向单向无环(§0.1 第 3 条)', severity: 'error', from: {}, to: { circular: true }, }, { name: 'no-cross-module-internal', comment: '任何文件不得 import modules/*/internal/**(同模块自己除外,§5.2)', severity: 'error', from: { pathNot: `${MODULES}/([^/]+)/` }, to: { path: `${MODULES}/([^/]+)/internal/` }, }, { name: 'no-cross-module-internal-peer', comment: '模块之间只准 import 到对方的 index.ts,不得穿透 internal(§5.2)', severity: 'error', from: { path: `${MODULES}/([^/]+)/` }, to: { path: `${MODULES}/([^/]+)/internal/`, pathNot: `${MODULES}/$1/internal/`, }, }, { name: 'app-not-into-internal', comment: 'app/ 是组装层,只经模块出口认识模块(§5.2)', severity: 'error', from: { path: '^apps/(api|web)/src/app/' }, to: { path: `${MODULES}/([^/]+)/internal/` }, }, { name: 'domain-is-pure', comment: 'domain/ 零 IO、零框架:npm 只准 zod / decimal.js / date-fns,仓内只准 @contracts / @sfeel / @utils(§5.3)', severity: 'error', from: { path: `${MODULES}/([^/]+)/internal/domain/` }, to: { path: 'node_modules', pathNot: DOMAIN_NPM_ALLOWLIST, }, }, { name: 'domain-is-pure-core', comment: 'domain/ 不得触 Node 核心能力(fs / http / crypto / child_process …,§5.3)', severity: 'error', from: { path: `${MODULES}/([^/]+)/internal/domain/` }, to: { dependencyTypes: ['core'] }, }, { name: 'usecase-not-to-adapter', comment: 'usecase/ 依赖 port.ts 声明的能力,不 import 任何 adapter(§5.3)', severity: 'error', from: { path: `${MODULES}/([^/]+)/internal/usecase/` }, to: { path: `${MODULES}/([^/]+)/internal/adapter/` }, }, { name: 'web-not-to-api', comment: '前后端互不 import,跨端唯一通道是 @contracts(§5.1)', severity: 'error', from: { path: '^apps/web/' }, to: { path: '^apps/api/' }, }, { name: 'api-not-to-web', comment: '前后端互不 import(§5.1)', severity: 'error', from: { path: '^apps/api/' }, to: { path: '^apps/web/' }, }, { name: 'packages-are-leaves', comment: 'packages/* 不得反向 import apps/*(§5.1)', severity: 'error', from: { path: '^packages/' }, to: { path: '^apps/' }, }, { name: 'utils-is-leaf', comment: 'packages/utils 是叶子,不依赖任何仓内包(§5.1)', severity: 'error', from: { path: '^packages/utils/' }, to: { path: '^(apps|activities|packages/(?!utils))' }, }, { name: 'no-orphans', comment: '无孤儿模块;契约面(index/contract/port)、入口与配置是合法的无入边文件,不计孤儿', severity: 'error', from: { orphan: true, pathNot: [ '(^|/)(index|contract|port)\\.ts$', '^apps/(api|web)/src/app/', '^activities/', '^tools/', '\\.d\\.ts$', '\\.(config|setup)\\.(js|cjs|mjs|ts)$', '(^|/)__tests__/', '\\.test\\.ts$', ], }, to: {}, }, // ── JCAI 增补 ────────────────────────────────────────────────────────── { name: 'framework-only-in-adapter', comment: 'Mastra / AI SDK / Drizzle / pg / pg-boss / Hono 只准在 adapter 与 app(§6.2)', severity: 'error', from: { path: `${MODULES}/([^/]+)/internal/(domain|usecase)/` }, to: { path: 'node_modules/(@mastra|ai|@ai-sdk|drizzle-orm|drizzle-kit|pg|pg-boss|hono|@hono)(/|$)', }, }, { name: 'contracts-is-pure', comment: '@contracts 只有 zod schema / 常量 / 类型,零实现、零框架(§8.1)', severity: 'error', from: { path: '^packages/contracts/' }, to: { path: 'node_modules', pathNot: 'node_modules/zod(/|$)', }, }, { name: 'sfeel-is-pure', comment: '@sfeel 是纯函数包,零 IO 零框架(§8.3)', severity: 'error', from: { path: '^packages/sfeel/' }, to: { dependencyTypes: ['core'] }, }, { name: 'activities-isolated', comment: 'activities/* 只准 import @sdk / @contracts 与白名单纯库,不得 import apps/**(ADR-004)', severity: 'error', from: { path: '^activities/' }, to: { path: '^apps/' }, }, { name: 'apps-not-into-activities', comment: '活动经安装装载,api 侧任何文件不得静态 import activities/**(§2.1 / ADR-004)', severity: 'error', from: { path: '^apps/' }, to: { path: '^activities/' }, }, { name: 'activity-no-environment-capability', comment: '活动包零环境能力:不得触 node 核心模块(AM 12.1 无越权代码)', severity: 'error', from: { path: '^activities/' }, to: { dependencyTypes: ['core'] }, }, ...tierRules, ], options: { doNotFollow: { path: 'node_modules' }, exclude: { path: ['(^|/)dist/', '(^|/)\\.build/', '(^|/)node_modules/', '(^|/)api-report/', '\\.d\\.ts$'], }, tsPreCompilationDeps: true, tsConfig: { fileName: 'tsconfig.base.json' }, enhancedResolveOptions: { exportsFields: ['exports'], conditionNames: ['import', 'require', 'node', 'default', 'types'], extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], mainFields: ['module', 'main', 'types'], }, reporterOptions: { text: { highlightFocused: true }, }, }, };