refactor(scripts): consolidate gate scripts on mdast fences, parseArgs, and globSync

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.
This commit is contained in:
Tianyi Cui
2026-07-26 23:14:28 +08:00
parent c9dc097749
commit c3873464ba
15 changed files with 163 additions and 268 deletions

View File

@@ -11,6 +11,7 @@
import { globSync, readFileSync, existsSync } from 'node:fs'
import { resolve, sep } from 'node:path'
import ts from 'typescript'
import { markdownFences } from './markdown.ts'
import { partitionPairedMarkdownDerivatives } from './paired-markdown-derivatives.ts'
const root = resolve(import.meta.dirname, '..')
@@ -80,42 +81,24 @@ function blockSymbol(code: string): string | null {
/** Extract every source-equivalence block from one Markdown file. */
function extractEquivBlocks(docRel: string): EquivBlock[] {
const text = readFileSync(resolve(root, docRel), 'utf8')
const lines = text.split('\n')
const blocks: EquivBlock[] = []
let open: { line: number; body: string[]; projection?: 'public-api' } | null = null
for (let i = 0; i < lines.length; i++) {
const raw = lines[i] ?? ''
const fence = /^```(\s*)(\S.*)?$/.exec(raw)
if (!fence) {
if (open) open.body.push(raw)
continue
for (const fence of markdownFences(readFileSync(resolve(root, docRel), 'utf8'))) {
if (fence.info === 'ts type-equiv public-api') {
throw new Error(`verify-type-equiv: ${docRel}:${fence.line} — use the concise \`ts public-api\` fence`)
}
if (open) {
const code = open.body.join('\n')
const symbol = blockSymbol(code)
if (!symbol) {
throw new Error(`verify-type-equiv: ${docRel}:${open.line} — type-equiv block has no parseable interface/type/class declaration`)
}
blocks.push({
doc: docRel,
line: open.line,
symbol,
code,
...(open.projection === undefined ? {} : { projection: open.projection }),
})
open = null
continue
if (fence.info !== 'ts type-equiv' && fence.info !== 'ts public-api') continue
const symbol = blockSymbol(fence.code)
if (symbol === null) {
throw new Error(`verify-type-equiv: ${docRel}:${fence.line} — type-equiv block has no parseable interface/type/class declaration`)
}
const info = (fence[2] ?? '').trim()
if (info === 'ts type-equiv public-api') {
throw new Error(`verify-type-equiv: ${docRel}:${i + 1} — use the concise \`ts public-api\` fence`)
}
if (info === 'ts type-equiv') open = { line: i + 1, body: [] }
if (info === 'ts public-api') open = { line: i + 1, body: [], projection: 'public-api' }
blocks.push({
doc: docRel,
line: fence.line,
symbol,
code: fence.code,
...(fence.info === 'ts public-api' ? { projection: 'public-api' as const } : {}),
})
}
if (open) throw new Error(`verify-type-equiv: ${docRel}:${open.line} — unterminated type-equiv block`)
return blocks
}