Skip to content

docs-gen: 无标题的 {@link ../x.zod.ts} 被渲染成「链接套链接」—— 2 张已发布参考页正文里能直接看到 #6136

Description

@os-zhuang

在实施 #5059(参考页开篇取块规则)时,给渲染管线补 pin 用例顺带扫出。与 #5059 不同根因、不同代码段(#5059 改的是选哪个 doc block,本单在选定之后的渲染链),故单独立单。与 #5553 同处一条渲染链但也是第三条独立缺陷:#5553 是按行拆段落 + 花括号无差别转义,修好那两点也不会修好这一条。

现象(origin/main 8195184e)

packages/spec/scripts/lib/file-description.ts(#5059 从 build-docs.ts 抽出前是 getFileDescription())对模块 JSDoc 依次做两次替换:

// 1) 先把 {@link target} 换成 markdown 链接
.replace(/\{@link\s+([^}]+?)\s*\}/g, (_m, target) => {
  const route = sourcePathToDocsRoute(target.trim());
  return route ? `[${target.trim()}](${route})` : `\`${target.trim()}\``;
})
// 2) 再把「正文里裸露的源码路径」也换成链接
.replace(/(?<!\()\b((?:\.\.\/)?[\w-]+\/[\w.-]+\.zod\.ts)\b(?!\))/g, (_m0, p) => { … })

第 (1) 步产出的是 [../a/b.zod.ts](/docs/references/a/b) —— 链接文本里就是那条路径。第 (2) 步的前后瞻只排除了「前面是 (」和「后面是 )」,而这里路径前面是 [、后面是 ],所以第二次照样命中,再包一层。

落到已发布页面上(两处,grep -rn '\[\.\./\[' content/docs/references/):

content/docs/references/automation/etl.mdx:54:
See also: [../[integration/connector.zod.ts](/docs/references/integration/connector)](/docs/references/integration/connector) for the Enterprise Connector layer

content/docs/references/integration/connector.mdx:102:
See also: [../[automation/etl.zod.ts](/docs/references/automation/etl)](/docs/references/automation/etl) for the ETL Pipeline layer (data engineering)

读者看到的是一个链接文本里又嵌了一个链接 —— MDX 渲染后是残缺的方括号与重复文字,不是一条可点的「另见」。

触发条件

只有无标题形式 {@link 路径} 会中招;带标题的 {@link 路径 | 文本} 走的是上面那条更靠前的替换,产出的链接文本是「文本」而不是路径,第 (2) 步匹配不到。两处受害都来自 @see 标签(@see ../integration/connector.zod.ts 先被改写成 See also: …,再被第 (2) 步吃掉),形状与 {@link} 无标题分支等价。

修法方向(未验证)

第 (2) 步的职责是「补上正文里裸露的路径」,所以它必须跳过已经在 markdown 链接内的路径 —— 与 escape-mdx.ts 需要感知反引号跨度是同一类问题。可行做法:第 (2) 步只在链接语法之外的片段上跑(先按 \[[^\]]*\]\([^)]*\) 切段),而不是靠加长前后瞻(前后瞻挡不住嵌套)。

验收:grep -rn '\[\.\./\[' content/docs/references/ 归零,且上面两句恢复成单个可点链接。#5059 已把这段渲染抽到 lib/file-description.ts 并配了 scripts/file-description.test.ts,新用例可直接加在那里,不必跑整个生成器再 grep .mdx。

影响面

2 张已发布参考页的正文各一处,读者今天访问就能看到。纯展示层,无运行时/协议语义。

范围外,故单开,不在 #5059 的 PR(#6134)里改 —— 那个 PR 只改选块规则,渲染链一字未动(它的 pin 用例特意用带标题的 {@link … | …} 形式,并在注释里写明「不 pin 这条已知缺陷,pin 了等于追认」)。

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Triage: pm:queue; domain:spec-tooling confirmed as filed (kept, not re-applied).

    Landing site. packages/spec/scripts/lib/file-description.ts — inside the domain:spec-tooling seat's declared file surface (packages/spec/scripts/**, seat post #6018). The filer's self-applied domain label is correct on the code, so it stands; recording the confirmation because a domain:* that never passed this seat is exactly the shape the 20:47Z sweep found rotting in a four-way blind spot.

    Stale-premise check — the one thing that could have invalidated this issue, and did not. The file only exists on main because #5059's PR #6134 merged (52760bf, top of git log origin/main -- packages/spec/scripts/). Filed against a path that was hours old; re-verified rather than assumed. Both replace steps are still present exactly as quoted, and the two published victims still reproduce:

    $ grep -rn '\[\.\./\[' content/docs/references/
    automation/etl.mdx:54
    integration/connector.mdx:102
    

    Graded a defect, not an observation. Two reference pages are wrong in published output today, and the acceptance criterion is mechanical (grep to zero + both sentences render as one clickable link). Presentation-layer only, no runtime or protocol semantics ⇒ not target:v17 — improvement-class surfaces catch the next train.

    Dedup (full enumeration; search API unavailable to this seat). Three docs-gen neighbours are open, all distinct code, all already queued: #5553 (per-line paragraph splitting + indiscriminate brace escaping — same render chain, and the issue is right that fixing it does not fix this), #5853 (getCategoryTitle() capitalisation), #5059→#6134 (which block gets picked, upstream of this one, now merged). No duplicate.

    ⚠️ Serialization trap for the spec-tooling seat. #5553 and this one are the second and third independent defects on one render chain, and #5553's fix touches escaping/segmentation logic that may well sit in the same module after #5059's extraction. Do not batch them together — same-file/same-package items serialize strictly across rounds. Whichever goes first, the other's cost estimate should be re-read afterwards rather than carried over from filing time.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. added and removed
    bugSomething isn't working
    on Aug 7, 2026
  3. self-assigned this
    on Aug 7, 2026
  4. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 5 轮(spec-tooling 车道,座位登记 #6018)
    会话:session_014wsZeReNTqiceBfLb5Pyf5
    分支:claude/issue-5553-file-description-rendering(与 #5553 打包,同一 PR 双 Fixes)
    Worktree:objectstack-issue-5553
    域:domain:spec-tooling

    打包依据:落点核实两单同落 packages/spec/scripts/lib/file-description.ts,同一渲染链上的两个独立缺陷(#6136 的立单者在 #5059 报告里已明确「fixing #5553's paragraph split and brace escaping does not fix it」——所以是两条独立断言,不是重复单)。分开派各付一次 references 重生成且互埋 diff。

    文件面同 #5553 的认领评论。(越界即停,报告说明)


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions