Files
lingxi/docs/工程规范/03-格式化与Lint.md
T
Stev_Wang 00ae12435e docs(specs): add AGENTS.md and engineering guidelines
项目尚无统一工程规范,AI 助手与研发各自发挥导致返工风险。建立
总纲 + 细则两层结构:AGENTS.md 只写硬约束与索引(14 条红线、技术栈
基线、仓库结构、命令契约),细则拆为 10 份文档覆盖 Git、代码风格、
格式化、API 与路由、数据库、测试与 CI、Review、日志、密钥、资产命名。

影响面:仅文档。约束力从本轮起对新建代码生效;与现状冲突处以文档为准。
回滚方式:git revert 本提交。
2026-11-02 15:09:51 +08:00

142 lines
5.8 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# 03 · 格式化与 Lint
| 项 | 内容 |
| --- | --- |
| 文档版本 | V1.0(2026-11-02) |
| 依据 | 技术架构 §2.2(前端)、§10.1(工程约定)、§4.6(CI/CD) |
| 适用范围 | 全仓库可执行文件 |
| 强制级别 | 强制(CI 门禁,不允许「先合并后修」) |
---
## 1 一句话原则
**格式交给工具,评审只看逻辑。** 任何格式争论都应由配置解决,禁止在 Review 中讨论空格与换行。
---
## 2 Prettier(唯一格式化器)
| 配置项 | 值 | 说明 |
| --- | --- | --- |
| `printWidth` | `100` | 与技术架构示例行宽一致 |
| `tabWidth` | `2` | |
| `useTabs` | `false` | |
| `semi` | `true` | |
| `singleQuote` | `true` | |
| `trailingComma` | `all` | |
| `arrowParens` | `always` | |
| `endOfLine` | `lf` | 跨平台一致 |
| `plugins` | `prettier-plugin-tailwindcss`(仅 `apps/web`) | 若引入 Tailwind;未引入则不加 |
规则:
- `FMT-01` 只允许一个 Prettier 版本、一个根配置;子包**不得**覆盖。
- `FMT-02` 禁止在文件中写 `prettier-ignore`,除非是生成代码或大段 markdown 表格,并注明原因。
- `FMT-03` CI 执行 `pnpm format:check`,失败即阻断。
- `FMT-04` 禁止把格式化产生的无关改动混进功能 PR(会产生冲突与 Review 噪音)。
---
## 3 ESLint(ESLint 9 flat config)
| 项 | 约定 |
| --- | --- |
| 配置位置 | 根 `eslint.config.mjs`,按 `apps/*`、`packages/*` 分层 export |
| 基础 | `@eslint/js` recommended + `typescript-eslint` 的 `strictTypeChecked` + `stylisticTypeChecked` |
| 前端附加 | `eslint-plugin-react-hooks`、`eslint-plugin-react-refresh`、`jsx-a11y` |
| 导入排序 | `eslint-plugin-simple-import-sort` |
| 命名检查 | `@typescript-eslint/naming-convention`(对应 [02](02-代码风格.md) §1) |
### 3.1 必须为 `error` 的规则
| 规则 | 目的 |
| --- | --- |
| `@typescript-eslint/no-explicit-any` | 禁 `any` |
| `@typescript-eslint/no-floating-promises` | 禁未处理 Promise |
| `@typescript-eslint/no-misused-promises` | 禁 async 传入非异步回调位 |
| `@typescript-eslint/consistent-type-imports` | 类型导入用 `import type` |
| `@typescript-eslint/no-unnecessary-condition` | 消除冗余判断(strict 下有效) |
| `no-restricted-imports` | **UI / 图标白名单**(见 §3.2) |
| `no-console` | 业务代码禁用,`scripts/**` 与 `worker` 的 logger 除外 |
| `import/no-cycle` | 禁循环依赖 |
| `react-hooks/rules-of-hooks` / `exhaustive-deps` | Hooks 正确性 |
| `jsx-a11y/*` 关键项 | 可访问性底线 |
### 3.2 白名单(`no-restricted-imports` 强制)
**禁止导入**(含子路径):
```
@douyinfe/semi-ui ← 只能用 @douyinfe/semi-ui-19
antd @ant-design/* @arco-design/*
@douyinfe/semi-icons @ant-design/icons react-icons lucide-react @heroicons/*
element-plus naive-ui @mui/* @chakra-ui/*
```
**规则**:
- `FMT-05` 图标只能 `import { IconXxx } from '@lingxi/ui/icons'`;禁止 `import * as Icons`、禁止直接引 `remixicon/icons/...`。
- `FMT-06` SVG 内联仅允许品牌 Logo(`packages/ui/brand/`),其他一律走图标出口。
- `FMT-07` 颜色字面量(`#rrggbb`、`rgb(`)在 `apps/web` 内禁用,除非在 `packages/ui/theme/` 的 token 定义文件。
### 3.3 允许 `warn` 的规则
`@typescript-eslint/no-non-null-assertion`(须注释证明非空)、`complexity`(> 15 警告)、`max-lines-per-function`(> 50 警告)。
---
## 4 提交钩子(本地)
| 钩子 | 工具 | 行为 |
| --- | --- | --- |
| `pre-commit` | husky + lint-staged | 仅对暂存文件跑 `eslint --fix` + `prettier --write` |
| `commit-msg` | commitlint | 校验 Conventional Commits(见 [01](01-Git规范.md) §2) |
| `pre-push` | husky | 跑 `pnpm typecheck`(本地拦截类型错误,避免浪费 CI) |
- `FMT-08` `lint-staged` 只处理暂存文件,**禁止**在钩子里跑全量 lint / 全量测试(太慢会诱发 `--no-verify`)。
- `FMT-09` 禁止 `git commit --no-verify`;如确因钩子故障,须在 PR 描述说明并附 CI 结果。
---
## 5 CI 门禁(阻断项)
| 阶段 | 命令 | 失败后果 |
| --- | --- | --- |
| 安装 | `pnpm install --frozen-lockfile` | 阻断(lock 不一致直接失败) |
| 格式 | `pnpm format:check` | 阻断 |
| Lint | `pnpm lint --max-warnings=0` | 阻断 |
| 类型 | `pnpm typecheck` | 阻断 |
| 单测 | `pnpm test -- --coverage` | 阻断(覆盖率不得低于基线) |
| 迁移 | `prisma migrate diff` 校验 schema 与迁移一致 | 阻断 |
| 构建 | `pnpm build` | 阻断 |
| 安全 | 依赖审计 + 镜像高危漏洞 | 阻断(高危 0) |
- `FMT-10` CI 与本地必须使用**同一份配置**,禁止 CI 单独放宽规则。
- `FMT-11` 覆盖率基线只升不降;下调须在 PR 说明理由并由技术负责人批准。
---
## 6 例外与豁免
| 场景 | 做法 |
| --- | --- |
| 生成代码(Prisma Client、OpenAPI 类型) | 在 `eslint.config.mjs` 中按路径 `ignores`,禁止在生成文件内加注释 |
| 第三方类型缺陷 | 文件级 `/* eslint-disable rule -- 原因 */`,必须写原因并在 PR 说明 |
| 单行特殊语法 | 行内 `// eslint-disable-next-line rule -- 原因` |
| 全文件 disable | **禁止**;确需则改为局部 disable 或调整规则配置 |
- `FMT-12` 任何 `eslint-disable` 都必须写明原因与到期处理方式(升级依赖 / 提 issue)。
- `FMT-13` 规则调整(新增 / 降级 / 关闭)必须单独 PR,说明影响文件数与整改计划。
---
## 7 检查清单
- [ ] `pnpm format:check` 通过,无格式化噪音混入
- [ ] `pnpm lint --max-warnings=0` 通过
- [ ] `pnpm typecheck` 通过
- [ ] 无新增 `eslint-disable`;已有的都有原因
- [ ] 未引入禁用包 / 禁用图标库
- [ ] 无散落色值,样式走 token