| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- import { readFileSync, readdirSync, statSync } from 'node:fs';
- import { join, relative } from 'node:path';
- const root = 'd:/work/ylrz_saas/java';
- function walk(dir, out = []) {
- for (const name of readdirSync(dir)) {
- const p = join(dir, name);
- const st = statSync(p);
- if (st.isDirectory()) {
- if (name === 'target' || name === 'node_modules' || name === '.git') continue;
- walk(p, out);
- } else if (name.endsWith('.java')) {
- out.push(p);
- }
- }
- return out;
- }
- function hasMojibakeLatin(line) {
- // UTF-8 CJK misread as Latin-1 often produces 3+ chars in U+00C0..U+00FF range
- const m = line.match(/[\u00c0-\u00ff]{3,}/g);
- if (!m) return false;
- return /\/\/|\/\*|\*|"|'|error\(|success\(|return /.test(line);
- }
- function scanFile(absPath) {
- const raw = readFileSync(absPath);
- const rel = relative('d:/work/ylrz_saas', absPath).replace(/\\/g, '/');
- const bom = raw.length >= 3 && raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf;
- const t = raw.toString('utf8');
- const badLines = [];
- t.split('\n').forEach((line, i) => {
- const n = i + 1;
- if (line.includes('\uFFFD')) {
- badLines.push({ line: n, kind: 'FFFD', text: line.trim().slice(0, 100) });
- return;
- }
- if (line.includes('\u951f\u65a4\u70b7')) {
- badLines.push({ line: n, kind: 'replacement-seq', text: line.trim().slice(0, 100) });
- return;
- }
- if (hasMojibakeLatin(line)) {
- badLines.push({ line: n, kind: 'latin-mojibake', text: line.trim().slice(0, 100) });
- return;
- }
- if (/[^\s"'/\\]\?{2,}[^\s?]/.test(line) && /\/\/|\/\*|"|'|error\(|success\(/.test(line)) {
- badLines.push({ line: n, kind: 'qmarks', text: line.trim().slice(0, 100) });
- }
- });
- const unicodeEscapes = (t.match(/\\u[0-9a-fA-F]{4}/g) || []).length;
- if (!bom && !badLines.length) return null;
- return { rel, bom, badLineCount: badLines.length, badLines: badLines.slice(0, 5), unicodeEscapes };
- }
- const files = walk(root);
- const issues = files.map(scanFile).filter(Boolean);
- issues.sort((a, b) => a.rel.localeCompare(b.rel));
- const summary = {
- scanned: files.length,
- filesWithIssues: issues.length,
- bomFiles: issues.filter((x) => x.bom).map((x) => x.rel),
- fffdFiles: issues.filter((x) => x.badLines.some((l) => l.kind === 'FFFD')).map((x) => x.rel),
- issues: issues.map((x) => ({
- rel: x.rel,
- bom: x.bom,
- badLineCount: x.badLineCount,
- samples: x.badLines,
- })),
- };
- import { writeFileSync } from 'node:fs';
- const outPath = 'd:/work/ylrz_saas/java/fs-service/scripts/scan_java_encoding_result.json';
- writeFileSync(outPath, JSON.stringify(summary, null, 2), 'utf8');
- console.log('scanned', summary.scanned, 'java files');
- console.log('files with issues', summary.filesWithIssues);
- console.log('BOM files', summary.bomFiles.length);
- console.log('FFFD files', summary.fffdFiles.length);
- console.log('result', outPath);
- if (summary.fffdFiles.length) {
- console.log('FFFD list:');
- summary.fffdFiles.forEach((f) => console.log(' ', f));
- }
|