const fs = require('node:fs'); const path = require('node:path'); const assert = require('node:assert/strict'); const root = path.resolve(__dirname, '../..'); const files = ['docs/104/IEC104_API接口汇总.md', 'docs/104/IEC104_完整调用流程.md']; for (const file of files) { const bytes = fs.readFileSync(path.join(root, file)); const source = new TextDecoder('utf-8', { fatal: true }).decode(bytes); const baseline = fs.readFileSync(path.join(__dirname, path.basename(file) + '.before')); assert.equal(bytes.subarray(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf])), baseline.subarray(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf])), `${file}: BOM changed`); assert(!source.includes('\ufffd') && !source.includes('\r'), `${file}: encoding or line ending`); assert(source.endsWith('\n') && !/[\t ]+$/m.test(source), `${file}: whitespace`); const ids = new Set(); let fence = '', details = 0, blocks = 0; const tableProblems = []; let tableColumns = 0; for (const [index, line] of source.split('\n').entries()) { const marker = /^(`{3,}|~{3,})/.exec(line); if (marker) { if (!fence) { fence = marker[1]; blocks++; } else if (marker[1][0] === fence[0] && marker[1].length >= fence.length) fence = ''; tableColumns = 0; continue; } if (fence) continue; for (const match of line.matchAll(//g)) { assert(!ids.has(match[1]), `${file}:${index + 1}: duplicate id ${match[1]}`); ids.add(match[1]); } if (line.includes('
')) details++; if (line.includes('
')) details--; assert(details >= 0, `${file}:${index + 1}: unexpected details close`); if (/^\|/.test(line)) { const columns = (line.replace(/\\\|/g, '').match(/\|/g) || []).length; if (tableColumns && columns !== tableColumns) tableProblems.push(index + 1); tableColumns = columns; } else tableColumns = 0; } assert(!fence && details === 0, `${file}: unclosed fence/details`); assert.deepEqual(tableProblems, [], `${file}: inconsistent table column count`); for (const id of baseline.toString('utf8').matchAll(//g)) { assert(ids.has(id[1]), `${file}: removed existing anchor ${id[1]}`); } console.log(`${file}: ${blocks} fenced blocks, ${ids.size} stable anchors, UTF-8/LF and tables OK`); }