fix(scripts): address review findings on the gate consolidation

- publint-all: the recursive publication view uses readdirSync
  {recursive} again instead of globSync('**/*') — the glob skips
  dot-prefixed segments (verified empirically), but npm pack publishes
  dotfiles inside included directories, so hidden exports were
  reported missing and other hidden files escaped validation
- markdown.ts/verify-type-equiv: markdownFences now reports whether a
  closing delimiter terminates the block (mdast silently closes an
  unterminated fence at EOF), and verify-type-equiv rejects unclosed
  type-equivalence fences again — the Agent Note claimed such a block
  still fails at the manifest checks, but its comparisons can succeed
- Agent Note EN+ZH: record the restored rejection; rewrite the zh
  Problem section into past tense to match the English side's shipped
  reality; pair re-recorded
This commit is contained in:
Tianyi Cui
2026-07-27 12:02:39 +08:00
parent 035a965973
commit ebdcb5776a
6 changed files with 26 additions and 10 deletions

View File

@@ -31,6 +31,12 @@ export interface MarkdownFence {
info: string
/** Block body without the fence delimiters. */
code: string
/**
* Whether a closing fence delimiter terminates the block — mdast silently
* closes an unterminated fence at end of file. False on indented
* (non-fenced) blocks, whose end line is code.
*/
closed: boolean
}
/** Parse GitHub-flavored Markdown with the repository's standard extensions. */
@@ -56,13 +62,16 @@ export function visitMarkdown(node: Nodes, visitor: (node: Nodes) => boolean | v
* @returns each block's opening line, language, info string, and body.
*/
export function markdownFences(source: string): MarkdownFence[] {
const lines = source.split('\n')
const fences: MarkdownFence[] = []
visitMarkdown(parseMarkdown(source), (node) => {
if (node.type !== 'code' || node.position === undefined) return
const lang = node.lang ?? null
const meta = node.meta ?? ''
const info = lang === null ? '' : meta === '' ? lang : `${lang} ${meta}`
fences.push({ line: node.position.start.line, lang, info, code: node.value })
const endLine = lines[node.position.end.line - 1] ?? ''
const closed = /^ {0,3}(`{3,}|~{3,})\s*$/.test(endLine)
fences.push({ line: node.position.start.line, lang, info, code: node.value, closed })
})
return fences
}

View File

@@ -2,6 +2,7 @@
import {
globSync,
readdirSync,
readFileSync,
statSync,
} from 'node:fs'
@@ -91,7 +92,10 @@ function publicationFiles(target: PackageTarget): PackFile[] {
function addPath(path: string, paths: Set<string>): void {
const stat = statSync(path)
if (stat.isDirectory()) {
for (const entry of globSync('**/*', { cwd: path, withFileTypes: true })) {
// readdirSync, not globSync: `**/*` skips dot-prefixed segments, but npm
// pack publishes dotfiles inside included directories, and this view must
// match what npm publishes.
for (const entry of readdirSync(path, { recursive: true, withFileTypes: true })) {
if (entry.isFile()) paths.add(resolve(entry.parentPath, entry.name))
}
} else if (stat.isFile()) {

View File

@@ -88,6 +88,9 @@ function extractEquivBlocks(docRel: string): EquivBlock[] {
throw new Error(`verify-type-equiv: ${docRel}:${fence.line} — use the concise \`ts public-api\` fence`)
}
if (fence.info !== 'ts type-equiv' && fence.info !== 'ts public-api') continue
if (!fence.closed) {
throw new Error(`verify-type-equiv: ${docRel}:${fence.line} — unterminated type-equivalence fence (missing closing \`\`\`)`)
}
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`)