Implements the gate-consolidation Agent Note from the NIH dependency audit: - Shared markdownFences helper in scripts/markdown.ts (mdast code-node visit); doc-typecheck and verify-type-equiv extract fences through it; md-fences.ts and the duplicated extractEquivBlocks regex scanner are deleted; markdownProseLines derives fenced lines from parsed code-node positions instead of a second fence regex. - publint-all.ts and verify-built-package-invariants.mjs parse argv with node:util parseArgs instead of hand-stepped parseOptions copies. - Five straggler readdirSync walks become globSync: verify-runtime-closure, dev-web discoverPluginDirs, verify-package-paths realPackageNames, verify-client-domain-graph listSources, publint-all addPath. The dirent-diagnostic walks in check-workspace-constraints.ts and clean.ts stay. Behavior parity verified: pnpm run doc-sync and every rewritten gate produce byte-identical output before and after on this tree. Moves the owning Agent Note proposed -> implemented and re-records its pair.
5.1 KiB
5.1 KiB
Agent Note: 把门禁脚本统一到已有依赖与内置模块上
Status: implemented
English | 中文
问题
scripts/ 下的门禁大多已经在用正确的工具(15 个以上的门禁使用 node:fs 的 globSync,markdown 门禁使用 mdast/micromark),但少数几个掉队的脚本仍在手写同类门禁早已用既有依赖或内置模块完成的事情:
- 重复的围栏扫描器。
scripts/md-fences.ts(约 55 行,由doc-typecheck.ts消费)和scripts/verify-type-equiv.ts中的extractEquivBlocks(约 39 行)是同一个围栏代码块正则行扫描器的两份拷贝,而scripts/verify-mermaid.ts已经通过访问 mdastcode节点来提取代码围栏;scripts/markdown.ts自己的markdownProseLines也是先解析成 mdast,再用第二个正则手工跟踪围栏状态。这两个正则扫描器只识别第 0 列的反引号围栏,因此在波浪线围栏和缩进围栏上与基于 mdast 的门禁悄悄不一致。 - 手写的 argv 解析。
scripts/publint-all.ts中的parseOptions和scripts/verify-built-package-invariants.mjs中与之几乎相同的拷贝(约 26 行)手工推进 argv 下标,而同类脚本(verify-runtime-closure.ts、build-exe-for-python-sdk.ts、packages/sdk/scripts/src/args.ts)已经在使用node:util的内置parseArgs。 - **手写的目录遍历。**五处代码各自重写了
globSync已覆盖的嵌套readdirSync遍历:verify-runtime-closure.ts对 packages 与 vendor manifest(元数据清单)的扫描、dev-web.ts的discoverPluginDirs、verify-package-paths.ts的realPackageNames、verify-client-domain-graph.ts的listSources,以及publint-all.ts的addPath(合计约 55–65 行)。scripts/package-invariants.ts展示了一行式的globSync模板。
所有替换都不需要引入新依赖;每一处替换用的都是既有的 devDependency 或 Node 内置模块。
决策
scripts/markdown.ts中的共享 mdast 围栏辅助函数markdownFences访问code节点,读取语言、完整 info string、块体以及以 1 起始的开围栏行号;doc-typecheck.ts和verify-type-equiv.ts通过它提取代码围栏。md-fences.ts和重复的extractEquivBlocks扫描器已删除,markdownProseLines也改为从解析出的code节点位置推导围栏内的行,而不再用第二个正则。- 两个 CLI 都改用
parseArgs解析 argv;未知选项和缺失取值仍然大声失败,只是错误文案换成了parseArgs自带的文本,而非原先手写的用法字符串。 - 那五处掉队的目录遍历改用
globSync。check-workspace-constraints.ts和clean.ts中的遍历保留:它们需要 dirent 级别的细节来诊断结构异常的目录树,按模式匹配的 glob 报告不了这些信息。
曾考虑的替代方案
- **新的 glob/目录遍历依赖(
tinyglobby、fdir)。**不予采纳:内置模块已在全仓库范围内胜出;这几处只是掉队者,不是能力缺口。 - **用
p-map替换publint-all.ts中约 19 行的有序 worker 池。**刻意未纳入:为一次小删除引入一个新 devDependency,正处在依赖策略门槛的边缘,而且该池的需求(worker 数量有界、确定性顺序、环境变量覆盖)已记录在并行 pre-push 门禁决策记录中。仅当p-map赢得第二个消费方时再顺带纳入。 - **保留这两个围栏扫描器。**不予采纳:在第三个正确实现旁边放着两份逐渐漂移的解析器拷贝,正是共享的
markdown.ts辅助函数要防止的那种重复;「只认第 0 列反引号」的限制也是同类门禁之间的潜在不一致。
后果
- 只剩一个围栏解析器:所有 markdown 门禁现在都经由 mdast 归类代码围栏,因此波浪线围栏、缩进围栏和四反引号容器围栏在各处的行为完全一致。文档树中不存在正则扫描器处理有误的围栏形态,所以在落地这次替换的代码树上门禁结果不变:
pnpm run doc-sync及每个被改写的门禁在改动前后各跑一遍,输出逐字节相同(doc-typecheck的块数/opt-out 计数、verify-type-equiv的匹配计数、publint、verify-built-package-invariants、verify-runtime-closure、verify-package-paths、verify-client-domain-graph,以及两个包 README 散文门禁)。 verify-type-equiv不再对未闭合的围栏报专门的错误:mdast 会在文件末尾闭合未闭合的代码块,这样的块会进入 manifest 检查,并在那里以孤儿或漂移的形式照样失败,而不是触发专门的扫描器错误。doc-typecheck的扫描器本来就没有这条错误路径。parseArgs对重复出现的选项保留最后一个值而不报错,还会把下一个以--开头的 token 当作值消费;这两种情况都是测试未固定的开发工具边缘用例,作为删除两份手写解析器的交换被接受。