@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.
Files changed (105) hide show
  1. package/README.md +0 -34
  2. package/dist/analysts/architects/analyst-structure.js +19 -19
  3. package/dist/analysts/architects/archetypes-custom.js +8 -6
  4. package/dist/analysts/architects/detector-archetypes.js +30 -27
  5. package/dist/analysts/architects/signals-project-advanced.js +24 -26
  6. package/dist/analysts/architects/signals-project.js +1 -1
  7. package/dist/analysts/architects/strategist-structure.js +47 -66
  8. package/dist/analysts/azure-pipelines/analysts/analyst-azure.js +21 -14
  9. package/dist/analysts/azure-pipelines/corrections/correction-azure.js +22 -19
  10. package/dist/analysts/azure-pipelines/detectors/detector-azure-performance.js +21 -18
  11. package/dist/analysts/azure-pipelines/detectors/detector-azure-security.js +25 -20
  12. package/dist/analysts/azure-pipelines/detectors/detector-azure-structure.js +39 -37
  13. package/dist/analysts/azure-pipelines/scorers/scorer-azure.js +10 -7
  14. package/dist/analysts/circleci/analysts/analyst-circleci.js +23 -15
  15. package/dist/analysts/circleci/corrections/correction-circleci.js +22 -20
  16. package/dist/analysts/circleci/detectors/detector-circleci-performance.js +23 -19
  17. package/dist/analysts/circleci/detectors/detector-circleci-security.js +78 -82
  18. package/dist/analysts/circleci/detectors/detector-circleci-structure.js +20 -17
  19. package/dist/analysts/converters/engines/converter-gha-to-gitlab.js +17 -15
  20. package/dist/analysts/corrections/analyst-quick-fixes.js +25 -28
  21. package/dist/analysts/corrections/analyst-scoring.js +24 -21
  22. package/dist/analysts/corrections/corrector-structure.js +35 -35
  23. package/dist/analysts/corrections/fix-alias-imports.js +10 -6
  24. package/dist/analysts/corrections/fix-md-fences.js +23 -23
  25. package/dist/analysts/corrections/map-reversion.js +54 -51
  26. package/dist/analysts/corrections/pruning.js +19 -16
  27. package/dist/analysts/corrections/quick-fixes/fix-any-to-proper-type.js +57 -61
  28. package/dist/analysts/corrections/quick-fixes/fix-unknown-to-specific-type.js +30 -30
  29. package/dist/analysts/corrections/reorganize-barrels.js +10 -10
  30. package/dist/analysts/corrections/scoring-shared.js +19 -18
  31. package/dist/analysts/corrections/type-safety/context-analyzer.js +15 -10
  32. package/dist/analysts/corrections/type-safety/type-validator.js +2 -1
  33. package/dist/analysts/corrections/type-safety/usage-analyzer.js +36 -39
  34. package/dist/analysts/css/analysts/analyst-css.js +16 -15
  35. package/dist/analysts/css/corrections/correction-css.js +19 -11
  36. package/dist/analysts/css/detectors/detector-css-best-practices.js +129 -118
  37. package/dist/analysts/css/scorers/scorer-css.js +23 -18
  38. package/dist/analysts/css-in-js/analysts/analyst-css-in-js.js +24 -17
  39. package/dist/analysts/css-in-js/corrections/correction-css-in-js.js +31 -16
  40. package/dist/analysts/css-in-js/detectors/detector-css-in-js-best-practices.js +20 -15
  41. package/dist/analysts/css-in-js/scorers/scorer-css-in-js.js +79 -54
  42. package/dist/analysts/css-in-js/shared.js +7 -0
  43. package/dist/analysts/detectors/detector-architecture.js +89 -83
  44. package/dist/analysts/detectors/detector-bugs-ml.js +21 -19
  45. package/dist/analysts/detectors/detector-code-fragile.js +30 -26
  46. package/dist/analysts/detectors/detector-duplications.js +21 -18
  47. package/dist/analysts/detectors/detector-monorepo.js +41 -36
  48. package/dist/analysts/detectors/detector-performance.js +22 -16
  49. package/dist/analysts/detectors/detector-recommendation-architecture.js +39 -35
  50. package/dist/analysts/detectors/detector-security.js +43 -42
  51. package/dist/analysts/detectors/detector-structure.js +29 -26
  52. package/dist/analysts/js-ts/detectors/detector-anti-patterns-async.js +4 -1
  53. package/dist/analysts/js-ts/detectors/detector-constructions-syntactic.js +10 -16
  54. package/dist/analysts/plugins/detector-documentation.js +1 -0
  55. package/dist/analysts/react/analysts/analyst-react-hooks.js +4 -2
  56. package/dist/analysts/react/analysts/analyst-react.js +1 -1
  57. package/dist/analysts/react/corrections/correction-react.js +2 -2
  58. package/dist/analysts/react/detectors/detector-react-best-practices.js +1 -1
  59. package/dist/analysts/registry/autodiscovery.js +2 -2
  60. package/dist/analysts/tailwind/corrections/correction-tailwind.js +0 -8
  61. package/dist/analysts/tailwind/scorers/scorer-tailwind.js +1 -2
  62. package/dist/cli/commands/command-analysts.js +3 -2
  63. package/dist/cli/commands/command-formatters.js +1 -1
  64. package/dist/cli/commands/command-github-actions.js +1 -1
  65. package/dist/cli/commands/command-guardian.js +1 -1
  66. package/dist/cli/commands/command-marketplace.js +4 -4
  67. package/dist/cli/diagnostic/filters.js +9 -9
  68. package/dist/core/config/chalk-safe.js +4 -4
  69. package/dist/core/config/config.js +5 -5
  70. package/dist/core/execution/analysis-cache.js +1 -1
  71. package/dist/core/execution/ast-cache.js +1 -3
  72. package/dist/core/execution/executor.js +2 -4
  73. package/dist/core/execution/scanner.js +1 -1
  74. package/dist/core/messages/en/analysts/report-circleci-messages.js +7 -7
  75. package/dist/core/messages/en/caretakers/caretaker-messages.js +1 -7
  76. package/dist/core/messages/ja/analysts/report-circleci-messages.js +7 -7
  77. package/dist/core/messages/ja/caretakers/caretaker-messages.js +1 -7
  78. package/dist/core/messages/pt/analysts/report-circleci-messages.js +7 -7
  79. package/dist/core/messages/pt/caretakers/caretaker-messages.js +1 -7
  80. package/dist/core/messages/zh/analysts/report-circleci-messages.js +7 -7
  81. package/dist/core/messages/zh/caretakers/caretaker-messages.js +1 -7
  82. package/dist/core/parsing/parser.js +2 -3
  83. package/dist/core/parsing/utils.js +1 -0
  84. package/dist/core/workers/worker-pool.js +0 -0
  85. package/dist/guardian/records.js +1 -0
  86. package/dist/guardian/sentinel.js +1 -0
  87. package/dist/guardian/watcher-hidden.js +1 -0
  88. package/dist/licenses/fs-utils.js +2 -1
  89. package/dist/licenses/header-options.js +1 -0
  90. package/dist/licenses/index.js +1 -1
  91. package/dist/reports/generator-report.js +3 -3
  92. package/dist/reports/report-patterns-usage.js +1 -1
  93. package/dist/shared/data-processing/fragment-report.js +1 -1
  94. package/dist/shared/formatters/engines/stylelint.js +40 -34
  95. package/dist/shared/formatters/formatters/markdown.js +1 -1
  96. package/dist/shared/helpers/framework-detector.js +5 -1
  97. package/dist/shared/persistence/persistence.js +13 -5
  98. package/dist/shared/plugins/core-plugin.js +3 -1
  99. package/dist/types/analysts/tailwind-correction.js +2 -0
  100. package/dist/types/index.js +3 -3
  101. package/dist/types/processing/filters.js +5 -4
  102. package/dist/vulnerabilities/npm-audit.js +1 -0
  103. package/dist/vulnerabilities/scanner.js +1 -1
  104. package/dist/vulnerabilities/vulnerabilities.js +1 -0
  105. 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
- const linha = calcularLinha(src, match.index, match);
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
- try {
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
- const src = await fs.readFile(fileCaminho, 'utf8');
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
- export async function scanAndApplyFixMdFences(root) {
52
- let changed = 0;
53
- async function listMarkdown(dir) {
54
- const out = [];
55
- try {
56
- const entries = await fs.readdir(dir, {
57
- withFileTypes: true
58
- });
59
- for (const entry of entries) {
60
- const fullCaminho = path.join(dir, entry.name);
61
- if (entry.isDirectory()) {
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
- const files = await listMarkdown(root);
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.importsReescritos && move.conteudoOriginal) {
176
- // Usa flag 'wx' para escrita exclusiva - falha se o arquivo já existir,
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
- const src = path.join(base, pend.arquivo);
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: 60,
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
- // ALTA CONFIANÇA: Aplicar tipo automaticamente
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
- // ALTA CONFIANÇA: Criar interface dedicada
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
- let resolved;
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;