GRP-002 循环引用
将文档间的 Markdown 链接视为图,验证是否存在循环(如 A → B → C → A 这样的闭环)。发现循环时,会报告为 error。这是项目作用域规则,会跨越 include 加载的所有文档进行评估。
检测对象仅限相对路径指向 .md 文件的链接。仅锚点链接(#section)和外部 URL 会被忽略。
文档 A 引用 B,B 引用 C,C 又引用 A,这样的循环单看任意一个文件都不可能察觉。维持一致的依赖关系需要文档图为 DAG(有向无环图);循环会导致读者困惑,并使更新影响范围难以追踪。用 AI 大量生成文档时,链接也可能在无意中变为双向,从而产生循环。本规则可检测此类循环。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
files | string | — | 循环检测对象的文件 glob。未指定则覆盖所有文档 |
exclude | string[] | — | 从图中排除的文件 glob 数组 |
siteRouter | object | — | 解析 Starlight 等 SSG 生成的 routed URL(如 /docs/x/),让循环检测能沿这些链接遍历 |
省略全部选项也可工作。exclude 用于排除像目录文件或 index 文件那样有意持有多向链接的文件。
siteRouter — SSG 的 routed URL 支持
Section titled “siteRouter — SSG 的 routed URL 支持”不指定 siteRouter 时,/docs/x/ 这类绝对 URL 在构建图时会被跳过,因此经由 SSG 生成链接的循环不会被检出。可用字段与 REF-001 的 siteRouter 完全相同。
| 子字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
preset | string | — | 已知的 SSG 预设。目前仅支持 "starlight" |
contentDir | string | ✓ | 内容目录(如 "packages/site/src/content/docs") |
defaultLocale | string | — | 默认 locale。Starlight 无前缀的 root locale 指定为 "root" |
locales | string[] | — | 支持的 locale 列表(如 ["root", "ja", "ko", "zh"]) |
urlPrefix | string | — | (不使用 preset 的通用配置) 从 URL 中剥离的前缀 |
indexFile | string | — | 最先尝试的 index 文件名(默认: "index.md") |
Starlight (i18n) 示例:
{ "rule": "grp002", "options": { "siteRouter": { "preset": "starlight", "contentDir": "packages/site/src/content/docs", "defaultLocale": "root", "locales": ["root", "ja", "ko", "zh"] } }}docs/a.md:
# ASee [B](./b.md).
docs/b.md:
# BSee [C](./c.md).
docs/c.md:
# CSee [A](./a.md).发生 a.md → b.md → c.md → a.md 的循环,故判定为违例。
docs/a.md line 2 error Circular reference detected: docs/a.md -> docs/b.md -> docs/c.md -> docs/a.md GRP-002切断循环中「依赖最弱的链接」。例如把 c.md → a.md 的链接换成其它表达方式。
docs/c.md:
# C
This module is consumed by upstream documents.{ "rule": "grp002", "options": { "files": "docs/**/*.md", "exclude": ["docs/index.md", "docs/sitemap.md"] }}exclude 中指定的文件会作为节点从图中整体排除。经由它们形成的循环不在检测对象内,因此推荐仅用于必须双向链接的目录类文件。
- REF-001 链接断裂 — 验证链接目标文件是否实际存在
- GRP-001 可追溯链 — 基于表格的 ID 引用链验证
- GRP-003 孤立文档 — 检测未被任何文档引用的文件