@mocoto/mahoraga 0.14.2 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -34
- package/dist/analysts/architects/analyst-structure.js +19 -19
- package/dist/analysts/architects/archetypes-custom.js +8 -6
- package/dist/analysts/architects/detector-archetypes.js +30 -27
- package/dist/analysts/architects/signals-project-advanced.js +24 -26
- package/dist/analysts/architects/signals-project.js +1 -1
- package/dist/analysts/architects/strategist-structure.js +47 -66
- package/dist/analysts/azure-pipelines/analysts/analyst-azure.js +21 -14
- package/dist/analysts/azure-pipelines/corrections/correction-azure.js +22 -19
- package/dist/analysts/azure-pipelines/detectors/detector-azure-performance.js +21 -18
- package/dist/analysts/azure-pipelines/detectors/detector-azure-security.js +25 -20
- package/dist/analysts/azure-pipelines/detectors/detector-azure-structure.js +39 -37
- package/dist/analysts/azure-pipelines/scorers/scorer-azure.js +10 -7
- package/dist/analysts/circleci/analysts/analyst-circleci.js +23 -15
- package/dist/analysts/circleci/corrections/correction-circleci.js +22 -20
- package/dist/analysts/circleci/detectors/detector-circleci-performance.js +23 -19
- package/dist/analysts/circleci/detectors/detector-circleci-security.js +78 -82
- package/dist/analysts/circleci/detectors/detector-circleci-structure.js +20 -17
- package/dist/analysts/converters/engines/converter-gha-to-gitlab.js +17 -15
- package/dist/analysts/corrections/analyst-quick-fixes.js +25 -28
- package/dist/analysts/corrections/analyst-scoring.js +24 -21
- package/dist/analysts/corrections/corrector-structure.js +35 -35
- package/dist/analysts/corrections/fix-alias-imports.js +10 -6
- package/dist/analysts/corrections/fix-md-fences.js +23 -23
- package/dist/analysts/corrections/map-reversion.js +54 -51
- package/dist/analysts/corrections/pruning.js +19 -16
- package/dist/analysts/corrections/quick-fixes/fix-any-to-proper-type.js +57 -61
- package/dist/analysts/corrections/quick-fixes/fix-unknown-to-specific-type.js +30 -30
- package/dist/analysts/corrections/reorganize-barrels.js +10 -10
- package/dist/analysts/corrections/scoring-shared.js +19 -18
- package/dist/analysts/corrections/type-safety/context-analyzer.js +15 -10
- package/dist/analysts/corrections/type-safety/type-validator.js +2 -1
- package/dist/analysts/corrections/type-safety/usage-analyzer.js +36 -39
- package/dist/analysts/css/analysts/analyst-css.js +16 -15
- package/dist/analysts/css/corrections/correction-css.js +19 -11
- package/dist/analysts/css/detectors/detector-css-best-practices.js +129 -118
- package/dist/analysts/css/scorers/scorer-css.js +23 -18
- package/dist/analysts/css-in-js/analysts/analyst-css-in-js.js +24 -17
- package/dist/analysts/css-in-js/corrections/correction-css-in-js.js +31 -16
- package/dist/analysts/css-in-js/detectors/detector-css-in-js-best-practices.js +20 -15
- package/dist/analysts/css-in-js/scorers/scorer-css-in-js.js +79 -54
- package/dist/analysts/css-in-js/shared.js +7 -0
- package/dist/analysts/detectors/detector-architecture.js +89 -83
- package/dist/analysts/detectors/detector-bugs-ml.js +21 -19
- package/dist/analysts/detectors/detector-code-fragile.js +30 -26
- package/dist/analysts/detectors/detector-duplications.js +21 -18
- package/dist/analysts/detectors/detector-monorepo.js +41 -36
- package/dist/analysts/detectors/detector-performance.js +22 -16
- package/dist/analysts/detectors/detector-recommendation-architecture.js +39 -35
- package/dist/analysts/detectors/detector-security.js +43 -42
- package/dist/analysts/detectors/detector-structure.js +29 -26
- package/dist/analysts/js-ts/detectors/detector-anti-patterns-async.js +4 -1
- package/dist/analysts/js-ts/detectors/detector-constructions-syntactic.js +10 -16
- package/dist/analysts/plugins/detector-documentation.js +1 -0
- package/dist/analysts/react/analysts/analyst-react-hooks.js +4 -2
- package/dist/analysts/react/analysts/analyst-react.js +1 -1
- package/dist/analysts/react/corrections/correction-react.js +2 -2
- package/dist/analysts/react/detectors/detector-react-best-practices.js +1 -1
- package/dist/analysts/registry/autodiscovery.js +2 -2
- package/dist/analysts/tailwind/corrections/correction-tailwind.js +0 -8
- package/dist/analysts/tailwind/scorers/scorer-tailwind.js +1 -2
- package/dist/cli/commands/command-analysts.js +3 -2
- package/dist/cli/commands/command-formatters.js +1 -1
- package/dist/cli/commands/command-github-actions.js +1 -1
- package/dist/cli/commands/command-guardian.js +1 -1
- package/dist/cli/commands/command-marketplace.js +4 -4
- package/dist/cli/diagnostic/filters.js +9 -9
- package/dist/core/config/chalk-safe.js +4 -4
- package/dist/core/config/config.js +5 -5
- package/dist/core/execution/analysis-cache.js +1 -1
- package/dist/core/execution/ast-cache.js +1 -3
- package/dist/core/execution/executor.js +2 -4
- package/dist/core/execution/scanner.js +1 -1
- package/dist/core/messages/en/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/en/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/ja/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/ja/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/pt/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/pt/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/zh/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/zh/caretakers/caretaker-messages.js +1 -7
- package/dist/core/parsing/parser.js +2 -3
- package/dist/core/parsing/utils.js +1 -0
- package/dist/core/workers/worker-pool.js +0 -0
- package/dist/guardian/records.js +1 -0
- package/dist/guardian/sentinel.js +1 -0
- package/dist/guardian/watcher-hidden.js +1 -0
- package/dist/licenses/fs-utils.js +2 -1
- package/dist/licenses/header-options.js +1 -0
- package/dist/licenses/index.js +1 -1
- package/dist/reports/generator-report.js +3 -3
- package/dist/reports/report-patterns-usage.js +1 -1
- package/dist/shared/data-processing/fragment-report.js +1 -1
- package/dist/shared/formatters/engines/stylelint.js +40 -34
- package/dist/shared/formatters/formatters/markdown.js +1 -1
- package/dist/shared/helpers/framework-detector.js +5 -1
- package/dist/shared/persistence/persistence.js +13 -5
- package/dist/shared/plugins/core-plugin.js +3 -1
- package/dist/types/analysts/tailwind-correction.js +2 -0
- package/dist/types/index.js +3 -3
- package/dist/types/processing/filters.js +5 -4
- package/dist/vulnerabilities/npm-audit.js +1 -0
- package/dist/vulnerabilities/scanner.js +1 -1
- package/dist/vulnerabilities/vulnerabilities.js +1 -0
- package/package.json +5 -10
|
@@ -42,32 +42,35 @@ export const analistaQuickFixes = {
|
|
|
42
42
|
const uniqueFixes = quickFixes.filter((fix, index, arr) => arr.findIndex(arquivo => arquivo.id === fix.id) === index);
|
|
43
43
|
for (const fixResultado of uniqueFixes) {
|
|
44
44
|
for (const match of fixResultado.matches) {
|
|
45
|
-
|
|
46
|
-
const previewCorrecao = fixResultado.fix(match, src);
|
|
47
|
-
const originalLine = src.split('\n')[linha - 1] || '';
|
|
48
|
-
const fixedLine = previewCorrecao.split('\n')[linha - 1] || '';
|
|
49
|
-
const sugestao = [fixResultado.description, '', `[CHAVE-INGLESA] Correção sugerida:`, `[ERRO] Antes: ${originalLine.trim()}`, `[OK] Depois: ${fixedLine.trim()}`, '', `Confiança: ${fixResultado.confidence}%`, `Categoria: ${fixResultado.category}`, `ID do Fix: ${fixResultado.id}`].join('\n');
|
|
50
|
-
const nivel = mapearCategoriaNivel(fixResultado.category);
|
|
51
|
-
const ocorrencia = criarOcorrencia({
|
|
52
|
-
tipo: 'auto-fix-disponivel',
|
|
53
|
-
nivel,
|
|
54
|
-
mensagem: fixResultado.title,
|
|
55
|
-
relPath,
|
|
56
|
-
linha
|
|
57
|
-
});
|
|
58
|
-
const ocorrenciaGenerica = ocorrencia;
|
|
59
|
-
ocorrenciaGenerica.sugestao = sugestao;
|
|
60
|
-
ocorrenciaGenerica.quickFixId = fixResultado.id;
|
|
61
|
-
ocorrenciaGenerica.confidence = fixResultado.confidence;
|
|
62
|
-
ocorrenciaGenerica.category = fixResultado.category;
|
|
63
|
-
ocorrenciaGenerica.matchIndex = match.index;
|
|
64
|
-
ocorrenciaGenerica.matchLength = match[0].length;
|
|
65
|
-
ocorrencias.push(ocorrencia);
|
|
45
|
+
processQuickFixMatchScoring(match, fixResultado, src, relPath, ocorrencias);
|
|
66
46
|
}
|
|
67
47
|
}
|
|
68
48
|
return ocorrencias;
|
|
69
49
|
}
|
|
70
50
|
};
|
|
51
|
+
function processQuickFixMatchScoring(match, fixResultado, src, relPath, ocorrencias) {
|
|
52
|
+
const linha = calcularLinha(src, match.index, match);
|
|
53
|
+
const previewCorrecao = fixResultado.fix(match, src);
|
|
54
|
+
const originalLine = src.split('\n')[linha - 1] || '';
|
|
55
|
+
const fixedLine = previewCorrecao.split('\n')[linha - 1] || '';
|
|
56
|
+
const sugestao = [fixResultado.description, '', `[CHAVE-INGLESA] Correção sugerida:`, `[ERRO] Antes: ${originalLine.trim()}`, `[OK] Depois: ${fixedLine.trim()}`, '', `Confiança: ${fixResultado.confidence}%`, `Categoria: ${fixResultado.category}`, `ID do Fix: ${fixResultado.id}`].join('\n');
|
|
57
|
+
const nivel = mapearCategoriaNivel(fixResultado.category);
|
|
58
|
+
const ocorrencia = criarOcorrencia({
|
|
59
|
+
tipo: 'auto-fix-disponivel',
|
|
60
|
+
nivel,
|
|
61
|
+
mensagem: fixResultado.title,
|
|
62
|
+
relPath,
|
|
63
|
+
linha
|
|
64
|
+
});
|
|
65
|
+
const ocorrenciaGenerica = ocorrencia;
|
|
66
|
+
ocorrenciaGenerica.sugestao = sugestao;
|
|
67
|
+
ocorrenciaGenerica.quickFixId = fixResultado.id;
|
|
68
|
+
ocorrenciaGenerica.confidence = fixResultado.confidence;
|
|
69
|
+
ocorrenciaGenerica.category = fixResultado.category;
|
|
70
|
+
ocorrenciaGenerica.matchIndex = match.index;
|
|
71
|
+
ocorrenciaGenerica.matchLength = match[0].length;
|
|
72
|
+
ocorrencias.push(ocorrencia);
|
|
73
|
+
}
|
|
71
74
|
// ─── analistaPontuacao ────────────────────────────────────────
|
|
72
75
|
export const analistaPontuacao = {
|
|
73
76
|
nome: 'pontuacao-fix',
|
|
@@ -31,41 +31,7 @@ export async function corrigirEstrutura(mapa, fileEntries, baseDir = process.cwd
|
|
|
31
31
|
log.info(CorretorEstruturaExtraMensagens.simular.replace('{arquivo}', arquivo).replace('{destino}', path.relative(baseDir, destino)));
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
await fs.mkdir(path.dirname(destino), {
|
|
36
|
-
recursive: true
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
const msg = err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err);
|
|
41
|
-
logAuto.corretorErroCriarDiretorio(destino, msg);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
try {
|
|
45
|
-
// Usa flag 'wx' para escrita exclusiva - falha se o arquivo já existir,
|
|
46
|
-
// eliminando a condição de corrida TOCTOU entre stat e write
|
|
47
|
-
const conteudo = await fs.readFile(origem, 'utf-8');
|
|
48
|
-
const { novoConteudo } = reescreverImports(conteudo, path.posix.normalize(arquivo.replace(/\\/g, '/')), path.posix.normalize(path.relative(baseDir, destino).replace(/\\/g, '/')));
|
|
49
|
-
// Registra o move no mapa de reversão
|
|
50
|
-
await mapaReversao.registrarMove(arquivo, path.relative(baseDir, destino), entry.motivo ?? 'Reorganização estrutural', conteudo, novoConteudo, true);
|
|
51
|
-
try {
|
|
52
|
-
await fs.writeFile(destino, novoConteudo, { encoding: 'utf-8', flag: 'wx' });
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
const code = err.code;
|
|
56
|
-
if (code === 'EEXIST') {
|
|
57
|
-
logAuto.corretorDestinoExiste(arquivo, path.relative(baseDir, destino));
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
throw err;
|
|
61
|
-
}
|
|
62
|
-
await fs.unlink(origem);
|
|
63
|
-
log.sucesso(CorretorEstruturaExtraMensagens.movido.replace('{arquivo}', arquivo).replace('{destino}', path.relative(baseDir, destino)));
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
const msg = err && typeof err === 'object' && 'message' in err ? String((err).message) : String(err);
|
|
67
|
-
logAuto.corretorErroMover(arquivo, msg);
|
|
68
|
-
}
|
|
34
|
+
await moverArquivoComReversao(entry, origem, destino, baseDir, arquivo);
|
|
69
35
|
})));
|
|
70
36
|
for (const pluginRel of PLUGINS) {
|
|
71
37
|
try {
|
|
@@ -108,3 +74,37 @@ export async function corrigirEstrutura(mapa, fileEntries, baseDir = process.cwd
|
|
|
108
74
|
}
|
|
109
75
|
}
|
|
110
76
|
}
|
|
77
|
+
async function moverArquivoComReversao(entry, origem, destino, baseDir, arquivo) {
|
|
78
|
+
try {
|
|
79
|
+
await fs.mkdir(path.dirname(destino), {
|
|
80
|
+
recursive: true
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const msg = err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err);
|
|
85
|
+
logAuto.corretorErroCriarDiretorio(destino, msg);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const conteudo = await fs.readFile(origem, 'utf-8');
|
|
90
|
+
const { novoConteudo } = reescreverImports(conteudo, path.posix.normalize(arquivo.replace(/\\/g, '/')), path.posix.normalize(path.relative(baseDir, destino).replace(/\\/g, '/')));
|
|
91
|
+
await mapaReversao.registrarMove(arquivo, path.relative(baseDir, destino), entry.motivo ?? 'Reorganização estrutural', conteudo, novoConteudo, true);
|
|
92
|
+
try {
|
|
93
|
+
await fs.writeFile(destino, novoConteudo, { encoding: 'utf-8', flag: 'wx' });
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
const code = err.code;
|
|
97
|
+
if (code === 'EEXIST') {
|
|
98
|
+
logAuto.corretorDestinoExiste(arquivo, path.relative(baseDir, destino));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
await fs.unlink(origem);
|
|
104
|
+
log.sucesso(CorretorEstruturaExtraMensagens.movido.replace('{arquivo}', arquivo).replace('{destino}', path.relative(baseDir, destino)));
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
const msg = err && typeof err === 'object' && 'message' in err ? String((err).message) : String(err);
|
|
108
|
+
logAuto.corretorErroMover(arquivo, msg);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -13,6 +13,15 @@ export function aplicarFixAliasImports(fileCaminho, content) {
|
|
|
13
13
|
content: out
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
async function processTypeFileForAlias(fileCaminho) {
|
|
17
|
+
const src = await fs.readFile(fileCaminho, 'utf8');
|
|
18
|
+
const { changed: wasChanged, content } = aplicarFixAliasImports(fileCaminho, src);
|
|
19
|
+
if (wasChanged) {
|
|
20
|
+
await fs.writeFile(fileCaminho, content, 'utf8');
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
16
25
|
export async function scanAndApplyFix(root) {
|
|
17
26
|
let changed = 0;
|
|
18
27
|
async function walk(dir) {
|
|
@@ -26,12 +35,7 @@ export async function scanAndApplyFix(root) {
|
|
|
26
35
|
await walk(fileCaminho);
|
|
27
36
|
}
|
|
28
37
|
else if (entry.isFile() && fileCaminho.endsWith('.ts')) {
|
|
29
|
-
|
|
30
|
-
const { changed: wasChanged, content } = aplicarFixAliasImports(fileCaminho, src);
|
|
31
|
-
if (wasChanged) {
|
|
32
|
-
await fs.writeFile(fileCaminho, content, 'utf8');
|
|
33
|
-
changed++;
|
|
34
|
-
}
|
|
38
|
+
changed += await processTypeFileForAlias(fileCaminho);
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
}
|
|
@@ -48,33 +48,33 @@ export function fixFences(content) {
|
|
|
48
48
|
}
|
|
49
49
|
return out.join('\n');
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (/^(node_modules|dist|coverage|pre-public|preview-mahoraga|\.git)$/i.test(entry.name)) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
out.push(...(await listMarkdown(fullCaminho)));
|
|
66
|
-
}
|
|
67
|
-
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {
|
|
68
|
-
out.push(fullCaminho);
|
|
51
|
+
async function listMarkdownFiles(dir) {
|
|
52
|
+
const out = [];
|
|
53
|
+
try {
|
|
54
|
+
const entries = await fs.readdir(dir, {
|
|
55
|
+
withFileTypes: true
|
|
56
|
+
});
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
const fullCaminho = path.join(dir, entry.name);
|
|
59
|
+
if (entry.isDirectory()) {
|
|
60
|
+
if (/^(node_modules|dist|coverage|pre-public|preview-mahoraga|\.git)$/i.test(entry.name)) {
|
|
61
|
+
continue;
|
|
69
62
|
}
|
|
63
|
+
out.push(...(await listMarkdownFiles(fullCaminho)));
|
|
64
|
+
}
|
|
65
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {
|
|
66
|
+
out.push(fullCaminho);
|
|
70
67
|
}
|
|
71
|
-
return out;
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return out;
|
|
75
68
|
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return out;
|
|
76
73
|
}
|
|
77
|
-
|
|
74
|
+
}
|
|
75
|
+
export async function scanAndApplyFixMdFences(root) {
|
|
76
|
+
let changed = 0;
|
|
77
|
+
const files = await listMarkdownFiles(root);
|
|
78
78
|
for (const fileCaminho of files) {
|
|
79
79
|
const rel = path.relative(root, fileCaminho).replace(/\\/g, '/');
|
|
80
80
|
if (rel.startsWith('pre-public/') || rel.includes('/legado/')) {
|
|
@@ -172,57 +172,8 @@ export class GerenciadorMapaReversao {
|
|
|
172
172
|
recursive: true
|
|
173
173
|
});
|
|
174
174
|
// Move o arquivo de volta
|
|
175
|
-
if (move
|
|
176
|
-
|
|
177
|
-
// eliminando a condição de corrida TOCTOU entre stat e write
|
|
178
|
-
try {
|
|
179
|
-
await fs.writeFile(origemCaminho, move.conteudoOriginal, {
|
|
180
|
-
encoding: 'utf-8',
|
|
181
|
-
flag: 'wx'
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
catch (err) {
|
|
185
|
-
const code = err.code;
|
|
186
|
-
if (code === 'EEXIST') {
|
|
187
|
-
logAuto.mapaReversaoArquivoExisteOrigem(move.origem);
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
if (err.code && err.code !== 'ENOENT') {
|
|
191
|
-
logAuto.mapaReversaoErroReverter(err.message);
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
throw err;
|
|
195
|
-
}
|
|
196
|
-
try {
|
|
197
|
-
await fs.unlink(destinoCaminho);
|
|
198
|
-
}
|
|
199
|
-
catch (err) {
|
|
200
|
-
if (err.code === 'ENOENT') {
|
|
201
|
-
logAuto.mapaReversaoArquivoDestinoNaoEncontrado(move.destino);
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
throw err;
|
|
205
|
-
}
|
|
206
|
-
log.sucesso(MapaReversaoExtraMensagens.arquivoRevertidoConteudo.replace('{destino}', move.destino).replace('{origem}', move.origem));
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
// Usa rename atômico - se destino não existir, falha com ENOENT
|
|
210
|
-
try {
|
|
211
|
-
await fs.rename(destinoCaminho, origemCaminho);
|
|
212
|
-
}
|
|
213
|
-
catch (err) {
|
|
214
|
-
const code = err.code;
|
|
215
|
-
if (code === 'ENOENT') {
|
|
216
|
-
logAuto.mapaReversaoArquivoDestinoNaoEncontrado(move.destino);
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
if (code === 'EEXIST') {
|
|
220
|
-
logAuto.mapaReversaoArquivoExisteOrigem(move.origem);
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
throw err;
|
|
224
|
-
}
|
|
225
|
-
log.sucesso(MapaReversaoExtraMensagens.arquivoRevertido.replace('{destino}', move.destino).replace('{origem}', move.origem));
|
|
175
|
+
if (!await this.reverterComConteudo(move, origemCaminho, destinoCaminho)) {
|
|
176
|
+
return false;
|
|
226
177
|
}
|
|
227
178
|
// Remove o move do mapa
|
|
228
179
|
await this.removerMove(id);
|
|
@@ -295,6 +246,58 @@ export class GerenciadorMapaReversao {
|
|
|
295
246
|
logAuto.mapaReversaoErroSalvar(err.message);
|
|
296
247
|
}
|
|
297
248
|
}
|
|
249
|
+
async reverterComConteudo(move, origemCaminho, destinoCaminho) {
|
|
250
|
+
if (move.importsReescritos && move.conteudoOriginal) {
|
|
251
|
+
try {
|
|
252
|
+
await fs.writeFile(origemCaminho, move.conteudoOriginal, {
|
|
253
|
+
encoding: 'utf-8',
|
|
254
|
+
flag: 'wx'
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
const code = err.code;
|
|
259
|
+
if (code === 'EEXIST') {
|
|
260
|
+
logAuto.mapaReversaoArquivoExisteOrigem(move.origem);
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
if (err.code && err.code !== 'ENOENT') {
|
|
264
|
+
logAuto.mapaReversaoErroReverter(err.message);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
throw err;
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
await fs.unlink(destinoCaminho);
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
if (err.code === 'ENOENT') {
|
|
274
|
+
logAuto.mapaReversaoArquivoDestinoNaoEncontrado(move.destino);
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
log.sucesso(MapaReversaoExtraMensagens.arquivoRevertidoConteudo.replace('{destino}', move.destino).replace('{origem}', move.origem));
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
try {
|
|
283
|
+
await fs.rename(destinoCaminho, origemCaminho);
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
const code = err.code;
|
|
287
|
+
if (code === 'ENOENT') {
|
|
288
|
+
logAuto.mapaReversaoArquivoDestinoNaoEncontrado(move.destino);
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
if (code === 'EEXIST') {
|
|
292
|
+
logAuto.mapaReversaoArquivoExisteOrigem(move.origem);
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
throw err;
|
|
296
|
+
}
|
|
297
|
+
log.sucesso(MapaReversaoExtraMensagens.arquivoRevertido.replace('{destino}', move.destino).replace('{origem}', move.origem));
|
|
298
|
+
}
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
298
301
|
}
|
|
299
302
|
// Instância global
|
|
300
303
|
export const mapaReversao = new GerenciadorMapaReversao();
|
|
@@ -91,21 +91,24 @@ function moverArquivosSimulado(lista, base) {
|
|
|
91
91
|
async function moverArquivos(lista, base, historico) {
|
|
92
92
|
const limitar = pLimit(CONCORRENCIA);
|
|
93
93
|
await Promise.all(lista.map(pend => limitar(async () => {
|
|
94
|
-
|
|
95
|
-
const dest = path.join(base, DIR_ABANDONADOS, pend.arquivo);
|
|
96
|
-
try {
|
|
97
|
-
const fs = await import('node:fs');
|
|
98
|
-
await ensureDir(dest);
|
|
99
|
-
await fs.promises.rename(src, dest);
|
|
100
|
-
historico.push({
|
|
101
|
-
arquivo: pend.arquivo,
|
|
102
|
-
movidoEm: new Date().toISOString(),
|
|
103
|
-
motivo: pend.motivo
|
|
104
|
-
});
|
|
105
|
-
logAuto.podaArquivoMovido(pend.arquivo);
|
|
106
|
-
}
|
|
107
|
-
catch (err) {
|
|
108
|
-
log.erro(`[ERRO] Falha ao mover ${pend.arquivo}: ${typeof err === 'object' && err && 'message' in err ? err.message : String(err)}`);
|
|
109
|
-
}
|
|
94
|
+
await moverArquivoIndividual(pend, base, historico);
|
|
110
95
|
})));
|
|
111
96
|
}
|
|
97
|
+
async function moverArquivoIndividual(pend, base, historico) {
|
|
98
|
+
const src = path.join(base, pend.arquivo);
|
|
99
|
+
const dest = path.join(base, DIR_ABANDONADOS, pend.arquivo);
|
|
100
|
+
try {
|
|
101
|
+
const fs = await import('node:fs');
|
|
102
|
+
await ensureDir(dest);
|
|
103
|
+
await fs.promises.rename(src, dest);
|
|
104
|
+
historico.push({
|
|
105
|
+
arquivo: pend.arquivo,
|
|
106
|
+
movidoEm: new Date().toISOString(),
|
|
107
|
+
motivo: pend.motivo
|
|
108
|
+
});
|
|
109
|
+
logAuto.podaArquivoMovido(pend.arquivo);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
log.erro(`[ERRO] Falha ao mover ${pend.arquivo}: ${typeof err === 'object' && err && 'message' in err ? err.message : String(err)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -10,9 +10,10 @@ import { analyzeTypeUsage } from '../type-safety/type-analyzer.js';
|
|
|
10
10
|
import { createTypeDefinition } from '../type-safety/type-creator.js';
|
|
11
11
|
import { validateTypeReplacement } from '../type-safety/type-validator.js';
|
|
12
12
|
const { MENSAGENS_CORRECAO_TIPOS } = getMessages();
|
|
13
|
+
const CONFIANCA_MEDIA = 60;
|
|
13
14
|
const CONFIANCA_NIVEIS = {
|
|
14
15
|
HIGH: 85,
|
|
15
|
-
MEDIUM:
|
|
16
|
+
MEDIUM: CONFIANCA_MEDIA,
|
|
16
17
|
DEFAULT: 70
|
|
17
18
|
};
|
|
18
19
|
export const fixAnyToProperTipo = {
|
|
@@ -62,66 +63,7 @@ export async function fixAnyToProperTypeAsync(match, fullCode, fileCaminho, ast)
|
|
|
62
63
|
const typeAnalise = analyzeTypeUsage(match, fullCode, fileCaminho, ast);
|
|
63
64
|
// 2. Estratégia baseada em confiança
|
|
64
65
|
if (typeAnalise.confidence >= CONFIANCA_NIVEIS.HIGH) {
|
|
65
|
-
|
|
66
|
-
if (typeAnalise.isSimpleType) {
|
|
67
|
-
// Tipo primitivo: substituir diretamente
|
|
68
|
-
const fixedCodigo = fullCode.replace(match[0], `: ${typeAnalise.inferredTipo}`);
|
|
69
|
-
// Validar resultado
|
|
70
|
-
const validation = await validateTypeReplacement(fullCode, fixedCodigo, typeAnalise);
|
|
71
|
-
if (!validation.isCompatible) {
|
|
72
|
-
return {
|
|
73
|
-
code: fullCode,
|
|
74
|
-
applied: false,
|
|
75
|
-
reason: `Validação falhou: ${validation.errors.join(', ')}`,
|
|
76
|
-
warnings: validation.warnings.map(dimensaoLargura => ({
|
|
77
|
-
type: 'unsafe-type',
|
|
78
|
-
message: dimensaoLargura,
|
|
79
|
-
suggestion: 'Revise manualmente'
|
|
80
|
-
}))
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
code: fixedCodigo,
|
|
85
|
-
applied: true,
|
|
86
|
-
warnings: validation.warnings.map(dimensaoLargura => ({
|
|
87
|
-
type: 'type-suggestion',
|
|
88
|
-
message: dimensaoLargura,
|
|
89
|
-
suggestion: MENSAGENS_CORRECAO_TIPOS.validacao.revisar
|
|
90
|
-
}))
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
// Tipo complexo: criar interface
|
|
95
|
-
const typeCaminho = await createTypeDefinition(typeAnalise, fileCaminho);
|
|
96
|
-
const importStatement = `import type { ${typeAnalise.typeName} } from '${typeCaminho}';\n`;
|
|
97
|
-
// Adicionar import no topo e substituir any
|
|
98
|
-
const lines = fullCode.split('\n');
|
|
99
|
-
const importIndex = findImportInsertionPoint(lines);
|
|
100
|
-
lines.splice(importIndex, 0, importStatement);
|
|
101
|
-
let fixedCodigo = lines.join('\n');
|
|
102
|
-
fixedCodigo = fixedCodigo.replace(match[0], `: ${typeAnalise.typeName}`);
|
|
103
|
-
// Validar resultado
|
|
104
|
-
const validation = await validateTypeReplacement(fullCode, fixedCodigo, typeAnalise);
|
|
105
|
-
if (!validation.isCompatible) {
|
|
106
|
-
return {
|
|
107
|
-
code: fullCode,
|
|
108
|
-
applied: false,
|
|
109
|
-
reason: `Validação falhou: ${validation.errors.join(', ')}`
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
return {
|
|
113
|
-
code: fixedCodigo,
|
|
114
|
-
applied: true,
|
|
115
|
-
additionalChanges: [{
|
|
116
|
-
type: 'add-import',
|
|
117
|
-
content: importStatement
|
|
118
|
-
}, {
|
|
119
|
-
type: 'create-type-file',
|
|
120
|
-
content: typeAnalise.typeDefinition,
|
|
121
|
-
path: buildTypesRelPathPosix(typeAnalise.suggestedPath)
|
|
122
|
-
}]
|
|
123
|
-
};
|
|
124
|
-
}
|
|
66
|
+
return await applyHighConfidenceAnyFix(match, fullCode, fileCaminho, typeAnalise);
|
|
125
67
|
}
|
|
126
68
|
else if (typeAnalise.confidence >= CONFIANCA_NIVEIS.MEDIUM) {
|
|
127
69
|
// MÉDIA CONFIANÇA: Sugerir mas não aplicar
|
|
@@ -162,6 +104,60 @@ export async function fixAnyToProperTypeAsync(match, fullCode, fileCaminho, ast)
|
|
|
162
104
|
};
|
|
163
105
|
}
|
|
164
106
|
}
|
|
107
|
+
async function applyHighConfidenceAnyFix(match, fullCode, fileCaminho, typeAnalise) {
|
|
108
|
+
if (typeAnalise.isSimpleType) {
|
|
109
|
+
const fixedCodigo = fullCode.replace(match[0], `: ${typeAnalise.inferredTipo}`);
|
|
110
|
+
const validation = await validateTypeReplacement(fullCode, fixedCodigo, typeAnalise);
|
|
111
|
+
if (!validation.isCompatible) {
|
|
112
|
+
return {
|
|
113
|
+
code: fullCode,
|
|
114
|
+
applied: false,
|
|
115
|
+
reason: `Validação falhou: ${validation.errors.join(', ')}`,
|
|
116
|
+
warnings: validation.warnings.map(dimensaoLargura => ({
|
|
117
|
+
type: 'unsafe-type',
|
|
118
|
+
message: dimensaoLargura,
|
|
119
|
+
suggestion: 'Revise manualmente'
|
|
120
|
+
}))
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
code: fixedCodigo,
|
|
125
|
+
applied: true,
|
|
126
|
+
warnings: validation.warnings.map(dimensaoLargura => ({
|
|
127
|
+
type: 'type-suggestion',
|
|
128
|
+
message: dimensaoLargura,
|
|
129
|
+
suggestion: MENSAGENS_CORRECAO_TIPOS.validacao.revisar
|
|
130
|
+
}))
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const typeCaminho = await createTypeDefinition(typeAnalise, fileCaminho);
|
|
134
|
+
const importStatement = `import type { ${typeAnalise.typeName} } from '${typeCaminho}';\n`;
|
|
135
|
+
const lines = fullCode.split('\n');
|
|
136
|
+
const importIndex = findImportInsertionPoint(lines);
|
|
137
|
+
lines.splice(importIndex, 0, importStatement);
|
|
138
|
+
let fixedCodigo = lines.join('\n');
|
|
139
|
+
fixedCodigo = fixedCodigo.replace(match[0], `: ${typeAnalise.typeName}`);
|
|
140
|
+
const validation = await validateTypeReplacement(fullCode, fixedCodigo, typeAnalise);
|
|
141
|
+
if (!validation.isCompatible) {
|
|
142
|
+
return {
|
|
143
|
+
code: fullCode,
|
|
144
|
+
applied: false,
|
|
145
|
+
reason: `Validação falhou: ${validation.errors.join(', ')}`
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
code: fixedCodigo,
|
|
150
|
+
applied: true,
|
|
151
|
+
additionalChanges: [{
|
|
152
|
+
type: 'add-import',
|
|
153
|
+
content: importStatement
|
|
154
|
+
}, {
|
|
155
|
+
type: 'create-type-file',
|
|
156
|
+
content: typeAnalise.typeDefinition,
|
|
157
|
+
path: buildTypesRelPathPosix(typeAnalise.suggestedPath)
|
|
158
|
+
}]
|
|
159
|
+
};
|
|
160
|
+
}
|
|
165
161
|
/**
|
|
166
162
|
* Encontra ponto de inserção para import
|
|
167
163
|
*/
|
|
@@ -51,36 +51,7 @@ export async function fixUnknownToSpecificTypeAsync(match, fullCode, fileCaminho
|
|
|
51
51
|
const typeAnalise = await analyzeUnknownUsage(match, fullCode, fileCaminho, ast);
|
|
52
52
|
// 2. Estratégia mais conservadora (requer >= 90% confiança)
|
|
53
53
|
if (typeAnalise.confidence >= 90) {
|
|
54
|
-
|
|
55
|
-
const typeCaminho = await createTypeDefinition(typeAnalise, fileCaminho);
|
|
56
|
-
const importStatement = `import type { ${typeAnalise.typeName} } from '${typeCaminho}';\n`;
|
|
57
|
-
// Adicionar import e substituir unknown
|
|
58
|
-
const lines = fullCode.split('\n');
|
|
59
|
-
const importIndex = findImportInsertionPoint(lines);
|
|
60
|
-
lines.splice(importIndex, 0, importStatement);
|
|
61
|
-
let fixedCodigo = lines.join('\n');
|
|
62
|
-
fixedCodigo = fixedCodigo.replace(match[0], `: ${typeAnalise.typeName}`);
|
|
63
|
-
// Validar
|
|
64
|
-
const validation = await validateTypeReplacement(fullCode, fixedCodigo, typeAnalise);
|
|
65
|
-
if (!validation.isCompatible) {
|
|
66
|
-
return {
|
|
67
|
-
code: fullCode,
|
|
68
|
-
applied: false,
|
|
69
|
-
reason: `Validação falhou: ${validation.errors.join(', ')}`
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
code: fixedCodigo,
|
|
74
|
-
applied: true,
|
|
75
|
-
additionalChanges: [{
|
|
76
|
-
type: 'add-import',
|
|
77
|
-
content: importStatement
|
|
78
|
-
}, {
|
|
79
|
-
type: 'create-type-file',
|
|
80
|
-
content: typeAnalise.typeDefinition,
|
|
81
|
-
path: buildTypesRelPathPosix(typeAnalise.suggestedPath)
|
|
82
|
-
}]
|
|
83
|
-
};
|
|
54
|
+
return await applyHighConfidenceUnknownFix(match, fullCode, fileCaminho, typeAnalise);
|
|
84
55
|
}
|
|
85
56
|
else if (typeAnalise.confidence >= 70) {
|
|
86
57
|
// MÉDIA CONFIANÇA: Sugerir tipo
|
|
@@ -120,6 +91,35 @@ export async function fixUnknownToSpecificTypeAsync(match, fullCode, fileCaminho
|
|
|
120
91
|
};
|
|
121
92
|
}
|
|
122
93
|
}
|
|
94
|
+
async function applyHighConfidenceUnknownFix(match, fullCode, fileCaminho, typeAnalise) {
|
|
95
|
+
const typeCaminho = await createTypeDefinition(typeAnalise, fileCaminho);
|
|
96
|
+
const importStatement = `import type { ${typeAnalise.typeName} } from '${typeCaminho}';\n`;
|
|
97
|
+
const lines = fullCode.split('\n');
|
|
98
|
+
const importIndex = findImportInsertionPoint(lines);
|
|
99
|
+
lines.splice(importIndex, 0, importStatement);
|
|
100
|
+
let fixedCodigo = lines.join('\n');
|
|
101
|
+
fixedCodigo = fixedCodigo.replace(match[0], `: ${typeAnalise.typeName}`);
|
|
102
|
+
const validation = await validateTypeReplacement(fullCode, fixedCodigo, typeAnalise);
|
|
103
|
+
if (!validation.isCompatible) {
|
|
104
|
+
return {
|
|
105
|
+
code: fullCode,
|
|
106
|
+
applied: false,
|
|
107
|
+
reason: `Validação falhou: ${validation.errors.join(', ')}`
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
code: fixedCodigo,
|
|
112
|
+
applied: true,
|
|
113
|
+
additionalChanges: [{
|
|
114
|
+
type: 'add-import',
|
|
115
|
+
content: importStatement
|
|
116
|
+
}, {
|
|
117
|
+
type: 'create-type-file',
|
|
118
|
+
content: typeAnalise.typeDefinition,
|
|
119
|
+
path: buildTypesRelPathPosix(typeAnalise.suggestedPath)
|
|
120
|
+
}]
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
123
|
/**
|
|
124
124
|
* Encontra ponto de inserção para import
|
|
125
125
|
*/
|
|
@@ -28,6 +28,15 @@ function resolverImportRelativo(arquivoRel, importSpec) {
|
|
|
28
28
|
const dir = path.posix.dirname(normalizarRel(arquivoRel));
|
|
29
29
|
return path.posix.normalize(path.posix.join(dir, importSpec));
|
|
30
30
|
}
|
|
31
|
+
function resolverImportSpec(spec, rel) {
|
|
32
|
+
if (spec.startsWith('@/')) {
|
|
33
|
+
return semExt(normalizarRel(`src/${spec.slice(2)}`));
|
|
34
|
+
}
|
|
35
|
+
if (spec.startsWith('@')) {
|
|
36
|
+
return semExt(normalizarRel(`src/${spec.slice(1)}`)).replace(/^src\//, '');
|
|
37
|
+
}
|
|
38
|
+
return semExt(resolverImportRelativo(rel, spec));
|
|
39
|
+
}
|
|
31
40
|
function criarMapaMovimentos(mapa, _baseDir) {
|
|
32
41
|
const movimentos = new Map();
|
|
33
42
|
for (const entry of mapa) {
|
|
@@ -231,16 +240,7 @@ async function atualizarImportsGlobais(srcDir, movimentos) {
|
|
|
231
240
|
if (!isRelative && !isAlias) {
|
|
232
241
|
continue;
|
|
233
242
|
}
|
|
234
|
-
|
|
235
|
-
if (spec.startsWith('@/')) {
|
|
236
|
-
resolved = semExt(normalizarRel(`src/${spec.slice(2)}`));
|
|
237
|
-
}
|
|
238
|
-
else if (spec.startsWith('@')) {
|
|
239
|
-
resolved = semExt(normalizarRel(`src/${spec.slice(1)}`)).replace(/^src\//, '');
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
resolved = semExt(resolverImportRelativo(rel, spec));
|
|
243
|
-
}
|
|
243
|
+
const resolved = resolverImportSpec(spec, rel);
|
|
244
244
|
const moveDestino = movimentos.get(resolved);
|
|
245
245
|
if (!moveDestino) {
|
|
246
246
|
continue;
|