@mocoto/mahoraga 0.14.1 → 0.14.2

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 (268) hide show
  1. package/dist/analysts/architects/analyst-structure.js +1 -1
  2. package/dist/analysts/architects/archetypes-custom.js +8 -13
  3. package/dist/analysts/architects/detector-archetypes.js +39 -35
  4. package/dist/analysts/architects/orchestrator-archetypes.js +3 -3
  5. package/dist/analysts/architects/signals-project-advanced.js +2 -2
  6. package/dist/analysts/architects/signals-project.js +1 -1
  7. package/dist/analysts/azure-pipelines/analysts/analyst-azure.js +20 -21
  8. package/dist/analysts/azure-pipelines/detectors/detector-azure-structure.js +0 -3
  9. package/dist/analysts/circleci/analysts/analyst-circleci.js +22 -24
  10. package/dist/analysts/circleci/detectors/detector-circleci-structure.js +4 -7
  11. package/dist/analysts/converters/convert-registry.js +1 -1
  12. package/dist/analysts/converters/index.js +1 -1
  13. package/dist/analysts/corrections/auto-fix-engine.js +1 -1
  14. package/dist/analysts/corrections/corrector-structure.js +8 -7
  15. package/dist/analysts/corrections/map-reversion.js +2 -2
  16. package/dist/analysts/corrections/reorganize-barrels.js +3 -3
  17. package/dist/analysts/corrections/rewrite-testes-aliases.js +23 -22
  18. package/dist/analysts/corrections/type-safety/type-analyzer.js +3 -3
  19. package/dist/analysts/corrections/type-safety/type-validator.js +2 -2
  20. package/dist/analysts/corrections/type-safety/usage-analyzer.js +3 -3
  21. package/dist/analysts/css/analysts/analyst-css.js +27 -28
  22. package/dist/analysts/css-in-js/detectors/detector-css-in-js-best-practices.js +8 -15
  23. package/dist/analysts/detectors/detector-architecture.js +2 -2
  24. package/dist/analysts/detectors/detector-bugs-ml.js +8 -8
  25. package/dist/analysts/detectors/detector-code-fragile.js +11 -10
  26. package/dist/analysts/detectors/detector-dependencies.js +5 -5
  27. package/dist/analysts/detectors/detector-duplications.js +5 -8
  28. package/dist/analysts/detectors/detector-monorepo.js +10 -9
  29. package/dist/analysts/detectors/detector-performance.js +2 -1
  30. package/dist/analysts/detectors/detector-recommendation-architecture.js +1 -1
  31. package/dist/analysts/detectors/detector-security.js +1 -1
  32. package/dist/analysts/detectors/detector-structure.js +3 -3
  33. package/dist/analysts/github-actions/analysts/analyst-github-actions.js +5 -8
  34. package/dist/analysts/github-actions/detectors/detector-workflow-accessibility.js +1 -9
  35. package/dist/analysts/github-actions/detectors/detector-workflow-structure.js +1 -4
  36. package/dist/analysts/github-actions/detectors/detector-workflow-trigger-unsafe.js +6 -5
  37. package/dist/analysts/gitlab-ci/analysts/analyst-gitlab-ci.js +2 -2
  38. package/dist/analysts/gitlab-ci/detectors/detector-gitlab-ci-structure.js +0 -3
  39. package/dist/analysts/go/analysts/analyst-best-practices.js +2 -2
  40. package/dist/analysts/go/analysts/analyst-concurrency.js +1 -1
  41. package/dist/analysts/go/analysts/analyst-security.js +1 -1
  42. package/dist/analysts/go/detectors/detector-conventions.js +1 -1
  43. package/dist/analysts/html/analysts/analyst-html.js +10 -12
  44. package/dist/analysts/html/detectors/detector-html.js +3 -3
  45. package/dist/analysts/js-ts/analysts/analyst-commands-cli.js +22 -22
  46. package/dist/analysts/js-ts/analysts/analyst-functions-long.js +5 -5
  47. package/dist/analysts/js-ts/analysts/analyst-patterns-usage.js +6 -2
  48. package/dist/analysts/js-ts/detectors/detector-anti-patterns-async.js +81 -9
  49. package/dist/analysts/js-ts/detectors/detector-constructions-syntactic.js +35 -6
  50. package/dist/analysts/js-ts/detectors/detector-context-smart.js +6 -6
  51. package/dist/analysts/js-ts/detectors/detector-leaks-memory.js +1 -1
  52. package/dist/analysts/js-ts/detectors/detector-types-unsafe.js +33 -2
  53. package/dist/analysts/php/analysts/analyst-php.js +3 -3
  54. package/dist/analysts/php/detectors/detector-php-best-practices.js +5 -5
  55. package/dist/analysts/php/detectors/detector-php-security.js +5 -5
  56. package/dist/analysts/php/scorers/scorer-php.js +2 -2
  57. package/dist/analysts/plugins/detector-documentation.js +5 -6
  58. package/dist/analysts/plugins/detector-markdown.js +7 -7
  59. package/dist/analysts/python/analysts/analyst-python.js +2 -5
  60. package/dist/analysts/react/analysts/analyst-react-hooks.js +63 -8
  61. package/dist/analysts/react/analysts/analyst-react.js +45 -1
  62. package/dist/analysts/react/corrections/correction-react.js +40 -0
  63. package/dist/analysts/react/detectors/detector-react-best-practices.js +4 -4
  64. package/dist/analysts/react/scorers/scorer-react.js +36 -1
  65. package/dist/analysts/rust/analysts/analyst-best-practices.js +42 -3
  66. package/dist/analysts/rust/analysts/analyst-memory.js +2 -2
  67. package/dist/analysts/rust/analysts/analyst-rust.js +52 -5
  68. package/dist/analysts/rust/analysts/analyst-security.js +29 -1
  69. package/dist/analysts/scorers/scorer.js +5 -5
  70. package/dist/analysts/shell/analysts/analyst-shell.js +81 -5
  71. package/dist/analysts/shell/corrections/correction-shell.js +34 -1
  72. package/dist/analysts/shell/detectors/detector-shell-security.js +88 -0
  73. package/dist/analysts/shell/scorers/scorer-shell.js +58 -1
  74. package/dist/analysts/strategists/operator-structure.js +5 -7
  75. package/dist/analysts/strategists/suggestions-contextuais.js +5 -2
  76. package/dist/analysts/svg/analysts/analyst-svg.js +1 -0
  77. package/dist/analysts/tailwind/analysts/analyst-tailwind.js +79 -55
  78. package/dist/analysts/tailwind/corrections/correction-tailwind.js +116 -9
  79. package/dist/analysts/tailwind/detectors/detector-tailwind-best-practices.js +122 -7
  80. package/dist/analysts/tailwind/scorers/scorer-tailwind.js +62 -10
  81. package/dist/analysts/xml/analysts/analyst-xml.js +2 -2
  82. package/dist/app/index.js +1 -0
  83. package/dist/bin/cli-bootstrap.js +6 -4
  84. package/dist/bin/index.js +6 -4
  85. package/dist/caretakers/scoring.js +1 -0
  86. package/dist/cli/commands/command-analysts.js +1 -1
  87. package/dist/cli/commands/command-azure.js +1 -1
  88. package/dist/cli/commands/command-circleci.js +1 -1
  89. package/dist/cli/commands/command-compliance.js +1 -1
  90. package/dist/cli/commands/command-diagnose.js +10 -13
  91. package/dist/cli/commands/command-fix-types.js +9 -32
  92. package/dist/cli/commands/command-formatters.js +2 -2
  93. package/dist/cli/commands/command-gitlab-ci.js +1 -1
  94. package/dist/cli/commands/command-guardian.js +1 -1
  95. package/dist/cli/commands/command-imports.js +6 -6
  96. package/dist/cli/commands/command-jenkins.js +1 -1
  97. package/dist/cli/commands/command-licenses.js +1 -1
  98. package/dist/cli/commands/command-marketplace.js +3 -3
  99. package/dist/cli/commands/command-names.js +3 -8
  100. package/dist/cli/commands/command-perf.js +7 -9
  101. package/dist/cli/commands/command-plugins.js +4 -4
  102. package/dist/cli/diagnostic/auto-fix.js +2 -2
  103. package/dist/cli/diagnostic/exporters/json-exporter.js +1 -1
  104. package/dist/cli/diagnostic/exporters/sharded-exporter.js +0 -3
  105. package/dist/cli/diagnostic/exporters/svg-optimization-exporter.js +1 -1
  106. package/dist/cli/diagnostic/handlers/archetype-handler.js +3 -6
  107. package/dist/cli/diagnostic/handlers/auto-fix-handler.js +4 -4
  108. package/dist/cli/diagnostic/handlers/guardian-handler.js +1 -1
  109. package/dist/cli/diagnostic/processing-diagnostic.js +31 -35
  110. package/dist/cli/diagnostic/processing-helpers.js +2 -2
  111. package/dist/cli/handlers/fix-types-exporter.js +1 -4
  112. package/dist/cli/helpers/display-frame.js +5 -5
  113. package/dist/core/config/auto/auto-fix-config.js +0 -6
  114. package/dist/core/config/chalk-safe.js +2 -2
  115. package/dist/core/config/config.js +6 -8
  116. package/dist/core/config/conventions.js +1 -1
  117. package/dist/core/config/security.js +2 -2
  118. package/dist/core/execution/analysis-cache.js +5 -8
  119. package/dist/core/execution/executor.js +8 -19
  120. package/dist/core/execution/inquisitor.js +24 -21
  121. package/dist/core/execution/results.js +1 -0
  122. package/dist/core/execution/scanner.js +3 -3
  123. package/dist/core/messages/en/analysts/analyst-github-actions-messages.js +1 -1
  124. package/dist/core/messages/en/analysts/analyst-patterns-usage-messages.js +1 -0
  125. package/dist/core/messages/en/analysts/analyst-shell-messages.js +15 -0
  126. package/dist/core/messages/en/analysts/detector-constructions-syntactic-messages.js +6 -0
  127. package/dist/core/messages/en/analysts/detector-js-ts-messages.js +27 -0
  128. package/dist/core/messages/en/analysts/detector-react-messages.js +8 -0
  129. package/dist/core/messages/en/analysts/detector-shell-messages.js +17 -0
  130. package/dist/core/messages/en/analysts/detector-tailwind-messages.js +3 -3
  131. package/dist/core/messages/en/core/plugin-messages.js +31 -3
  132. package/dist/core/messages/en/log/log.js +4 -4
  133. package/dist/core/messages/en/ui/filter-config.js +1 -5
  134. package/dist/core/messages/i18n-system.js +3 -3
  135. package/dist/core/messages/index.js +3 -3
  136. package/dist/core/messages/ja/analysts/analyst-github-actions-messages.js +1 -1
  137. package/dist/core/messages/ja/analysts/analyst-patterns-usage-messages.js +1 -0
  138. package/dist/core/messages/ja/analysts/analyst-shell-messages.js +15 -0
  139. package/dist/core/messages/ja/analysts/detector-constructions-syntactic-messages.js +6 -0
  140. package/dist/core/messages/ja/analysts/detector-js-ts-messages.js +27 -0
  141. package/dist/core/messages/ja/analysts/detector-react-messages.js +8 -0
  142. package/dist/core/messages/ja/analysts/detector-shell-messages.js +17 -0
  143. package/dist/core/messages/ja/analysts/detector-tailwind-messages.js +3 -3
  144. package/dist/core/messages/ja/core/plugin-messages.js +31 -3
  145. package/dist/core/messages/ja/log/log.js +4 -4
  146. package/dist/core/messages/ja/ui/filter-config.js +1 -1
  147. package/dist/core/messages/pt/analysts/analyst-github-actions-messages.js +1 -1
  148. package/dist/core/messages/pt/analysts/analyst-patterns-usage-messages.js +1 -0
  149. package/dist/core/messages/pt/analysts/analyst-shell-messages.js +15 -0
  150. package/dist/core/messages/pt/analysts/detector-constructions-syntactic-messages.js +6 -0
  151. package/dist/core/messages/pt/analysts/detector-js-ts-messages.js +27 -0
  152. package/dist/core/messages/pt/analysts/detector-react-messages.js +8 -0
  153. package/dist/core/messages/pt/analysts/detector-shell-messages.js +17 -0
  154. package/dist/core/messages/pt/analysts/detector-tailwind-messages.js +3 -3
  155. package/dist/core/messages/pt/core/plugin-messages.js +31 -3
  156. package/dist/core/messages/pt/log/log-engine.js +6 -6
  157. package/dist/core/messages/pt/log/log.js +3 -3
  158. package/dist/core/messages/pt/ui/filter-config.js +1 -1
  159. package/dist/core/messages/shared/icons.js +3 -3
  160. package/dist/core/messages/zh/analysts/analyst-github-actions-messages.js +1 -1
  161. package/dist/core/messages/zh/analysts/analyst-patterns-usage-messages.js +1 -0
  162. package/dist/core/messages/zh/analysts/analyst-shell-messages.js +15 -0
  163. package/dist/core/messages/zh/analysts/detector-constructions-syntactic-messages.js +6 -0
  164. package/dist/core/messages/zh/analysts/detector-js-ts-messages.js +27 -0
  165. package/dist/core/messages/zh/analysts/detector-react-messages.js +8 -0
  166. package/dist/core/messages/zh/analysts/detector-shell-messages.js +17 -0
  167. package/dist/core/messages/zh/analysts/detector-tailwind-messages.js +3 -3
  168. package/dist/core/messages/zh/core/plugin-messages.js +31 -3
  169. package/dist/core/messages/zh/log/log.js +3 -3
  170. package/dist/core/messages/zh/ui/filter-config.js +1 -5
  171. package/dist/core/parsing/filters.js +3 -3
  172. package/dist/core/parsing/langs/json.js +1 -1
  173. package/dist/core/parsing/langs/python.js +1 -1
  174. package/dist/core/parsing/langs/typescript.js +1 -1
  175. package/dist/core/parsing/parser.js +2 -2
  176. package/dist/core/registry/file-registry.js +3 -2
  177. package/dist/core/registry/paths.js +3 -3
  178. package/dist/core/reporting/default-reporter.js +2 -2
  179. package/dist/core/schema/version.js +6 -6
  180. package/dist/core/workers/worker-executor.js +3 -3
  181. package/dist/core/workers/worker-pool.js +0 -0
  182. package/dist/guardian/baseline.js +1 -1
  183. package/dist/guardian/gpg.js +3 -1
  184. package/dist/guardian/integrity.js +2 -7
  185. package/dist/guardian/records.js +6 -1
  186. package/dist/guardian/result.js +1 -1
  187. package/dist/guardian/sentinel.js +6 -1
  188. package/dist/guardian/watcher-hidden.js +5 -1
  189. package/dist/licenses/fs-utils.js +4 -1
  190. package/dist/licenses/generate-notices.js +1 -1
  191. package/dist/licenses/header-options.js +0 -1
  192. package/dist/licenses/index.js +1 -0
  193. package/dist/licenses/normalizer.js +10 -9
  194. package/dist/node.loader.js +224 -4
  195. package/dist/reports/analise-async-patterns.js +1 -1
  196. package/dist/reports/filter-smart.js +2 -5
  197. package/dist/reports/generator-report.js +4 -4
  198. package/dist/reports/report-archetypes.js +10 -10
  199. package/dist/reports/report-caretaker-health.js +2 -1
  200. package/dist/sdk/analyzer.js +1 -1
  201. package/dist/shared/data-processing/fragment-report.js +10 -10
  202. package/dist/shared/data-processing/json.js +1 -1
  203. package/dist/shared/data-processing/occurrences.js +3 -2
  204. package/dist/shared/formatters/code-min-formatter.js +1 -1
  205. package/dist/shared/formatters/engines/prettier.js +1 -1
  206. package/dist/shared/formatters/engines/stylelint.js +6 -9
  207. package/dist/shared/formatters/formatter.js +8 -8
  208. package/dist/shared/formatters/formatters/code.js +3 -3
  209. package/dist/shared/formatters/formatters/css.js +2 -10
  210. package/dist/shared/formatters/formatters/dotfiles.js +1 -1
  211. package/dist/shared/formatters/formatters/html.js +1 -5
  212. package/dist/shared/formatters/formatters/json.js +0 -3
  213. package/dist/shared/formatters/formatters/markdown.js +18 -23
  214. package/dist/shared/formatters/formatters/properties.js +2 -2
  215. package/dist/shared/formatters/formatters/shell.js +1 -4
  216. package/dist/shared/formatters/formatters/sql.js +0 -3
  217. package/dist/shared/formatters/formatters/xml.js +5 -7
  218. package/dist/shared/formatters/formatters/yaml.js +2 -7
  219. package/dist/shared/formatters/index.js +1 -1
  220. package/dist/shared/helpers/framework-detector.js +1 -1
  221. package/dist/shared/helpers/json.js +1 -1
  222. package/dist/shared/helpers/magic-constants-whitelist.js +1 -1
  223. package/dist/shared/helpers/masking.js +17 -17
  224. package/dist/shared/helpers/reader-report.js +0 -12
  225. package/dist/shared/helpers/structural-hash.js +3 -2
  226. package/dist/shared/helpers/structure.js +1 -1
  227. package/dist/shared/marketplace/registry.js +1 -1
  228. package/dist/shared/marketplace/remote.js +4 -4
  229. package/dist/shared/persistence/persistence.js +0 -1
  230. package/dist/shared/plugins/core-plugin.js +3 -1
  231. package/dist/shared/plugins/registry.js +3 -2
  232. package/dist/types/caretakers/imports-barrel.js +1 -0
  233. package/dist/types/caretakers/index.js +4 -0
  234. package/dist/types/caretakers/map-reversion.js +1 -0
  235. package/dist/types/caretakers/pruning.js +1 -0
  236. package/dist/types/caretakers/scoring.js +1 -0
  237. package/dist/types/common/analysts.js +1 -1
  238. package/dist/types/core/config/filters.js +1 -0
  239. package/dist/types/core/config/index.js +2 -0
  240. package/dist/types/core/execution/ambiente.js +1 -0
  241. package/dist/types/core/execution/linguagens.js +1 -0
  242. package/dist/types/core/execution/parse-errors.js +1 -0
  243. package/dist/types/core/execution/results.js +1 -0
  244. package/dist/types/core/execution/structure-json.js +1 -0
  245. package/dist/types/core/index.js +1 -0
  246. package/dist/types/core/messages/index.js +1 -0
  247. package/dist/types/core/messages/log.js +1 -0
  248. package/dist/types/core/parsing/babel-narrow.js +1 -0
  249. package/dist/types/core/parsing/index.js +1 -0
  250. package/dist/types/core/runtime.js +1 -0
  251. package/dist/types/guardian/index.js +2 -0
  252. package/dist/types/guardian/integrity.js +7 -0
  253. package/dist/types/guardian/snapshot.js +1 -0
  254. package/dist/types/index.js +4 -4
  255. package/dist/types/licenses/index.js +2 -0
  256. package/dist/types/processing/display.js +16 -13
  257. package/dist/types/processing/filters.js +3 -7
  258. package/dist/types/reports/compliance.js +1 -0
  259. package/dist/types/reports/streaming.js +1 -0
  260. package/dist/types/scripts/index.js +1 -0
  261. package/dist/types/scripts/migrar-aliases.js +1 -0
  262. package/dist/types/sdk/index.js +1 -0
  263. package/dist/types/shared/index.js +2 -0
  264. package/dist/types/vulnerabilities/index.js +2 -0
  265. package/dist/vulnerabilities/npm-audit.js +0 -1
  266. package/dist/vulnerabilities/scanner.js +2 -1
  267. package/dist/vulnerabilities/vulnerabilities.js +0 -1
  268. package/package.json +11 -12
@@ -10,8 +10,8 @@ export function sanitizarRelPath(rel) {
10
10
  if (!rel) {
11
11
  return '';
12
12
  }
13
- rel = rel.replace(/^[A-Za-z]:\\?/u, '').replace(/^\/+/, '');
14
- const norm = rel.replace(/\\+/g, '/');
13
+ const safe = rel.replace(/^[A-Za-z]:\\?/u, '').replace(/^\/+/, '');
14
+ const norm = safe.replace(/\\+/g, '/');
15
15
  const collapsed = path.posix.normalize(norm);
16
16
  if (collapsed.startsWith('..')) {
17
17
  // remove todos os prefixos de ../ e ./ e barras iniciais resultantes
@@ -53,17 +53,14 @@ export class AnalysisCache {
53
53
  await this.load();
54
54
  const hash = this.hashConteudo(conteudo);
55
55
  const entry = this.cache[relPath];
56
- if (!entry) {
57
- return null;
58
- }
59
- if (entry.hash !== hash) {
56
+ if (!entry || entry.hash !== hash) {
60
57
  return null;
61
58
  }
62
59
  // Verifica TTL
63
60
  if (config.ANALISE_CACHE_TTL_MS > 0) {
64
61
  const idade = Date.now() - entry.timestamp;
65
62
  if (idade > config.ANALISE_CACHE_TTL_MS) {
66
- delete this.cache[relPath];
63
+ Reflect.deleteProperty(this.cache, relPath);
67
64
  return null;
68
65
  }
69
66
  }
@@ -90,7 +87,7 @@ export class AnalysisCache {
90
87
  */
91
88
  async invalidate(relPath) {
92
89
  await this.load();
93
- delete this.cache[relPath];
90
+ Reflect.deleteProperty(this.cache, relPath);
94
91
  }
95
92
  /**
96
93
  * Limpa todo o cache
@@ -118,7 +115,7 @@ export class AnalysisCache {
118
115
  */
119
116
  estatisticas() {
120
117
  const entradas = Object.keys(this.cache);
121
- const totalOcorrencias = entradas.reduce((acc, key) => acc + (this.cache[key].count ?? 0), 0);
118
+ const totalOcorrencias = entradas.reduce((acc, key) => acc + this.cache[key].count, 0);
122
119
  return {
123
120
  totalEntradas: entradas.length,
124
121
  totalOcorrencias,
@@ -135,7 +132,7 @@ export class AnalysisCache {
135
132
  const agora = Date.now();
136
133
  for (const [key, entry] of Object.entries(this.cache)) {
137
134
  if (agora - entry.timestamp > config.ANALISE_CACHE_TTL_MS) {
138
- delete this.cache[key];
135
+ Reflect.deleteProperty(this.cache, key);
139
136
  }
140
137
  }
141
138
  }
@@ -12,7 +12,7 @@ import { analysisCache } from './analysis-cache.js';
12
12
  import { ScopeAstCache } from './ast-cache.js';
13
13
  import { ocorrenciaErroAnalista } from '../../types/index.js';
14
14
  async function withTimeout(value, timeoutMs, errorMessage) {
15
- let timer = null;
15
+ let timer = undefined;
16
16
  try {
17
17
  return await Promise.race([
18
18
  Promise.resolve(value),
@@ -22,7 +22,7 @@ async function withTimeout(value, timeoutMs, errorMessage) {
22
22
  ]);
23
23
  }
24
24
  finally {
25
- if (timer) {
25
+ if (timer !== undefined) {
26
26
  clearTimeout(timer);
27
27
  }
28
28
  }
@@ -57,9 +57,6 @@ function combinarVisitors(tecnicas) {
57
57
  return visitorCombinado;
58
58
  }
59
59
  for (const item of visitantes) {
60
- if (!item.visitor) {
61
- continue;
62
- }
63
60
  for (const [key, val] of Object.entries(item.visitor)) {
64
61
  if (!visitorCombinado[key]) {
65
62
  visitorCombinado[key] = val;
@@ -70,7 +67,7 @@ function combinarVisitors(tecnicas) {
70
67
  if (typeof prev === 'function') {
71
68
  prev(path, state);
72
69
  }
73
- else if (prev && typeof prev === 'object' && 'enter' in prev && typeof prev.enter === 'function') {
70
+ else if (typeof prev === 'object' && 'enter' in prev && typeof prev.enter === 'function') {
74
71
  prev.enter(path, state);
75
72
  }
76
73
  if (typeof val === 'function') {
@@ -225,10 +222,8 @@ export async function executarInquisicao(fileEntriesComAst, tecnicas, baseDir, g
225
222
  const hash = hashConteudo(entry.content ?? '');
226
223
  novoEstado.arquivos[entry.relPath] = { hash, ocorrencias: [], reaproveitadoCount: 0 };
227
224
  }
228
- if (novoEstado.estatisticas) {
229
- novoEstado.estatisticas.totalArquivosProcessados = fileEntriesComAst.length;
230
- novoEstado.estatisticas.ultimaDuracaoMs = duracao;
231
- }
225
+ novoEstado.estatisticas.totalArquivosProcessados = fileEntriesComAst.length;
226
+ novoEstado.estatisticas.ultimaDuracaoMs = duracao;
232
227
  await salvarEstado(config.ANALISE_INCREMENTAL_STATE_PATH, novoEstado);
233
228
  }
234
229
  catch { /* Ignora erro ao salvar cache */ }
@@ -366,9 +361,7 @@ export async function executarInquisicao(fileEntriesComAst, tecnicas, baseDir, g
366
361
  pushOcorrencia(...(cacheAnterior.ocorrencias ?? []));
367
362
  novoEstado.arquivos[entry.relPath] = { ...cacheAnterior, hash, hashEstrutural: cacheAnterior.hashEstrutural };
368
363
  novoEstado.arquivos[entry.relPath].reaproveitadoCount = (cacheAnterior.reaproveitadoCount ?? 0) + 1;
369
- if (novoEstado.estatisticas) {
370
- novoEstado.estatisticas.totalReaproveitamentos = (novoEstado.estatisticas.totalReaproveitamentos || 0) + 1;
371
- }
364
+ novoEstado.estatisticas.totalReaproveitamentos = (novoEstado.estatisticas.totalReaproveitamentos || 0) + 1;
372
365
  if (detalharPorArquivo) {
373
366
  messages.logCore.reaproveitadoIncremental(entry.relPath);
374
367
  }
@@ -534,9 +527,7 @@ export async function executarInquisicao(fileEntriesComAst, tecnicas, baseDir, g
534
527
  ultimaExecucaoMs: Date.now(),
535
528
  reaproveitadoCount: 0
536
529
  };
537
- if (novoEstado.estatisticas) {
538
- novoEstado.estatisticas.totalArquivosProcessados = (novoEstado.estatisticas.totalArquivosProcessados || 0) + 1;
539
- }
530
+ novoEstado.estatisticas.totalArquivosProcessados = (novoEstado.estatisticas.totalArquivosProcessados || 0) + 1;
540
531
  }
541
532
  // NOVO: Atualiza progresso por arquivo (não por analista)
542
533
  messages.logAnalistas.arquivoProcessado();
@@ -583,9 +574,7 @@ export async function executarInquisicao(fileEntriesComAst, tecnicas, baseDir, g
583
574
  await analysisCache.persistir().catch(() => { });
584
575
  }
585
576
  if (config.ANALISE_INCREMENTAL_ENABLED) {
586
- if (novoEstado.estatisticas) {
587
- novoEstado.estatisticas.ultimaDuracaoMs = duracaoMs;
588
- }
577
+ novoEstado.estatisticas.ultimaDuracaoMs = duracaoMs;
589
578
  await salvarEstado(config.ANALISE_INCREMENTAL_STATE_PATH, novoEstado);
590
579
  if (config.LOG_ESTRUTURADO) {
591
580
  messages.log.info(JSON.stringify({
@@ -106,27 +106,25 @@ async function aplicarPriorizacao(entries, metaSet) {
106
106
  return entries;
107
107
  }
108
108
  const pesos = {
109
- duracaoMs: config.ANALISE_PRIORIZACAO_PESOS.duracaoMs ?? 1,
110
- ocorrencias: config.ANALISE_PRIORIZACAO_PESOS.ocorrencias ?? 2,
111
- penalidadeReuso: config.ANALISE_PRIORIZACAO_PESOS.penalidadeReuso ?? 0.5
109
+ duracaoMs: config.ANALISE_PRIORIZACAO_PESOS.duracaoMs,
110
+ ocorrencias: config.ANALISE_PRIORIZACAO_PESOS.ocorrencias,
111
+ penalidadeReuso: config.ANALISE_PRIORIZACAO_PESOS.penalidadeReuso
112
112
  };
113
113
  const scored = entries.map(entry => {
114
114
  const hist = inc.arquivos[entry.relPath];
115
115
  let score = 0;
116
- if (hist) {
117
- let dur = 0;
118
- let occ = 0;
119
- if (hist.analistas) {
120
- for (const a of Object.values(hist.analistas)) {
121
- dur += a.duracaoMs;
122
- occ += a.ocorrencias;
123
- }
124
- }
125
- else {
126
- occ = hist.ocorrencias?.length ?? 0;
116
+ let dur = 0;
117
+ let occ = 0;
118
+ if (hist.analistas) {
119
+ for (const a of Object.values(hist.analistas)) {
120
+ dur += a.duracaoMs;
121
+ occ += a.ocorrencias;
127
122
  }
128
- score = dur * pesos.duracaoMs + occ * pesos.ocorrencias - (hist.reaproveitadoCount ?? 0) * pesos.penalidadeReuso;
129
123
  }
124
+ else {
125
+ occ = hist.ocorrencias?.length ?? 0;
126
+ }
127
+ score = dur * pesos.duracaoMs + occ * pesos.ocorrencias - (hist.reaproveitadoCount ?? 0) * pesos.penalidadeReuso;
130
128
  return { entry, score };
131
129
  });
132
130
  scored.sort((a, b) => b.score - a.score);
@@ -167,7 +165,7 @@ export async function prepararComAst(entries, baseDir) {
167
165
  metricas.cacheHits = 0;
168
166
  metricas.cacheMiss = 0;
169
167
  g.__SUKUNA_METRICAS__ = metricas;
170
- const CONCURRENCY = (config.AUTOANALISE_CONCURRENCY ?? 50);
168
+ const CONCURRENCY = config.AUTOANALISE_CONCURRENCY;
171
169
  const limit = pLimit(CONCURRENCY);
172
170
  return Promise.all(entries.map(entry => limit(async () => {
173
171
  let ast;
@@ -235,13 +233,18 @@ export async function iniciarInquisicao(baseDir = process.cwd(), options = {}, t
235
233
  if (progressData.tipo === 'diretorio') {
236
234
  const g = getGlobal();
237
235
  g.__SUKUNA_DIR_COUNT__ = (g.__SUKUNA_DIR_COUNT__ ?? 0) + 1;
238
- g.__SUKUNA_DIR_SAMPLES__ ??= [];
239
- if (g.__SUKUNA_DIR_SAMPLES__.length < 5) {
240
- g.__SUKUNA_DIR_SAMPLES__.push(progressData.caminho);
236
+ const samples = g.__SUKUNA_DIR_SAMPLES__ ?? [];
237
+ if (samples.length < 5) {
238
+ const caminho = progressData.caminho ?? '';
239
+ samples.push(caminho);
240
+ g.__SUKUNA_DIR_SAMPLES__ = samples;
241
241
  }
242
242
  }
243
243
  else if (progressData.tipo === 'erro') {
244
- messages.log.erro(`Erro ao ${progressData.acao} ${progressData.caminho}: ${progressData.mensagem}`);
244
+ const acao = progressData.acao ?? '';
245
+ const caminho = progressData.caminho ?? '';
246
+ const mensagem = progressData.mensagem ?? '';
247
+ messages.log.erro(`Erro ao ${acao} ${caminho}: ${mensagem}`);
245
248
  }
246
249
  }
247
250
  catch {
@@ -300,7 +303,7 @@ export async function iniciarInquisicao(baseDir = process.cwd(), options = {}, t
300
303
  const porArquivo = {};
301
304
  for (const pe of parseErros) {
302
305
  const chave = pe.relPath || '__desconhecido__';
303
- (porArquivo[chave] = porArquivo[chave] || []).push(pe);
306
+ porArquivo[chave].push(pe);
304
307
  }
305
308
  for (const [arq, lista] of Object.entries(porArquivo)) {
306
309
  if (lista.length <= (config.PARSE_ERRO_MAX_POR_ARQUIVO || 1)) {
@@ -1 +1,2 @@
1
+ // SPDX-License-Identifier: MIT
1
2
  export {};
@@ -33,7 +33,7 @@ export async function scanRepository(baseDir, options = {}) {
33
33
  const statCache = new Map();
34
34
  const cliIncludeGroups = config.CLI_INCLUDE_GROUPS;
35
35
  const includeGroups = Array.isArray(cliIncludeGroups) ? cliIncludeGroups : [];
36
- const includeGroupsNorm = includeGroups.map(grupo => (grupo || []).map(caminho => toPosix(trimDotSlash((caminho || '')))));
36
+ const includeGroupsNorm = includeGroups.map(grupo => grupo.map(caminho => toPosix(trimDotSlash(caminho))));
37
37
  const includePadroes = ensureStringArray(config.CLI_INCLUDE_PATTERNS);
38
38
  const includePadroesNorm = includePadroes.map(caminho => toPosix(trimDotSlash((caminho || ''))));
39
39
  const excludePadroesNorm = ensureStringArray(config.CLI_EXCLUDE_PATTERNS).map(caminho => toPosix((caminho || '')));
@@ -188,7 +188,7 @@ export async function scanRepository(baseDir, options = {}) {
188
188
  return true;
189
189
  }
190
190
  // Compat extra também para padrões simples quando não há grupos
191
- for (const caminho of includePadroesNorm || []) {
191
+ for (const caminho of includePadroesNorm) {
192
192
  if (matchesPadrao(relPath, caminho)) {
193
193
  return true;
194
194
  }
@@ -367,7 +367,7 @@ export async function scanRepository(baseDir, options = {}) {
367
367
  st = await fs.stat(norm);
368
368
  statC.set(norm, st);
369
369
  }
370
- let isDir = st.isDirectory() ?? false;
370
+ let isDir = st.isDirectory();
371
371
  if (!isDir) {
372
372
  try {
373
373
  await fs.readdir(norm);
@@ -54,5 +54,5 @@ export const AnalistaGithubActionsMensagens = {
54
54
  pullRequestTargetGrantsWritePermissionsSugestao: 'Use pull_request instead of pull_request_target, or carefully validate the source branch',
55
55
  workflowDispatchWithoutInputs: 'workflow_dispatch without defined inputs',
56
56
  workflowDispatchWithoutInputsSugestao: 'Define required inputs to control manual workflow execution',
57
- erroAplicarCorrecao: (erro) => `Error applying fix: ${erro}`,
57
+ erroAplicarCorrecao: (erro) => `Error applying fix: ${String(erro)}`,
58
58
  };
@@ -16,5 +16,6 @@ export const PadroesUsoMensagens = {
16
16
  nonArrowCallback: "Callback using 'function' where arrow function would be more appropriate. Prefer () => {}.",
17
17
  consoleLog: "console.log detected in production code. Remove or replace with appropriate logger.",
18
18
  uselessConditional: "Unnecessary comparison: if (x === true). Use just if (x).",
19
+ satisfiesUsage: "TypeScript 'satisfies' keyword used — ensures type safety without widening",
19
20
  erroAnalise: (relPath, erro) => `Failed to analyze usage patterns in ${relPath}: ${erro}`
20
21
  };
@@ -60,4 +60,19 @@ export const AnalistaShellMensagens = {
60
60
  loopOverCommandOutputSugestao: 'Use glob: "for f in *".',
61
61
  pipeOverTempfile: 'Pipeline could replace temporary file.',
62
62
  pipeOverTempfileSugestao: 'Use pipes instead of temporary files.',
63
+ // Modern Bash (2026)
64
+ missingSetU: 'Missing "set -u" — unset variable references will silently expand to empty.',
65
+ missingSetUSugestao: 'Add "set -u" to catch typos in variable names.',
66
+ missingIso: 'Missing IFS=$\'\\n\\t\' — word splitting may cause unexpected behavior.',
67
+ missingIsoSugestao: 'Add IFS=$\'\\n\\t\' at the top of the script for safe word splitting.',
68
+ missingTrap: 'No trap handler found — cleanup may be skipped on signals.',
69
+ missingTrapSugestao: 'Add trap handler: trap "cleanup" EXIT INT TERM.',
70
+ missingMainFn: 'Script lacks a main function pattern.',
71
+ missingMainFnSugestao: 'Wrap logic in main() and call main "$@" at the bottom.',
72
+ missingCommandV: 'Hardcoded path instead of using command -v.',
73
+ missingCommandVSugestao: 'Use "command -v <tool>" to check availability.',
74
+ missingDebugMode: 'Script has no debug mode — troubleshooting is harder.',
75
+ missingDebugModeSugestao: 'Add [[ "${DEBUG:-}" == "true" ]] && set -x for debug tracing.',
76
+ missingInputValidation: 'Command arguments not validated — unexpected input may cause errors.',
77
+ missingInputValidationSugestao: 'Validate arguments at the top: [[ -z "$1" ]] && { echo "Usage: ..."; exit 1; }.',
63
78
  };
@@ -11,4 +11,10 @@ export const DetectorConstrucoesSintaticasMensagens = {
11
11
  templateLiteralOveruse: "Unnecessary template literal for simple concatenation. Use '+' operator.",
12
12
  unnecessaryObjectSpread: "Unnecessary object spread. Direct assignment 'obj.prop = val' is more efficient.",
13
13
  getterSetterWithoutValidation: "Getter/setter without validation in the setter. Add validation to avoid invalid data.",
14
+ // ES2025/ES2026
15
+ explicitResourceManagement: "Explicit Resource Management with 'using' detected (ES2026)",
16
+ temporalApiUsage: "Temporal API usage detected (ES2026) — modern date/time alternative to Date",
17
+ iteratorHelperUsage: "Iterator helper method detected (ES2025) — lazy evaluation on iterables",
18
+ setMethodUsage: "New Set method detected (ES2025) — use for set operations",
19
+ mapUpsertUsage: "Map upsert method detected (ES2026) — .getOrInsert() / .getOrInsertComputed()",
14
20
  };
@@ -54,4 +54,31 @@ export const DetectorJsTsMensagens = {
54
54
  observerWithoutDisconnect: 'Observer (MutationObserver/IntersectionObserver) without disconnect(). This causes memory leaks.',
55
55
  webSocketWithoutClose: 'WebSocket without matching close() call. The connection may remain open.',
56
56
  workerWithoutTerminate: 'Worker without terminate() call. The worker will continue running in the background.',
57
+ // ES2025+ features
58
+ satisfiesAvailable: 'Type can use "satisfies" instead of "as" assertion for safer narrowing',
59
+ satisfiesAvailableSugestao: 'Replace "as Type" with "satisfies Type" to validate without widening',
60
+ usingResourceManagement: 'Explicit Resource Management with "using" detected (ES2026)',
61
+ usingResourceManagementSugestao: 'Ensure the resource implements Symbol.dispose or Symbol.asyncDispose',
62
+ temporalApi: 'Temporal API usage detected (ES2026)',
63
+ temporalApiSugestao: 'Temporal replaces Date — use Temporal.Now, Temporal.PlainDate, etc.',
64
+ iteratorHelper: 'Iterator helper method detected (ES2025)',
65
+ iteratorHelperSugestao: 'Iterator helpers (.map(), .filter(), .take()) enable lazy evaluation',
66
+ setMethods: 'New Set method detected (ES2025)',
67
+ setMethodsSugestao: 'Use Set.prototype.union(), .intersection(), .difference() for set operations',
68
+ topLevelAwait: 'Top-level await detected',
69
+ topLevelAwaitSugestao: 'Verify the module top-level await does not block imports unnecessarily',
70
+ promiseWithResolvers: 'Promise.withResolvers() detected (ES2025)',
71
+ promiseWithResolversSugestao: 'Prefer async/await over Promise.withResolvers() when possible',
72
+ promiseAllSettled: 'Promise.allSettled() detected — good for all-settled patterns',
73
+ promiseAllSettledSugestao: 'Use Promise.allSettled() when you need results from all promises regardless of rejection',
74
+ forAwaitOf: 'for await...of detected — async iteration',
75
+ forAwaitOfSugestao: 'Ensure the async iterable correctly implements Symbol.asyncIterator',
76
+ regexpEscape: 'RegExp.escape() detected (ES2025)',
77
+ regexpEscapeSugestao: 'Use RegExp.escape() to safely escape user input in regex patterns',
78
+ errorIsError: 'Error.isError() detected (ES2026)',
79
+ errorIsErrorSugestao: 'Use Error.isError() for reliable error type checking',
80
+ arrayFromAsync: 'Array.fromAsync() detected (ES2026)',
81
+ arrayFromAsyncSugestao: 'Use Array.fromAsync() to create arrays from async iterables',
82
+ mapGetOrInsert: 'Map.getOrInsert() / .getOrInsertComputed() detected (ES2026)',
83
+ mapGetOrInsertSugestao: 'Use getOrInsert() for atomic map upsert operations',
57
84
  };
@@ -57,4 +57,12 @@ export const DetectorReactMensagens = {
57
57
  contextTooBroadSugestao: 'Split into smaller contexts',
58
58
  liftingStateTooHigh: 'State lifted more levels than needed',
59
59
  liftingStateTooHighSugestao: 'Consider context or local state',
60
+ react19ForwardRef: 'forwardRef deprecated in React 19',
61
+ react19ForwardRefSugestao: 'Pass ref as a regular prop instead',
62
+ react19FC: 'React.FC deprecated in React 19',
63
+ react19FCSugestao: 'Type props directly instead of using React.FC',
64
+ react19UseClient: 'Missing \'use client\' directive (React 19)',
65
+ react19UseClientSugestao: 'Add \'use client\' at the top of the file for client components',
66
+ react19DefaultProps: 'defaultProps deprecated in React 19',
67
+ react19DefaultPropsSugestao: 'Use default parameter values instead',
60
68
  };
@@ -60,4 +60,21 @@ export const DetectorShellMensagens = {
60
60
  loopOverCommandOutputSugestao: 'Use glob patterns instead of parsing ls',
61
61
  pipeOverTempfile: 'Pipeline could replace temporary file',
62
62
  pipeOverTempfileSugestao: 'Use pipes instead of temporary files',
63
+ // Modern Bash (2026)
64
+ missingSetU: 'Missing "set -u" — unset variable references will silently expand to empty',
65
+ missingSetUSugestao: 'Add "set -u" to catch typos in variable names',
66
+ missingIso: 'Missing IFS=$\'\\n\\t\' — word splitting may cause unexpected behavior',
67
+ missingIsoSugestao: 'Add IFS=$\'\\n\\t\' at the top of the script for safe word splitting',
68
+ missingTrap: 'No trap handler found — cleanup may be skipped on signals',
69
+ missingTrapSugestao: 'Add trap handler: trap "cleanup" EXIT INT TERM',
70
+ missingMainFn: 'Script lacks a main function pattern',
71
+ missingMainFnSugestao: 'Wrap logic in main() and call main "$@" at the bottom',
72
+ missingCommandV: 'Hardcoded path instead of using command -v',
73
+ missingCommandVSugestao: 'Use "command -v <tool>" to check availability',
74
+ missingDebugMode: 'Script has no debug mode — troubleshooting is harder',
75
+ missingDebugModeSugestao: 'Add [[ "${DEBUG:-}" == "true" ]] && set -x for debug tracing',
76
+ missingInputValidation: 'Command arguments not validated — unexpected input may cause errors',
77
+ missingInputValidationSugestao: 'Validate arguments at the top: [[ -z "$1" ]] && { echo "Usage: ..."; exit 1; }',
78
+ shellCheckRecommended: 'Consider running ShellCheck for comprehensive analysis',
79
+ shellCheckRecommendedSugestao: 'Install shellcheck and run: shellcheck script.sh',
63
80
  };
@@ -5,13 +5,13 @@ export const DetectorTailwindMensagens = {
5
5
  repeatedClasses: (duplicates) => `Repeated classes: ${duplicates}`,
6
6
  repeatedClassesSugestao: 'Remove duplicate classes',
7
7
  arbitraryValue: (val) => `Arbitrary value detected: ${val}`,
8
- arbitraryValueSugestao: 'Consider adding it to tailwind.config.js',
8
+ arbitraryValueSugestao: 'Consider adding it via @theme in CSS (Tailwind v4)',
9
9
  important: '!important detected in Tailwind class',
10
10
  importantSugestao: 'Avoid !important - refactor specificity',
11
11
  arbitraryValueOveruse: 'Excessive use of arbitrary values - may indicate missing design tokens',
12
- arbitraryValueOveruseSugestao: 'Define custom tokens in tailwind.config.js instead of arbitrary values',
12
+ arbitraryValueOveruseSugestao: 'Define custom tokens via @theme in CSS instead of arbitrary values (Tailwind v4)',
13
13
  missingDesignToken: 'Hardcoded value detected - use Tailwind design tokens',
14
- missingDesignTokenSugestao: 'Extract colors, spacing, and sizes to tailwind.config.js',
14
+ missingDesignTokenSugestao: 'Extract colors, spacing, and sizes to @theme in CSS (Tailwind v4)',
15
15
  responsiveWithoutBase: 'Responsive class without corresponding base class',
16
16
  responsiveWithoutBaseSugestao: 'Add the base class before responsive variants',
17
17
  inlineStylesWithTailwind: 'Inline styles detected alongside Tailwind classes',
@@ -29,7 +29,16 @@ export const ReactMensagens = {
29
29
  export const ReactHooksMensagens = {
30
30
  useEffectNoDeps: 'useEffect without dependency array (evaluate deps to avoid loops).',
31
31
  memoCallbackNoDeps: 'Hook without dependency array (useMemo/useCallback).',
32
- hookInConditional: 'Hook declared inside conditional (breaks Rules of Hooks).'
32
+ hookInConditional: 'Hook declared inside conditional (breaks Rules of Hooks).',
33
+ react19Use: 'use() hook detected (React 19) — ensure wrapped in <Suspense> boundary.',
34
+ react19UseOptimistic: 'useOptimistic hook detected (React 19) — requires update function.',
35
+ react19UseActionState: 'useActionState hook detected (React 19) — for form actions.',
36
+ react19UseFormStatus: 'useFormStatus hook detected (React 19) — access form pending state.',
37
+ react19ForwardRefDeprecated: 'forwardRef is deprecated in React 19 — pass ref as regular prop.',
38
+ react19FCDeprecated: 'React.FC/FunctionComponent is deprecated in React 19 — type props directly.',
39
+ react19DefaultPropsDeprecated: 'defaultProps is deprecated in React 19 — use default parameters.',
40
+ react19UseClient: 'File uses client features (hooks/events) without \'use client\' directive (React 19).',
41
+ react19FormAction: 'Form with action prop detected (React 19).'
33
42
  };
34
43
  // ─── TAILWIND MESSAGES ────────────────────────────────────────
35
44
  export const TailwindMensagens = {
@@ -38,7 +47,13 @@ export const TailwindMensagens = {
38
47
  importantUsage: (token) => `Use of ! (important) detected in (${token}). Prefer utility classes or scope reinforcement instead of important.`,
39
48
  variantConflict: (prop, variants) => `Possible variant conflict for ${prop} (variants: ${variants.slice(0, 6).join(', ')}). Check order/scope.`,
40
49
  dangerousArbitraryValue: (token) => `Arbitrary value with potentially dangerous url (${token}). Avoid javascript:/data:text/html.`,
41
- arbitraryValue: (token) => `Class with arbitrary value (${token}). Confirm it aligns with the design.`
50
+ arbitraryValue: (token) => `Class with arbitrary value (${token}). Confirm it aligns with the design.`,
51
+ v3DeprecatedUtility: (token, replacement) => `v3 deprecated utility "${token}" → use "${replacement}" (Tailwind v4).`,
52
+ v3Directive: `@tailwind directive detected (v3) → use @import "tailwindcss" (Tailwind v4).`,
53
+ v3LayerUtilities: `@layer utilities detected (v3) → use @utility (Tailwind v4).`,
54
+ themeFunction: `theme() function detected (deprecated v3) → prefer CSS variables (var(--color-*)).`,
55
+ v3ImportantPrefix: (token) => `!important as prefix in "${token}" (v3) → move ! to the end ("${token.replace('!', '')}!").`,
56
+ v3ArbitraryVar: `Variable in square brackets (v3) → use parentheses (e.g. bg-(--var) instead of bg-[--var]).`
42
57
  };
43
58
  // ─── CSS MESSAGES ─────────────────────────────────────────────
44
59
  export const CssMensagens = {
@@ -287,7 +302,20 @@ export const RustMensagens = {
287
302
  missingDoc: (fnName) => `Public function '${fnName}' missing documentation comment (///).`,
288
303
  namingConvention: (constName) => `Constant '${constName}' should follow SCREAMING_CASE convention.`,
289
304
  redundantReturn: 'Redundant return at end of function; Rust uses implicit return (last expression).',
290
- wildcardImport: (importPath) => `Wildcard import '${importPath}' may pollute namespace; prefer explicit imports.`
305
+ wildcardImport: (importPath) => `Wildcard import '${importPath}' may pollute namespace; prefer explicit imports.`,
306
+ lazyLockSuggestion: 'once_cell::sync::Lazy detected — use std::sync::LazyLock (Rust 1.80+).',
307
+ onceLockSuggestion: 'once_cell::sync::OnceCell detected — use std::sync::OnceLock (Rust 1.70+).',
308
+ offsetOfSuggestion: 'Manual pointer offset for field access — use std::mem::offset_of! (Rust 1.77+).',
309
+ letChainsPattern: 'let_chains pattern detected (stable since Rust 1.78).',
310
+ assertMatchesSuggestion: 'assert!(matches!(...)) pattern — consider assert_matches!(...) (nightly).',
311
+ isSomeAnd: '.is_some() && predicate pattern — use .is_some_and(|x| ...) (Rust 1.70+).',
312
+ isOkAnd: '.is_ok() && predicate pattern — use .is_ok_and(|x| ...) (Rust 1.70+).',
313
+ inspectMethod: 'map() with side-effect closure — use .inspect() (Rust 1.76+).',
314
+ implicitFormatCapture: 'format!("...{var}...") can use implicit capture (Rust 1.80+).',
315
+ pointerCast: 'Using `as` for pointer cast — use .cast() (Rust 1.72+).',
316
+ splitOnce: 'splitn(2, ...) with index access — use .split_once() (Rust 1.62+).',
317
+ okErrAntipattern: '.ok()?.unwrap() antipattern — use ? directly on Result.',
318
+ collectOverPush: 'Collection built with push() in loop — use .map().collect().'
291
319
  };
292
320
  // ─── JAVA / KOTLIN MESSAGES ───────────────────────────────────
293
321
  export const JavaMensagens = {
@@ -140,9 +140,9 @@ export function formatarLinha({ nivel, mensagem, sanitize = true }) {
140
140
  if (!process.env.VITEST && process.env.SUKUNA_CENTER === '1') {
141
141
  try {
142
142
  const cols = obterColunasTerm();
143
- const out = process.stdout && typeof process.stdout.isTTY !== 'undefined' ? process.stdout : undefined;
143
+ const out = typeof process.stdout.isTTY !== 'undefined' ? process.stdout : undefined;
144
144
  const isTty = !!out && out.isTTY;
145
- if (isTty && cols && cols > 0) {
145
+ if (isTty && typeof cols === 'number' && cols > 0) {
146
146
  const ANSI_REGEX = /[\u001B\u009B][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
147
147
  const visLen = (string) => (string || '').replace(ANSI_REGEX, '').length;
148
148
  const pad = Math.floor(Math.max(0, cols - visLen(linha)) / 2);
@@ -164,7 +164,7 @@ export function formatarLinha({ nivel, mensagem, sanitize = true }) {
164
164
  function obterColunasTerm() {
165
165
  // Tries to get terminal width safely
166
166
  try {
167
- const out = process.stdout && typeof process.stdout.columns !== 'undefined' ? process.stdout : undefined;
167
+ const out = typeof process.stdout.columns !== 'undefined' ? process.stdout : undefined;
168
168
  const cols = out?.columns;
169
169
  if (typeof cols === 'number' && cols > 0) {
170
170
  return cols;
@@ -414,7 +414,7 @@ export const log = {
414
414
  const visibleLen = (string) => string.replace(ANSI_REGEX, '').length;
415
415
  const frameWidth = Math.max(...lines.map(linha => visibleLen(linha)));
416
416
  const cols = obterColunasTerm() ?? 0;
417
- const outStream = process.stdout && typeof process.stdout.isTTY !== 'undefined' ? process.stdout : undefined;
417
+ const outStream = typeof process.stdout.isTTY !== 'undefined' ? process.stdout : undefined;
418
418
  const isTty = !!outStream && outStream.isTTY;
419
419
  if (isTty) {
420
420
  const pad = Math.floor(Math.max(0, cols - frameWidth) / 2);
@@ -221,11 +221,7 @@ export const AGRUPAMENTOS_MENSAGEM = [
221
221
  * Gets the priority of a problem type
222
222
  */
223
223
  export function getPrioridade(tipo) {
224
- return PRIORIDADES[tipo] || {
225
- prioridade: 'baixa',
226
- icone: ICONES_ARQUIVO.arquivo,
227
- descricao: 'Uncategorized problem'
228
- };
224
+ return PRIORIDADES[tipo];
229
225
  }
230
226
  /**
231
227
  * Finds grouping by message
@@ -40,7 +40,7 @@ function detectLocale() {
40
40
  const configPath = path.join(process.cwd(), 'mahoraga.config.json');
41
41
  const conteudo = fs.readFileSync(configPath, 'utf-8');
42
42
  const json = JSON.parse(conteudo);
43
- const confLocale = ((json.locale ?? json.locales) ?? json.LOCALE)?.toLowerCase();
43
+ const confLocale = (json.locale ?? json.locales ?? json.LOCALE)?.toLowerCase();
44
44
  if (confLocale && SUPPORTED_LOCALES.includes(confLocale)) {
45
45
  return confLocale;
46
46
  }
@@ -62,7 +62,7 @@ export function initLocale() {
62
62
  }
63
63
  initLocale();
64
64
  export function carregarMensagens(locale) {
65
- if (cache[locale]) {
65
+ if (locale in cache) {
66
66
  return cache[locale];
67
67
  }
68
68
  const caminho = path.join(process.cwd(), 'src', 'core', 'messages', 'locales', `${locale}.json`);
@@ -101,7 +101,7 @@ const localeModules = {
101
101
  export const messages = new Proxy({}, {
102
102
  get(_target, prop) {
103
103
  const locale = getLocale();
104
- const mod = localeModules[locale] || localeModules.pt;
104
+ const mod = localeModules[locale];
105
105
  if (prop in mod) {
106
106
  return mod[prop];
107
107
  }
@@ -43,7 +43,7 @@ function detectLocale() {
43
43
  const configPath = path.join(process.cwd(), 'mahoraga.config.json');
44
44
  const conteudo = fs.readFileSync(configPath, 'utf-8');
45
45
  const json = JSON.parse(conteudo);
46
- const confLocale = ((json.locale ?? json.locales) ?? json.LOCALE)?.toLowerCase();
46
+ const confLocale = (json.locale ?? json.locales ?? json.LOCALE)?.toLowerCase();
47
47
  if (confLocale && SUPPORTED_LOCALES.includes(confLocale)) {
48
48
  return confLocale;
49
49
  }
@@ -66,7 +66,7 @@ export function initLocale() {
66
66
  }
67
67
  initLocale();
68
68
  export function carregarMensagens(locale) {
69
- if (cache[locale]) {
69
+ if (locale in cache) {
70
70
  return cache[locale];
71
71
  }
72
72
  const caminho = path.join(process.cwd(), 'src', 'core', 'messages', 'locales', `${locale}.json`);
@@ -105,7 +105,7 @@ const localeModules = {
105
105
  export const messages = new Proxy({}, {
106
106
  get(_target, prop) {
107
107
  const locale = getLocale();
108
- const mod = localeModules[locale] || localeModules.pt;
108
+ const mod = localeModules[locale];
109
109
  if (prop in mod) {
110
110
  return mod[prop];
111
111
  }
@@ -55,5 +55,5 @@ export const AnalistaGithubActionsMensagens = {
55
55
  pullRequestTargetGrantsWritePermissionsSugestao: 'pull_request_target の代わりに pull_request を使用するか、ソースブランチを慎重に検証してください',
56
56
  workflowDispatchWithoutInputs: 'inputs が定義されていない workflow_dispatch',
57
57
  workflowDispatchWithoutInputsSugestao: '手動ワークフロー実行を制御するため必須入力を定義してください',
58
- erroAplicarCorrecao: (erro) => `修正の適用エラー: ${erro}`,
58
+ erroAplicarCorrecao: (erro) => `修正の適用エラー: ${String(erro)}`,
59
59
  };
@@ -16,5 +16,6 @@ export const PadroesUsoMensagens = {
16
16
  nonArrowCallback: "'function'を使用したコールバックでアロー関数の方が適切です。() => {}を優先してください。",
17
17
  consoleLog: "本番コードでconsole.logが検出されました。削除するか適切なロガーに置き換えてください。",
18
18
  uselessConditional: "不要な比較: if (x === true)。if (x) のみを使用してください。",
19
+ satisfiesUsage: "TypeScript の 'satisfies' キーワードが使用されています — ワイドニングなしで型安全性を保証します",
19
20
  erroAnalise: (relPath, erro) => `${relPath}の使用パターン分析に失敗しました: ${erro}`
20
21
  };
@@ -60,4 +60,19 @@ export const AnalistaShellMensagens = {
60
60
  loopOverCommandOutputSugestao: 'グロブを使用: "for f in *"。',
61
61
  pipeOverTempfile: 'パイプラインが一時ファイルを置き換えられる可能性があります。',
62
62
  pipeOverTempfileSugestao: '一時ファイルの代わりにパイプを使用してください。',
63
+ // Modern Bash (2026)
64
+ missingSetU: '"set -u" がありません — 未設定の変数は静かに空に展開されます。',
65
+ missingSetUSugestao: '変数名のタイポをキャッチするために "set -u" を追加してください。',
66
+ missingIso: 'IFS=$\'\\n\\t\' がありません — ワードスプリッティングが予期しない動作を引き起こす可能性があります。',
67
+ missingIsoSugestao: '安全なワードスプリッティングのためにスクリプト先頭に IFS=$\'\\n\\t\' を追加してください。',
68
+ missingTrap: 'trap ハンドラが見つかりません — シグナル時にクリーンアップがスキップされる可能性があります。',
69
+ missingTrapSugestao: 'trap ハンドラを追加: trap "cleanup" EXIT INT TERM。',
70
+ missingMainFn: 'スクリプトに main 関数パターンがありません。',
71
+ missingMainFnSugestao: 'ロジックを main() でラップし、最後に main "$@" を呼び出してください。',
72
+ missingCommandV: 'command -v の代わりにハードコードされたパス。',
73
+ missingCommandVSugestao: '可用性を確認するには "command -v <ツール>" を使用してください。',
74
+ missingDebugMode: 'スクリプトにデバッグモードがありません — トラブルシューティングが困難です。',
75
+ missingDebugModeSugestao: 'デバッグトレースのために [[ "${DEBUG:-}" == "true" ]] && set -x を追加してください。',
76
+ missingInputValidation: 'コマンド引数が検証されていません — 予期しない入力がエラーの原因になる可能性があります。',
77
+ missingInputValidationSugestao: '先頭で引数を検証: [[ -z "$1" ]] && { echo "使用法: ..."; exit 1; }。',
63
78
  };
@@ -11,4 +11,10 @@ export const DetectorConstrucoesSintaticasMensagens = {
11
11
  templateLiteralOveruse: "単純な連結に不要なテンプレートリテラル。'+'演算子を使用してください。",
12
12
  unnecessaryObjectSpread: "不要なオブジェクトスプレッド。直接代入'obj.prop = val'の方が効率的です。",
13
13
  getterSetterWithoutValidation: "セッターにバリデーションのないgetter/setter。無効なデータを防ぐためバリデーションを追加してください。",
14
+ // ES2025/ES2026
15
+ explicitResourceManagement: "'using' を使用した明示的リソース管理が検出されました (ES2026)",
16
+ temporalApiUsage: "Temporal API の使用が検出されました (ES2026) — Date に代わる最新の日付/時刻 API",
17
+ iteratorHelperUsage: "イテレータヘルパーメソッドが検出されました (ES2025) — イテラブルに対する遅延評価",
18
+ setMethodUsage: "新しい Set メソッドが検出されました (ES2025) — 集合演算に使用",
19
+ mapUpsertUsage: "Map の upsert メソッドが検出されました (ES2026) — .getOrInsert() / .getOrInsertComputed()",
14
20
  };