Files
Investidor-V2/tools/portal-next-lint-cleanup.cjs
T
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

137 lines
4.6 KiB
JavaScript

// Target the diagnostics from the current source; preserve literals and API property names.
const fs = require('node:fs'),
path = require('node:path'),
ts = require('typescript');
const root = path.resolve(__dirname, '..');
const input = path.join(
root,
'storage/app/private/investmoz-v2/portal-audit/next-lint-diagnostics.json',
);
const raw = fs.readFileSync(input);
const data = JSON.parse(
raw
.toString(raw[0] === 255 && raw[1] === 254 ? 'utf16le' : 'utf8')
.replace(/^\uFEFF/, ''),
);
const byFile = new Map();
for (const d of data.diagnostics) {
const group = byFile.get(d.filename) || [];
group.push(d);
byFile.set(d.filename, group);
}
let changed = 0;
for (const [name, diagnostics] of byFile) {
const file = path.resolve(root, name);
if (!file.startsWith(root + path.sep))
throw Error('Target outside workspace');
let source = fs.readFileSync(file, 'utf8');
const parsed = ts.createSourceFile(
name,
source,
ts.ScriptTarget.Latest,
true,
name.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.JS,
);
const edits = [];
const seen = new Set();
function edit(start, end, value) {
const key = start + ':' + end;
if (seen.has(key)) return;
seen.add(key);
edits.push({ start, end, value });
}
function walk(node, fn) {
fn(node);
ts.forEachChild(node, (n) => walk(n, fn));
}
for (const d of diagnostics) {
if (d.code === 'eslint(no-unused-vars)') {
for (const label of d.labels) {
const bytes = Buffer.from(source),
start = bytes
.subarray(0, label.span.offset)
.toString().length,
end = bytes
.subarray(0, label.span.offset + label.span.length)
.toString().length;
let id;
walk(parsed, (n) => {
if (
ts.isIdentifier(n) &&
n.getStart(parsed) === start &&
n.end === end
)
id = n;
});
if (!id) throw Error('Diagnostic no longer matches ' + name);
const alias = '_' + id.text;
const parent = id.parent;
edit(
start,
end,
ts.isShorthandPropertyAssignment(parent) ||
(ts.isBindingElement(parent) &&
!parent.propertyName &&
ts.isObjectBindingPattern(parent.parent))
? id.text + ': ' + alias
: alias,
);
}
} else if (d.code === 'typescript(no-floating-promises)') {
const span = d.labels[0].span,
bytes = Buffer.from(source),
start = bytes.subarray(0, span.offset).toString().length,
end = bytes
.subarray(0, span.offset + span.length)
.toString().length;
let statement;
walk(parsed, (n) => {
if (
ts.isExpressionStatement(n) &&
n.expression.getStart(parsed) <= start &&
n.expression.end >= end
)
statement = n;
});
if (!statement) throw Error('Promise expression not found ' + name);
edit(
statement.expression.getStart(parsed),
statement.expression.getStart(parsed),
'void ',
);
}
}
if (
name.startsWith('resources/') &&
diagnostics.some((d) => d.code === 'typescript(no-base-to-string)')
) {
walk(parsed, (n) => {
if (
ts.isCallExpression(n) &&
ts.isIdentifier(n.expression) &&
n.expression.text === 'String'
)
edit(
n.expression.getStart(parsed),
n.expression.end,
'valueText',
);
});
edit(0, 0, "import { valueText } from '@/lib/value-text';\n");
}
edits.sort((a, b) => b.start - a.start || b.end - a.end);
for (const e of edits)
source = source.slice(0, e.start) + e.value + source.slice(e.end);
if (edits.length) {
fs.writeFileSync(file, source);
changed++;
}
}
console.log(
JSON.stringify({
changed_files: changed,
diagnostic_bound_edits: true,
database_writes: 0,
}),
);