import { readFileSync, existsSync } from 'node:fs'; import { execSync } from 'node:child_process'; const root = 'd:/work/ylrz_saas'; const files = execSync('git show --name-only --pretty=format: 5dfe60ed', { cwd: root }) .toString('utf8') .split(/\r?\n/) .filter(Boolean); function scanFile(rel) { const path = `${root}/${rel.replace(/\\/g, '/')}`; if (!existsSync(path)) return null; if (!/\.(java|js|vue|sql|xml)$/.test(rel)) return null; const raw = readFileSync(path); const t = raw.toString('utf8'); const bom = raw.length >= 3 && raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf; const badLines = []; t.split('\n').forEach((line, i) => { if (line.includes('\uFFFD')) { badLines.push({ line: i + 1, kind: 'FFFD', text: line.trim().slice(0, 100) }); } else if (/[^\s"'/]\?{2,}[^\s?]/.test(line)) { badLines.push({ line: i + 1, kind: 'qmarks', text: line.trim().slice(0, 100) }); } }); const unicodeEscapes = (t.match(/\\u[0-9a-fA-F]{4}/g) || []).length; if (!bom && !badLines.length && unicodeEscapes === 0) return null; return { rel, bom, badLines: badLines.slice(0, 8), badLineCount: badLines.length, unicodeEscapes }; } const results = files.map(scanFile).filter(Boolean); console.log(JSON.stringify(results, null, 2)); console.log('files with issues:', results.length);