@mocoto/mahoraga 0.14.1 → 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 (306) hide show
  1. package/README.md +0 -34
  2. package/dist/analysts/architects/analyst-structure.js +20 -20
  3. package/dist/analysts/architects/archetypes-custom.js +16 -19
  4. package/dist/analysts/architects/detector-archetypes.js +43 -36
  5. package/dist/analysts/architects/orchestrator-archetypes.js +3 -3
  6. package/dist/analysts/architects/signals-project-advanced.js +26 -28
  7. package/dist/analysts/architects/signals-project.js +2 -2
  8. package/dist/analysts/architects/strategist-structure.js +47 -66
  9. package/dist/analysts/azure-pipelines/analysts/analyst-azure.js +41 -35
  10. package/dist/analysts/azure-pipelines/corrections/correction-azure.js +22 -19
  11. package/dist/analysts/azure-pipelines/detectors/detector-azure-performance.js +21 -18
  12. package/dist/analysts/azure-pipelines/detectors/detector-azure-security.js +25 -20
  13. package/dist/analysts/azure-pipelines/detectors/detector-azure-structure.js +39 -40
  14. package/dist/analysts/azure-pipelines/scorers/scorer-azure.js +10 -7
  15. package/dist/analysts/circleci/analysts/analyst-circleci.js +33 -27
  16. package/dist/analysts/circleci/corrections/correction-circleci.js +22 -20
  17. package/dist/analysts/circleci/detectors/detector-circleci-performance.js +23 -19
  18. package/dist/analysts/circleci/detectors/detector-circleci-security.js +78 -82
  19. package/dist/analysts/circleci/detectors/detector-circleci-structure.js +22 -22
  20. package/dist/analysts/converters/convert-registry.js +1 -1
  21. package/dist/analysts/converters/engines/converter-gha-to-gitlab.js +17 -15
  22. package/dist/analysts/converters/index.js +1 -1
  23. package/dist/analysts/corrections/analyst-quick-fixes.js +25 -28
  24. package/dist/analysts/corrections/analyst-scoring.js +24 -21
  25. package/dist/analysts/corrections/auto-fix-engine.js +1 -1
  26. package/dist/analysts/corrections/corrector-structure.js +43 -42
  27. package/dist/analysts/corrections/fix-alias-imports.js +10 -6
  28. package/dist/analysts/corrections/fix-md-fences.js +23 -23
  29. package/dist/analysts/corrections/map-reversion.js +56 -53
  30. package/dist/analysts/corrections/pruning.js +19 -16
  31. package/dist/analysts/corrections/quick-fixes/fix-any-to-proper-type.js +57 -61
  32. package/dist/analysts/corrections/quick-fixes/fix-unknown-to-specific-type.js +30 -30
  33. package/dist/analysts/corrections/reorganize-barrels.js +13 -13
  34. package/dist/analysts/corrections/rewrite-testes-aliases.js +23 -22
  35. package/dist/analysts/corrections/scoring-shared.js +19 -18
  36. package/dist/analysts/corrections/type-safety/context-analyzer.js +15 -10
  37. package/dist/analysts/corrections/type-safety/type-analyzer.js +3 -3
  38. package/dist/analysts/corrections/type-safety/type-validator.js +4 -3
  39. package/dist/analysts/corrections/type-safety/usage-analyzer.js +39 -42
  40. package/dist/analysts/css/analysts/analyst-css.js +42 -42
  41. package/dist/analysts/css/corrections/correction-css.js +19 -11
  42. package/dist/analysts/css/detectors/detector-css-best-practices.js +129 -118
  43. package/dist/analysts/css/scorers/scorer-css.js +23 -18
  44. package/dist/analysts/css-in-js/analysts/analyst-css-in-js.js +24 -17
  45. package/dist/analysts/css-in-js/corrections/correction-css-in-js.js +31 -16
  46. package/dist/analysts/css-in-js/detectors/detector-css-in-js-best-practices.js +28 -30
  47. package/dist/analysts/css-in-js/scorers/scorer-css-in-js.js +79 -54
  48. package/dist/analysts/css-in-js/shared.js +7 -0
  49. package/dist/analysts/detectors/detector-architecture.js +91 -85
  50. package/dist/analysts/detectors/detector-bugs-ml.js +29 -27
  51. package/dist/analysts/detectors/detector-code-fragile.js +41 -36
  52. package/dist/analysts/detectors/detector-dependencies.js +5 -5
  53. package/dist/analysts/detectors/detector-duplications.js +26 -26
  54. package/dist/analysts/detectors/detector-monorepo.js +51 -45
  55. package/dist/analysts/detectors/detector-performance.js +24 -17
  56. package/dist/analysts/detectors/detector-recommendation-architecture.js +40 -36
  57. package/dist/analysts/detectors/detector-security.js +43 -42
  58. package/dist/analysts/detectors/detector-structure.js +31 -28
  59. package/dist/analysts/github-actions/analysts/analyst-github-actions.js +5 -8
  60. package/dist/analysts/github-actions/detectors/detector-workflow-accessibility.js +1 -9
  61. package/dist/analysts/github-actions/detectors/detector-workflow-structure.js +1 -4
  62. package/dist/analysts/github-actions/detectors/detector-workflow-trigger-unsafe.js +6 -5
  63. package/dist/analysts/gitlab-ci/analysts/analyst-gitlab-ci.js +2 -2
  64. package/dist/analysts/gitlab-ci/detectors/detector-gitlab-ci-structure.js +0 -3
  65. package/dist/analysts/go/analysts/analyst-best-practices.js +2 -2
  66. package/dist/analysts/go/analysts/analyst-concurrency.js +1 -1
  67. package/dist/analysts/go/analysts/analyst-security.js +1 -1
  68. package/dist/analysts/go/detectors/detector-conventions.js +1 -1
  69. package/dist/analysts/html/analysts/analyst-html.js +10 -12
  70. package/dist/analysts/html/detectors/detector-html.js +3 -3
  71. package/dist/analysts/js-ts/analysts/analyst-commands-cli.js +22 -22
  72. package/dist/analysts/js-ts/analysts/analyst-functions-long.js +5 -5
  73. package/dist/analysts/js-ts/analysts/analyst-patterns-usage.js +6 -2
  74. package/dist/analysts/js-ts/detectors/detector-anti-patterns-async.js +84 -9
  75. package/dist/analysts/js-ts/detectors/detector-constructions-syntactic.js +33 -10
  76. package/dist/analysts/js-ts/detectors/detector-context-smart.js +6 -6
  77. package/dist/analysts/js-ts/detectors/detector-leaks-memory.js +1 -1
  78. package/dist/analysts/js-ts/detectors/detector-types-unsafe.js +33 -2
  79. package/dist/analysts/php/analysts/analyst-php.js +3 -3
  80. package/dist/analysts/php/detectors/detector-php-best-practices.js +5 -5
  81. package/dist/analysts/php/detectors/detector-php-security.js +5 -5
  82. package/dist/analysts/php/scorers/scorer-php.js +2 -2
  83. package/dist/analysts/plugins/detector-documentation.js +6 -6
  84. package/dist/analysts/plugins/detector-markdown.js +7 -7
  85. package/dist/analysts/python/analysts/analyst-python.js +2 -5
  86. package/dist/analysts/react/analysts/analyst-react-hooks.js +66 -9
  87. package/dist/analysts/react/analysts/analyst-react.js +46 -2
  88. package/dist/analysts/react/corrections/correction-react.js +41 -1
  89. package/dist/analysts/react/detectors/detector-react-best-practices.js +5 -5
  90. package/dist/analysts/react/scorers/scorer-react.js +36 -1
  91. package/dist/analysts/registry/autodiscovery.js +2 -2
  92. package/dist/analysts/rust/analysts/analyst-best-practices.js +42 -3
  93. package/dist/analysts/rust/analysts/analyst-memory.js +2 -2
  94. package/dist/analysts/rust/analysts/analyst-rust.js +52 -5
  95. package/dist/analysts/rust/analysts/analyst-security.js +29 -1
  96. package/dist/analysts/scorers/scorer.js +5 -5
  97. package/dist/analysts/shell/analysts/analyst-shell.js +81 -5
  98. package/dist/analysts/shell/corrections/correction-shell.js +34 -1
  99. package/dist/analysts/shell/detectors/detector-shell-security.js +88 -0
  100. package/dist/analysts/shell/scorers/scorer-shell.js +58 -1
  101. package/dist/analysts/strategists/operator-structure.js +5 -7
  102. package/dist/analysts/strategists/suggestions-contextuais.js +5 -2
  103. package/dist/analysts/svg/analysts/analyst-svg.js +1 -0
  104. package/dist/analysts/tailwind/analysts/analyst-tailwind.js +79 -55
  105. package/dist/analysts/tailwind/corrections/correction-tailwind.js +108 -9
  106. package/dist/analysts/tailwind/detectors/detector-tailwind-best-practices.js +122 -7
  107. package/dist/analysts/tailwind/scorers/scorer-tailwind.js +62 -11
  108. package/dist/analysts/xml/analysts/analyst-xml.js +2 -2
  109. package/dist/app/index.js +1 -0
  110. package/dist/bin/cli-bootstrap.js +6 -4
  111. package/dist/bin/index.js +6 -4
  112. package/dist/caretakers/scoring.js +1 -0
  113. package/dist/cli/commands/command-analysts.js +4 -3
  114. package/dist/cli/commands/command-azure.js +1 -1
  115. package/dist/cli/commands/command-circleci.js +1 -1
  116. package/dist/cli/commands/command-compliance.js +1 -1
  117. package/dist/cli/commands/command-diagnose.js +10 -13
  118. package/dist/cli/commands/command-fix-types.js +9 -32
  119. package/dist/cli/commands/command-formatters.js +2 -2
  120. package/dist/cli/commands/command-github-actions.js +1 -1
  121. package/dist/cli/commands/command-gitlab-ci.js +1 -1
  122. package/dist/cli/commands/command-guardian.js +1 -1
  123. package/dist/cli/commands/command-imports.js +6 -6
  124. package/dist/cli/commands/command-jenkins.js +1 -1
  125. package/dist/cli/commands/command-licenses.js +1 -1
  126. package/dist/cli/commands/command-marketplace.js +7 -7
  127. package/dist/cli/commands/command-names.js +3 -8
  128. package/dist/cli/commands/command-perf.js +7 -9
  129. package/dist/cli/commands/command-plugins.js +4 -4
  130. package/dist/cli/diagnostic/auto-fix.js +2 -2
  131. package/dist/cli/diagnostic/exporters/json-exporter.js +1 -1
  132. package/dist/cli/diagnostic/exporters/sharded-exporter.js +0 -3
  133. package/dist/cli/diagnostic/exporters/svg-optimization-exporter.js +1 -1
  134. package/dist/cli/diagnostic/filters.js +9 -9
  135. package/dist/cli/diagnostic/handlers/archetype-handler.js +3 -6
  136. package/dist/cli/diagnostic/handlers/auto-fix-handler.js +4 -4
  137. package/dist/cli/diagnostic/handlers/guardian-handler.js +1 -1
  138. package/dist/cli/diagnostic/processing-diagnostic.js +31 -35
  139. package/dist/cli/diagnostic/processing-helpers.js +2 -2
  140. package/dist/cli/handlers/fix-types-exporter.js +1 -4
  141. package/dist/cli/helpers/display-frame.js +5 -5
  142. package/dist/core/config/auto/auto-fix-config.js +0 -6
  143. package/dist/core/config/chalk-safe.js +6 -6
  144. package/dist/core/config/config.js +11 -13
  145. package/dist/core/config/conventions.js +1 -1
  146. package/dist/core/config/security.js +2 -2
  147. package/dist/core/execution/analysis-cache.js +5 -8
  148. package/dist/core/execution/ast-cache.js +1 -3
  149. package/dist/core/execution/executor.js +8 -21
  150. package/dist/core/execution/inquisitor.js +24 -21
  151. package/dist/core/execution/results.js +1 -0
  152. package/dist/core/execution/scanner.js +4 -4
  153. package/dist/core/messages/en/analysts/analyst-github-actions-messages.js +1 -1
  154. package/dist/core/messages/en/analysts/analyst-patterns-usage-messages.js +1 -0
  155. package/dist/core/messages/en/analysts/analyst-shell-messages.js +15 -0
  156. package/dist/core/messages/en/analysts/detector-constructions-syntactic-messages.js +6 -0
  157. package/dist/core/messages/en/analysts/detector-js-ts-messages.js +27 -0
  158. package/dist/core/messages/en/analysts/detector-react-messages.js +8 -0
  159. package/dist/core/messages/en/analysts/detector-shell-messages.js +17 -0
  160. package/dist/core/messages/en/analysts/detector-tailwind-messages.js +3 -3
  161. package/dist/core/messages/en/analysts/report-circleci-messages.js +7 -7
  162. package/dist/core/messages/en/caretakers/caretaker-messages.js +1 -7
  163. package/dist/core/messages/en/core/plugin-messages.js +31 -3
  164. package/dist/core/messages/en/log/log.js +4 -4
  165. package/dist/core/messages/en/ui/filter-config.js +1 -5
  166. package/dist/core/messages/i18n-system.js +3 -3
  167. package/dist/core/messages/index.js +3 -3
  168. package/dist/core/messages/ja/analysts/analyst-github-actions-messages.js +1 -1
  169. package/dist/core/messages/ja/analysts/analyst-patterns-usage-messages.js +1 -0
  170. package/dist/core/messages/ja/analysts/analyst-shell-messages.js +15 -0
  171. package/dist/core/messages/ja/analysts/detector-constructions-syntactic-messages.js +6 -0
  172. package/dist/core/messages/ja/analysts/detector-js-ts-messages.js +27 -0
  173. package/dist/core/messages/ja/analysts/detector-react-messages.js +8 -0
  174. package/dist/core/messages/ja/analysts/detector-shell-messages.js +17 -0
  175. package/dist/core/messages/ja/analysts/detector-tailwind-messages.js +3 -3
  176. package/dist/core/messages/ja/analysts/report-circleci-messages.js +7 -7
  177. package/dist/core/messages/ja/caretakers/caretaker-messages.js +1 -7
  178. package/dist/core/messages/ja/core/plugin-messages.js +31 -3
  179. package/dist/core/messages/ja/log/log.js +4 -4
  180. package/dist/core/messages/ja/ui/filter-config.js +1 -1
  181. package/dist/core/messages/pt/analysts/analyst-github-actions-messages.js +1 -1
  182. package/dist/core/messages/pt/analysts/analyst-patterns-usage-messages.js +1 -0
  183. package/dist/core/messages/pt/analysts/analyst-shell-messages.js +15 -0
  184. package/dist/core/messages/pt/analysts/detector-constructions-syntactic-messages.js +6 -0
  185. package/dist/core/messages/pt/analysts/detector-js-ts-messages.js +27 -0
  186. package/dist/core/messages/pt/analysts/detector-react-messages.js +8 -0
  187. package/dist/core/messages/pt/analysts/detector-shell-messages.js +17 -0
  188. package/dist/core/messages/pt/analysts/detector-tailwind-messages.js +3 -3
  189. package/dist/core/messages/pt/analysts/report-circleci-messages.js +7 -7
  190. package/dist/core/messages/pt/caretakers/caretaker-messages.js +1 -7
  191. package/dist/core/messages/pt/core/plugin-messages.js +31 -3
  192. package/dist/core/messages/pt/log/log-engine.js +6 -6
  193. package/dist/core/messages/pt/log/log.js +3 -3
  194. package/dist/core/messages/pt/ui/filter-config.js +1 -1
  195. package/dist/core/messages/shared/icons.js +3 -3
  196. package/dist/core/messages/zh/analysts/analyst-github-actions-messages.js +1 -1
  197. package/dist/core/messages/zh/analysts/analyst-patterns-usage-messages.js +1 -0
  198. package/dist/core/messages/zh/analysts/analyst-shell-messages.js +15 -0
  199. package/dist/core/messages/zh/analysts/detector-constructions-syntactic-messages.js +6 -0
  200. package/dist/core/messages/zh/analysts/detector-js-ts-messages.js +27 -0
  201. package/dist/core/messages/zh/analysts/detector-react-messages.js +8 -0
  202. package/dist/core/messages/zh/analysts/detector-shell-messages.js +17 -0
  203. package/dist/core/messages/zh/analysts/detector-tailwind-messages.js +3 -3
  204. package/dist/core/messages/zh/analysts/report-circleci-messages.js +7 -7
  205. package/dist/core/messages/zh/caretakers/caretaker-messages.js +1 -7
  206. package/dist/core/messages/zh/core/plugin-messages.js +31 -3
  207. package/dist/core/messages/zh/log/log.js +3 -3
  208. package/dist/core/messages/zh/ui/filter-config.js +1 -5
  209. package/dist/core/parsing/filters.js +3 -3
  210. package/dist/core/parsing/langs/json.js +1 -1
  211. package/dist/core/parsing/langs/python.js +1 -1
  212. package/dist/core/parsing/langs/typescript.js +1 -1
  213. package/dist/core/parsing/parser.js +3 -4
  214. package/dist/core/parsing/utils.js +1 -0
  215. package/dist/core/registry/file-registry.js +3 -2
  216. package/dist/core/registry/paths.js +3 -3
  217. package/dist/core/reporting/default-reporter.js +2 -2
  218. package/dist/core/schema/version.js +6 -6
  219. package/dist/core/workers/worker-executor.js +3 -3
  220. package/dist/core/workers/worker-pool.js +0 -0
  221. package/dist/guardian/baseline.js +1 -1
  222. package/dist/guardian/gpg.js +3 -1
  223. package/dist/guardian/integrity.js +2 -7
  224. package/dist/guardian/records.js +7 -1
  225. package/dist/guardian/result.js +1 -1
  226. package/dist/guardian/sentinel.js +7 -1
  227. package/dist/guardian/watcher-hidden.js +6 -1
  228. package/dist/licenses/fs-utils.js +5 -1
  229. package/dist/licenses/generate-notices.js +1 -1
  230. package/dist/licenses/index.js +1 -0
  231. package/dist/licenses/normalizer.js +10 -9
  232. package/dist/node.loader.js +224 -4
  233. package/dist/reports/analise-async-patterns.js +1 -1
  234. package/dist/reports/filter-smart.js +2 -5
  235. package/dist/reports/generator-report.js +7 -7
  236. package/dist/reports/report-archetypes.js +10 -10
  237. package/dist/reports/report-caretaker-health.js +2 -1
  238. package/dist/reports/report-patterns-usage.js +1 -1
  239. package/dist/sdk/analyzer.js +1 -1
  240. package/dist/shared/data-processing/fragment-report.js +11 -11
  241. package/dist/shared/data-processing/json.js +1 -1
  242. package/dist/shared/data-processing/occurrences.js +3 -2
  243. package/dist/shared/formatters/code-min-formatter.js +1 -1
  244. package/dist/shared/formatters/engines/prettier.js +1 -1
  245. package/dist/shared/formatters/engines/stylelint.js +43 -40
  246. package/dist/shared/formatters/formatter.js +8 -8
  247. package/dist/shared/formatters/formatters/code.js +3 -3
  248. package/dist/shared/formatters/formatters/css.js +2 -10
  249. package/dist/shared/formatters/formatters/dotfiles.js +1 -1
  250. package/dist/shared/formatters/formatters/html.js +1 -5
  251. package/dist/shared/formatters/formatters/json.js +0 -3
  252. package/dist/shared/formatters/formatters/markdown.js +19 -24
  253. package/dist/shared/formatters/formatters/properties.js +2 -2
  254. package/dist/shared/formatters/formatters/shell.js +1 -4
  255. package/dist/shared/formatters/formatters/sql.js +0 -3
  256. package/dist/shared/formatters/formatters/xml.js +5 -7
  257. package/dist/shared/formatters/formatters/yaml.js +2 -7
  258. package/dist/shared/formatters/index.js +1 -1
  259. package/dist/shared/helpers/framework-detector.js +6 -2
  260. package/dist/shared/helpers/json.js +1 -1
  261. package/dist/shared/helpers/magic-constants-whitelist.js +1 -1
  262. package/dist/shared/helpers/masking.js +17 -17
  263. package/dist/shared/helpers/reader-report.js +0 -12
  264. package/dist/shared/helpers/structural-hash.js +3 -2
  265. package/dist/shared/helpers/structure.js +1 -1
  266. package/dist/shared/marketplace/registry.js +1 -1
  267. package/dist/shared/marketplace/remote.js +4 -4
  268. package/dist/shared/persistence/persistence.js +13 -6
  269. package/dist/shared/plugins/core-plugin.js +5 -1
  270. package/dist/shared/plugins/registry.js +3 -2
  271. package/dist/types/analysts/tailwind-correction.js +2 -0
  272. package/dist/types/caretakers/imports-barrel.js +1 -0
  273. package/dist/types/caretakers/index.js +4 -0
  274. package/dist/types/caretakers/map-reversion.js +1 -0
  275. package/dist/types/caretakers/pruning.js +1 -0
  276. package/dist/types/caretakers/scoring.js +1 -0
  277. package/dist/types/common/analysts.js +1 -1
  278. package/dist/types/core/config/filters.js +1 -0
  279. package/dist/types/core/config/index.js +2 -0
  280. package/dist/types/core/execution/ambiente.js +1 -0
  281. package/dist/types/core/execution/linguagens.js +1 -0
  282. package/dist/types/core/execution/parse-errors.js +1 -0
  283. package/dist/types/core/execution/results.js +1 -0
  284. package/dist/types/core/execution/structure-json.js +1 -0
  285. package/dist/types/core/index.js +1 -0
  286. package/dist/types/core/messages/index.js +1 -0
  287. package/dist/types/core/messages/log.js +1 -0
  288. package/dist/types/core/parsing/babel-narrow.js +1 -0
  289. package/dist/types/core/parsing/index.js +1 -0
  290. package/dist/types/core/runtime.js +1 -0
  291. package/dist/types/guardian/index.js +2 -0
  292. package/dist/types/guardian/integrity.js +7 -0
  293. package/dist/types/guardian/snapshot.js +1 -0
  294. package/dist/types/index.js +4 -4
  295. package/dist/types/licenses/index.js +2 -0
  296. package/dist/types/processing/display.js +16 -13
  297. package/dist/types/processing/filters.js +8 -11
  298. package/dist/types/reports/compliance.js +1 -0
  299. package/dist/types/reports/streaming.js +1 -0
  300. package/dist/types/scripts/index.js +1 -0
  301. package/dist/types/scripts/migrar-aliases.js +1 -0
  302. package/dist/types/sdk/index.js +1 -0
  303. package/dist/types/shared/index.js +2 -0
  304. package/dist/types/vulnerabilities/index.js +2 -0
  305. package/dist/vulnerabilities/scanner.js +3 -2
  306. package/package.json +14 -20
package/README.md CHANGED
@@ -2,46 +2,12 @@
2
2
  Proveniência e Autoria: Este documento integra o projeto Mahoraga (licença MIT-0).
3
3
  ---
4
4
 
5
- <img src="./svg/banner-mahoraga.svg" width="100%">
6
-
7
- ---
8
-
9
5
  <div align="center">
10
6
 
11
- ![beta](./svg/badge-beta.svg)
12
- ![cobertura](./svg/badge-coverage.svg)
13
- ![mantido](./svg/badge-maintained.svg)
14
- ![pr-bem-vindo](./svg/badge-prs-welcome.svg)
15
- ![stavel](./svg/badge-stable.svg)
16
- ---
17
-
18
7
  <p><b>CLI modular para análise, diagnóstico e manutenção de projetos JavaScript/TypeScript com suporte multi-linguagem</b><p>
19
8
 
20
9
  </div>
21
10
 
22
- ---
23
-
24
- ## Índice
25
-
26
- - [Começar Rápido (30 segundos)](#começar-rápido-30-segundos)
27
- - [Fluxo Passo a Passo](#fluxo-passo-a-passo)
28
- - [Funcionalidades](#funcionalidades)
29
- - [Instalação](#instalação)
30
- - [Configuração](#configuração)
31
- - [Comandos da CLI](#comandos-da-cli)
32
- - [REST API](#rest-api)
33
- - [SDK Programático](#sdk-programático)
34
- - [GitHub App](#github-app)
35
- - [Editor (LSP / VSCode)](#editor-lsp--vscode)
36
- - [CI/CD](#cicd)
37
- - [Linguagens Suportadas](#linguagens-suportadas)
38
- - [Documentação Completa](#documentação-completa)
39
- - [Desenvolvimento](#desenvolvimento)
40
- - [Contribuir](#contribuir)
41
- - [Licença](#licença)
42
-
43
- ---
44
-
45
11
  ## Começar Rápido (30 segundos)
46
12
 
47
13
  ```bash
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import pLimit from 'p-limit';
4
4
  import { config } from '../../core/config/index.js';
5
5
  // Constantes para análise estrutural
6
- export const CONCORRENCIA = (config.STRUCTURE_CONCURRENCY ?? 5);
6
+ export const CONCORRENCIA = config.STRUCTURE_CONCURRENCY;
7
7
  export const CAMADAS = {
8
8
  ts: 'src',
9
9
  js: 'src',
@@ -17,27 +17,27 @@ export const CAMADAS = {
17
17
  yaml: 'config',
18
18
  // Adicione mais mapeamentos conforme necessário
19
19
  };
20
+ function determinarCamadaIdeal(entry) {
21
+ const rel = entry.relPath;
22
+ const normalizado = rel.replace(/\\/g, '/');
23
+ const atual = normalizado.split('/')[0] || '';
24
+ let ideal = null;
25
+ const matchDireta = Object.entries(CAMADAS).find(([, dir]) => normalizado.startsWith(`${dir.replace(/\\/g, '/')}/`));
26
+ if (matchDireta) {
27
+ ideal = matchDireta[1];
28
+ }
29
+ else {
30
+ const nome = path.basename(rel);
31
+ const [, tipo] = /\.([^.]+)\.[^.]+$/.exec(nome) ?? [];
32
+ if (tipo && CAMADAS[tipo]) {
33
+ ideal = CAMADAS[tipo];
34
+ }
35
+ }
36
+ return { arquivo: rel, atual, ideal };
37
+ }
20
38
  export async function analisarEstrutura(fileEntries, _baseDir = process.cwd()) {
21
39
  const limit = pLimit(CONCORRENCIA);
22
- const resultados = await Promise.all(fileEntries.map((entry) => limit(() => {
23
- const rel = entry.relPath;
24
- // Normaliza para separador POSIX para evitar dependência de platform e necessidade de mock em testes
25
- const normalizado = rel.replace(/\\/g, '/');
26
- const atual = normalizado.split('/')[0] || '';
27
- let ideal = null;
28
- const matchDireta = Object.entries(CAMADAS).find(([, dir]) => normalizado.startsWith(`${dir.replace(/\\/g, '/')}/`));
29
- if (matchDireta) {
30
- ideal = matchDireta[1];
31
- }
32
- else {
33
- const nome = path.basename(rel);
34
- const [, tipo] = /\.([^.]+)\.[^.]+$/.exec(nome) ?? [];
35
- if (tipo && CAMADAS[tipo]) {
36
- ideal = CAMADAS[tipo];
37
- }
38
- }
39
- return { arquivo: rel, atual, ideal };
40
- })));
40
+ const resultados = await Promise.all(fileEntries.map((entry) => limit(() => determinarCamadaIdeal(entry))));
41
41
  return resultados;
42
42
  }
43
43
  export { analisarEstrutura as alinhamentoEstrutural };
@@ -19,6 +19,13 @@ import { lerEstado, salvarEstado } from '../../shared/persistence/index.js';
19
19
  const { log, ArquetiposExtraMensagens } = getMessages();
20
20
  // Nome do arquivo legado (para compatibilidade)
21
21
  const ARQUETIPO_PERSONALIZADO_FILENAME = 'mahoraga.repo.arquetipo.json';
22
+ function logVerbose(fn) {
23
+ const isTest = (process.env.VITEST ?? '') !== '';
24
+ const isVerbose = log.verbose ?? false;
25
+ if (!isTest && isVerbose) {
26
+ fn();
27
+ }
28
+ }
22
29
  /**
23
30
  * Carrega o arquétipo personalizado do projeto atual
24
31
  * Tenta primeiro o novo caminho (.mahoraga/estrutura.arquetipo.json),
@@ -38,12 +45,7 @@ export async function carregarArquetipoPersonalizado(baseDir = process.cwd()) {
38
45
  const arquetipoLegado = await lerEstado(caminhoLegado, null);
39
46
  // Validação básica
40
47
  if (!arquetipoLegado?.nome || !arquetipoLegado.arquetipoOficial) {
41
- // Reduz ruído em testes e quando não estiver em modo verbose
42
- const isTest = (process.env.VITEST ?? '') !== '';
43
- const isVerbose = log.verbose ?? false;
44
- if (!isTest && isVerbose) {
45
- log.aviso(ArquetiposExtraMensagens.naoEncontrado.replace('{novo}', novoCaminho).replace('{legado}', caminhoLegado));
46
- }
48
+ logVerbose(() => { log.aviso(ArquetiposExtraMensagens.naoEncontrado.replace('{novo}', novoCaminho).replace('{legado}', caminhoLegado)); });
47
49
  return null;
48
50
  }
49
51
  return arquetipoLegado;
@@ -105,8 +107,8 @@ export async function existeArquetipoPersonalizado(baseDir = process.cwd()) {
105
107
  * Obtém o arquétipo oficial base para um arquétipo personalizado
106
108
  */
107
109
  export function obterArquetipoOficial(arquetipoPersonalizado) {
108
- const nomeOficial = arquetipoPersonalizado.arquetipoOficial ?? '';
109
- const encontrado = ARQUETIPOS.find((arq) => arq.nome === nomeOficial);
110
+ const nomeOficial = arquetipoPersonalizado.arquetipoOficial;
111
+ const encontrado = ARQUETIPOS?.find((arq) => arq.nome === nomeOficial);
110
112
  return encontrado ?? null;
111
113
  }
112
114
  /**
@@ -209,21 +211,16 @@ export function validarArquetipoPersonalizado(arquetipo) {
209
211
  }
210
212
  else {
211
213
  // Verifica se o arquétipo oficial existe
212
- const arquetipoOficial = ARQUETIPOS.find((arq) => arq.nome === arquetipo.arquetipoOficial);
214
+ const arquetipoOficial = ARQUETIPOS?.find((arq) => arq.nome === arquetipo.arquetipoOficial);
213
215
  if (!arquetipoOficial) {
214
- erros.push(ArquetiposExtraMensagens.validacao.arquetipoNaoEncontrado.replace('{arquetipo}', arquetipo.arquetipoOficial).replace('{disponiveis}', (ARQUETIPOS ?? []).map(arquivo => (arquivo).nome).join(', ')));
216
+ erros.push(ArquetiposExtraMensagens.validacao.arquetipoNaoEncontrado.replace('{arquetipo}', arquetipo.arquetipoOficial).replace('{disponiveis}', ARQUETIPOS.map(arquivo => (arquivo).nome).join(', ')));
215
217
  }
216
218
  }
217
- if (!arquetipo.estruturaPersonalizada) {
218
- erros.push(ArquetiposExtraMensagens.validacao.estruturaObrigatoria);
219
+ if (!Array.isArray(arquetipo.estruturaPersonalizada.diretorios)) {
220
+ erros.push(ArquetiposExtraMensagens.validacao.diretoriosArray);
219
221
  }
220
- else {
221
- if (!Array.isArray(arquetipo.estruturaPersonalizada.diretorios)) {
222
- erros.push(ArquetiposExtraMensagens.validacao.diretoriosArray);
223
- }
224
- if (!Array.isArray(arquetipo.estruturaPersonalizada.arquivosChave)) {
225
- erros.push(ArquetiposExtraMensagens.validacao.arquivosChaveArray);
226
- }
222
+ if (!Array.isArray(arquetipo.estruturaPersonalizada.arquivosChave)) {
223
+ erros.push(ArquetiposExtraMensagens.validacao.arquivosChaveArray);
227
224
  }
228
225
  return {
229
226
  valido: erros.length === 0,
@@ -41,6 +41,34 @@ if (process.env.VITEST) {
41
41
  scoreArquetipo
42
42
  };
43
43
  }
44
+ function aplicarBoostConfianca(candidato, arquetiposCandidatos, melhorDeteccao) {
45
+ if (arquetiposCandidatos.some((arq) => candidato.nome.includes(arq) || arq.includes(candidato.nome))) {
46
+ const boostConfianca = Math.min(melhorDeteccao.confiancaTotal * 100 * 0.8, 60);
47
+ return {
48
+ ...candidato,
49
+ confidence: Math.max(candidato.confidence + boostConfianca, 70),
50
+ explicacaoSimilaridade: `[Boost contextual: ${melhorDeteccao.tecnologia} detectado com ${(melhorDeteccao.confiancaTotal * 100).toFixed(0)}% confiança] ${candidato.explicacaoSimilaridade ?? ''}`
51
+ };
52
+ }
53
+ return candidato;
54
+ }
55
+ function criarArquetipoVirtual(melhorDeteccao, tecnologiaDetectada) {
56
+ return {
57
+ nome: tecnologiaDetectada,
58
+ score: Math.round(melhorDeteccao.confiancaTotal * 100),
59
+ confidence: Math.round(melhorDeteccao.confiancaTotal * 100),
60
+ matchedRequired: [],
61
+ missingRequired: [],
62
+ matchedOptional: [],
63
+ dependencyMatches: (melhorDeteccao.evidencias ?? []).filter(erro => erro.tipo === 'dependencia').map(erro => erro.valor),
64
+ filePadraoMatches: (melhorDeteccao.evidencias ?? []).filter(erro => erro.tipo === 'estrutura').map(erro => erro.valor),
65
+ forbiddenPresent: [],
66
+ anomalias: [],
67
+ sugestaoPadronizacao: (melhorDeteccao.sugestoesMelhoria ?? []).join('; '),
68
+ explicacaoSimilaridade: `Detectado via sistema inteligente contextual com ${(melhorDeteccao.confiancaTotal * 100).toFixed(0)}% confiança`,
69
+ descricao: `Projeto ${melhorDeteccao.tecnologia} identificado por análise contextual`
70
+ };
71
+ }
44
72
  export async function detectarArquetipos(contexto, baseDir, options) {
45
73
  if (!options?.quiet && config.VERBOSE) {
46
74
  console.log(DetectorArquetiposExtraMensagens.debugChamado, contexto.arquivos.length, 'arquivos');
@@ -91,7 +119,7 @@ export async function detectarArquetipos(contexto, baseDir, options) {
91
119
  const melhorDeteccao = resultadosContextuais.reduce((melhor, atual) => atual.confiancaTotal > melhor.confiancaTotal ? atual : melhor, {
92
120
  confiancaTotal: 0
93
121
  });
94
- if (melhorDeteccao && melhorDeteccao.confiancaTotal > 0.6) {
122
+ if (melhorDeteccao.confiancaTotal > 0.6) {
95
123
  // Escala 0-1, não 0-100
96
124
  // Mapear tecnologias detectadas para arquétipos conhecidos
97
125
  const mapeamentoTecnologia = {
@@ -106,40 +134,19 @@ export async function detectarArquetipos(contexto, baseDir, options) {
106
134
  'react-spa': ['react-spa', 'react', 'spa']
107
135
  };
108
136
  const tecnologiaDetectada = melhorDeteccao.tecnologia ?? 'desconhecido';
109
- const arquetiposCandidatos = mapeamentoTecnologia[tecnologiaDetectada] || [];
110
- // Aplicar boost de confiança para arquétipos relacionados
111
- let boostAplicado = false;
112
- candidatos = candidatos.map((candidato) => {
113
- if (arquetiposCandidatos.some((arq) => candidato.nome.includes(arq) || arq.includes(candidato.nome))) {
114
- const boostConfianca = Math.min(melhorDeteccao.confiancaTotal * 100 * 0.8, 60); // Boost agressivo até 60%
115
- boostAplicado = true;
116
- return {
117
- ...candidato,
118
- confidence: Math.max(candidato.confidence + boostConfianca, 70),
119
- // Mínimo 70% se detectado
120
- explicacaoSimilaridade: `[Boost contextual: ${melhorDeteccao.tecnologia} detectado com ${(melhorDeteccao.confiancaTotal * 100).toFixed(0)}% confiança] ${candidato.explicacaoSimilaridade ?? ''}`
121
- };
137
+ const arquetiposCandidatos = mapeamentoTecnologia[tecnologiaDetectada];
138
+ if (!arquetiposCandidatos) {
139
+ if (!options?.quiet && config.VERBOSE) {
140
+ console.log(`[AVISO] Tecnologia detectada "${tecnologiaDetectada}" não mapeada para nenhum arquétipo.`);
141
+ }
142
+ }
143
+ else {
144
+ // Aplicar boost de confiança para arquétipos relacionados
145
+ const boostAplicado = candidatos.some((candidato) => arquetiposCandidatos.some((arq) => candidato.nome.includes(arq) || arq.includes(candidato.nome)));
146
+ candidatos = candidatos.map((candidato) => aplicarBoostConfianca(candidato, arquetiposCandidatos, melhorDeteccao));
147
+ if (!boostAplicado) {
148
+ candidatos.unshift(criarArquetipoVirtual(melhorDeteccao, tecnologiaDetectada));
122
149
  }
123
- return candidato;
124
- });
125
- // Se não encontrou arquétipo compatível, criar um virtual baseado na detecção
126
- if (!boostAplicado) {
127
- const arquetipoVirtual = {
128
- nome: tecnologiaDetectada,
129
- score: Math.round(melhorDeteccao.confiancaTotal * 100),
130
- confidence: Math.round(melhorDeteccao.confiancaTotal * 100),
131
- matchedRequired: [],
132
- missingRequired: [],
133
- matchedOptional: [],
134
- dependencyMatches: (melhorDeteccao.evidencias ?? []).filter(erro => erro.tipo === 'dependencia').map(erro => erro.valor),
135
- filePadraoMatches: (melhorDeteccao.evidencias ?? []).filter(erro => erro.tipo === 'estrutura').map(erro => erro.valor),
136
- forbiddenPresent: [],
137
- anomalias: [],
138
- sugestaoPadronizacao: (melhorDeteccao.sugestoesMelhoria ?? []).join('; '),
139
- explicacaoSimilaridade: `Detectado via sistema inteligente contextual com ${(melhorDeteccao.confiancaTotal * 100).toFixed(0)}% confiança`,
140
- descricao: `Projeto ${melhorDeteccao.tecnologia} identificado por análise contextual`
141
- };
142
- candidatos.unshift(arquetipoVirtual); // Adiciona no início
143
150
  }
144
151
  }
145
152
  }
@@ -211,7 +218,7 @@ export async function detectarArquetipos(contexto, baseDir, options) {
211
218
  const baselineCaminho = path.join(baseDir, '.mahoraga', 'baseline-estrutura.json');
212
219
  let baseline;
213
220
  const existente = await lerEstado(baselineCaminho);
214
- if (existente && !Array.isArray(existente) && typeof existente === 'object' && 'arquetipo' in existente) {
221
+ if (!Array.isArray(existente) && typeof existente === 'object' && 'arquetipo' in existente) {
215
222
  baseline = existente;
216
223
  }
217
224
  if (!baseline && candidatos[0]) {
@@ -227,7 +234,7 @@ export async function detectarArquetipos(contexto, baseDir, options) {
227
234
  // Prioriza baseline apenas se o candidato principal for 'desconhecido' ou confiança baixa
228
235
  if (baseline && baseline.arquetipo !== 'desconhecido') {
229
236
  const arquivosRaizAtuais = arquivos.filter(caminho => !caminho.includes('/'));
230
- const setBase = new Set(baseline.arquivosRaiz || []);
237
+ const setBase = new Set(baseline.arquivosRaiz);
231
238
  const temIntersecao = arquivosRaizAtuais.some(arquivo => setBase.has(arquivo));
232
239
  const candidatoTop = candidatos[0];
233
240
  if (temIntersecao && (candidatoTop.nome === 'desconhecido' || candidatoTop.confidence < 50)) {
@@ -94,7 +94,7 @@ export function detectarArquetipo(arquivos) {
94
94
  const filtrados = apenasPenalidades.filter(elem => {
95
95
  // Regra específica: se o candidato for 'monorepo-packages' e o único forbidden detectado for 'src', descartamos
96
96
  if (elem.nome === 'monorepo-packages') {
97
- const forb = elem.forbiddenPresent || [];
97
+ const forb = elem.forbiddenPresent;
98
98
  if (forb.length === 1 && forb[0] === 'src') {
99
99
  return false;
100
100
  }
@@ -110,8 +110,8 @@ export function detectarArquetipo(arquivos) {
110
110
  const forbA = arquivo.forbiddenPresent.length || 0;
111
111
  const forbB = base.forbiddenPresent.length || 0;
112
112
  // Usa somente o total de diretórios proibidos definidos no alvo para o ratio
113
- const defA = ARQUETIPOS.find((diretorio) => diretorio.nome === arquivo.nome);
114
- const defB = ARQUETIPOS.find((diretorio) => diretorio.nome === base.nome);
113
+ const defA = ARQUETIPOS?.find((diretorio) => diretorio.nome === arquivo.nome);
114
+ const defB = ARQUETIPOS?.find((diretorio) => diretorio.nome === base.nome);
115
115
  const totA = defA?.forbiddenDirs?.length ?? 0;
116
116
  const totB = defB?.forbiddenDirs?.length ?? 0;
117
117
  const ratioA = totA > 0 ? forbA / totA : 0;
@@ -5,7 +5,7 @@ _sinaisAvancados // prefixo _ para ignorar warning de unused
5
5
  // Implementação fictícia para evitar erro de compilação
6
6
  return {
7
7
  nome: def.nome,
8
- descricao: def.descricao ?? '',
8
+ descricao: def.descricao,
9
9
  score: 0,
10
10
  confidence: 0,
11
11
  matchedRequired: [],
@@ -17,6 +17,28 @@ _sinaisAvancados // prefixo _ para ignorar warning de unused
17
17
  anomalias: []
18
18
  };
19
19
  }
20
+ function processarImportsFramework(imports, tecnologias, sinais) {
21
+ for (const indice of imports) {
22
+ if (typeof indice.source.value === 'string') {
23
+ const importSource = indice.source.value.toLowerCase();
24
+ if (importSource.includes('react') || importSource.includes('vue') || importSource.includes('angular')) {
25
+ tecnologias.set('frontend-framework', (tecnologias.get('frontend-framework') ?? 0) + 1);
26
+ }
27
+ if (importSource.includes('express') || importSource.includes('fastify') || importSource.includes('nestjs')) {
28
+ tecnologias.set('backend-framework', (tecnologias.get('backend-framework') ?? 0) + 1);
29
+ }
30
+ if (importSource.includes('prisma') || importSource.includes('mongoose') || importSource.includes('typeorm')) {
31
+ tecnologias.set('orm', (tecnologias.get('orm') ?? 0) + 1);
32
+ }
33
+ if (importSource.includes('jest') || importSource.includes('vitest') || importSource.includes('mocha')) {
34
+ tecnologias.set('testing-framework', (tecnologias.get('testing-framework') ?? 0) + 1);
35
+ }
36
+ if (/express|react|next|electron|discord\.js|telegraf/.test(importSource)) {
37
+ sinais.frameworksDetectados.push(indice.source.value);
38
+ }
39
+ }
40
+ }
41
+ }
20
42
  export function extrairSinaisAvancados(fileEntries, packageJson, _p0, _baseDir, _arquivos) {
21
43
  // Auxiliar para checar se o nó possui id.name string
22
44
  const hasIdNome = (node) => {
@@ -45,8 +67,8 @@ export function extrairSinaisAvancados(fileEntries, packageJson, _p0, _baseDir,
45
67
  const tecnologias = new Map();
46
68
  for (const fe of fileEntries) {
47
69
  let body = [];
48
- if (fe.ast && 'node' in fe.ast && fe.ast.node && fe.ast.node.type === 'Program' && Array.isArray(fe.ast.node.body)) {
49
- body = fe.ast.node.body;
70
+ if (fe.ast && 'node' in fe.ast && Array.isArray(fe.ast.node.body)) {
71
+ body = (fe.ast.node).body;
50
72
  }
51
73
  // Análise inteligente de padrões
52
74
  const conteudo = fe.content ?? '';
@@ -134,31 +156,7 @@ export function extrairSinaisAvancados(fileEntries, packageJson, _p0, _baseDir,
134
156
  // Classes
135
157
  sinais.classes += body.filter((node) => node.type === 'ClassDeclaration').length;
136
158
  // Frameworks por import (expandido)
137
- for (const indice of imports) {
138
- if (typeof indice.source.value === 'string') {
139
- const importSource = indice.source.value.toLowerCase();
140
- // Frameworks web
141
- if (importSource.includes('react') || importSource.includes('vue') || importSource.includes('angular')) {
142
- tecnologias.set('frontend-framework', (tecnologias.get('frontend-framework') ?? 0) + 1);
143
- }
144
- // Frameworks backend
145
- if (importSource.includes('express') || importSource.includes('fastify') || importSource.includes('nestjs')) {
146
- tecnologias.set('backend-framework', (tecnologias.get('backend-framework') ?? 0) + 1);
147
- }
148
- // ORMs
149
- if (importSource.includes('prisma') || importSource.includes('mongoose') || importSource.includes('typeorm')) {
150
- tecnologias.set('orm', (tecnologias.get('orm') ?? 0) + 1);
151
- }
152
- // Testing
153
- if (importSource.includes('jest') || importSource.includes('vitest') || importSource.includes('mocha')) {
154
- tecnologias.set('testing-framework', (tecnologias.get('testing-framework') ?? 0) + 1);
155
- }
156
- // Lista original mantida
157
- if (/express|react|next|electron|discord\.js|telegraf/.test(importSource)) {
158
- sinais.frameworksDetectados.push(indice.source.value);
159
- }
160
- }
161
- }
159
+ processarImportsFramework(imports, tecnologias, sinais);
162
160
  // Padrões de pastas/arquivos (expandido)
163
161
  const rel = fe.relPath.replace(/\\/g, '/');
164
162
  if (/src\/controllers|pages|api|prisma|packages|apps|src\/routes|src\/services|src\/repositories/.test(rel)) {
@@ -22,8 +22,8 @@ export function extrairSinaisProjeto(fileEntries, packageJson) {
22
22
  };
23
23
  for (const fe of fileEntries) {
24
24
  let body = [];
25
- if (fe.ast && 'node' in fe.ast && fe.ast.node && fe.ast.node.type === 'Program' && Array.isArray(fe.ast.node.body)) {
26
- body = fe.ast.node.body;
25
+ if (fe.ast && 'node' in fe.ast && Array.isArray(fe.ast.node.body)) {
26
+ body = (fe.ast.node).body;
27
27
  }
28
28
  // Funções
29
29
  sinais.funcoes += body.filter((node) => node.type === 'FunctionDeclaration').length;
@@ -3,15 +3,52 @@ import { statSync } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { getTypesDirectoryRelPosix } from '../../core/config/index.js';
5
5
  import { carregarConfigEstrategia, destinoPara, deveIgnorar, normalizarRel } from '../../shared/helpers/index.js';
6
- /**
7
- * Estrategista/Planejador de Estrutura
8
- *
9
- * Responsável por: dado o conjunto de arquivos e um catálogo de arquétipos,
10
- * sugerir um plano de reorganização (mover arquivos) com base em regras de nomeação
11
- * e diretórios-alvo padronizados. Não aplica mudanças no disco (apenas sugere).
12
- *
13
- * Domínio ideal: arquitetos (diagnóstico/planejamento). A execução fica com zeladores.
14
- */
6
+ function processarArquivoParaMovimento(rel, cfg, baseDir, sinaisAvancados, rels, mover, conflitos) {
7
+ if (deveIgnorar(rel, cfg.ignorarPastas)) {
8
+ return;
9
+ }
10
+ if (/__(tests|mocks)__/.test(rel) || /\.(test|spec)\.[jt]sx?$/.test(rel) || /fixtures\//.test(rel)) {
11
+ return;
12
+ }
13
+ if (!rel.endsWith('.ts') && !rel.endsWith('.js')) {
14
+ return;
15
+ }
16
+ const base = path.posix.basename(rel);
17
+ if (/^(eslint|vitest|next|tailwind|postcss|prettier|jest)\.config\.[jt]s$/i.test(base)) {
18
+ return;
19
+ }
20
+ const res = destinoPara(rel, cfg.raizCodigo, cfg.criarSubpastasPorEntidade, cfg.apenasCategoriasConfiguradas, cfg.categoriasMapa);
21
+ if (!res.destinoDir) {
22
+ return;
23
+ }
24
+ const currentDir = path.posix.dirname(rel);
25
+ const alreadyInTarget = currentDir === res.destinoDir || currentDir.startsWith(`${res.destinoDir}/`);
26
+ if (alreadyInTarget) {
27
+ return;
28
+ }
29
+ let destinoDirAjustado = res.destinoDir;
30
+ const motivoAjustado = res.motivo ?? 'Reorganização padrão';
31
+ if (sinaisAvancados) {
32
+ destinoDirAjustado = ajustarDestinoPorSinais(rel, res.destinoDir, sinaisAvancados, motivoAjustado);
33
+ }
34
+ const destino = path.posix.join(destinoDirAjustado, path.posix.basename(rel));
35
+ let destinoExiste = rels.includes(destino);
36
+ if (!destinoExiste) {
37
+ try {
38
+ const abs = path.join(baseDir, destino.replace(/\\/g, '/'));
39
+ statSync(abs);
40
+ destinoExiste = true;
41
+ }
42
+ catch {
43
+ destinoExiste = false;
44
+ }
45
+ }
46
+ if (destinoExiste) {
47
+ conflitos.push({ alvo: destino, motivo: 'destino já existe' });
48
+ return;
49
+ }
50
+ mover.push({ de: rel, para: destino, motivo: motivoAjustado });
51
+ }
15
52
  export async function gerarPlanoEstrategico(contexto, opcoes = {}, sinaisAvancados) {
16
53
  const typesDir = getTypesDirectoryRelPosix();
17
54
  const cfg = await carregarConfigEstrategia(contexto.baseDir, {
@@ -24,63 +61,7 @@ export async function gerarPlanoEstrategico(contexto, opcoes = {}, sinaisAvancad
24
61
  const rels = contexto.arquivos.map(arquivo => normalizarRel(arquivo.relPath));
25
62
  const isTestLike = (caminho) => /__(tests|mocks)__/.test(caminho) || /\.(test|spec)\.[jt]sx?$/.test(caminho) || /fixtures\//.test(caminho);
26
63
  for (const rel of rels) {
27
- if (deveIgnorar(rel, cfg.ignorarPastas)) {
28
- continue;
29
- }
30
- if (isTestLike(rel)) {
31
- continue;
32
- } // não mover testes/fixtures
33
- // Evitar mexer em arquivos fora do escopo de código (por agora)
34
- if (!rel.endsWith('.ts') && !rel.endsWith('.js')) {
35
- continue;
36
- }
37
- // Respeita convenções de ferramentas no root: não mover configs globais
38
- const base = path.posix.basename(rel);
39
- if (/^(eslint|vitest|next|tailwind|postcss|prettier|jest)\.config\.[jt]s$/i.test(base)) {
40
- continue;
41
- }
42
- const res = destinoPara(rel, cfg.raizCodigo, cfg.criarSubpastasPorEntidade, cfg.apenasCategoriasConfiguradas, cfg.categoriasMapa);
43
- if (!res.destinoDir) {
44
- continue;
45
- }
46
- const currentDir = path.posix.dirname(rel);
47
- const alreadyInTarget = currentDir === res.destinoDir || currentDir.startsWith(`${res.destinoDir}/`);
48
- if (alreadyInTarget) {
49
- continue;
50
- }
51
- // [LANCAMENTO] INTELIGÊNCIA CONTEXTUAL: Ajustar destino baseado em sinais avançados
52
- let destinoDirAjustado = res.destinoDir;
53
- const motivoAjustado = res.motivo ?? 'Reorganização padrão';
54
- if (sinaisAvancados) {
55
- destinoDirAjustado = ajustarDestinoPorSinais(rel, res.destinoDir, sinaisAvancados, motivoAjustado);
56
- }
57
- // Mantém o mesmo nome do arquivo; apenas move para pasta de destino
58
- const destino = path.posix.join(destinoDirAjustado, path.posix.basename(rel));
59
- // Conflito se já existe arquivo listado ou presente no filesystem
60
- let destinoExiste = rels.includes(destino);
61
- if (!destinoExiste) {
62
- try {
63
- const abs = path.join(contexto.baseDir, destino.replace(/\\/g, '/'));
64
- // fs.statSync usado de forma segura; se falhar, considera inexistente
65
- statSync(abs);
66
- destinoExiste = true;
67
- }
68
- catch {
69
- destinoExiste = false;
70
- }
71
- }
72
- if (destinoExiste) {
73
- conflitos.push({
74
- alvo: destino,
75
- motivo: 'destino já existe'
76
- });
77
- continue;
78
- }
79
- mover.push({
80
- de: rel,
81
- para: destino,
82
- motivo: motivoAjustado
83
- });
64
+ processarArquivoParaMovimento(rel, cfg, contexto.baseDir, sinaisAvancados, rels, mover, conflitos);
84
65
  }
85
66
  // Deduplicação simples
86
67
  const seen = new Set();
@@ -11,6 +11,21 @@ export function registrarDetectorAzure(detector) {
11
11
  export function obterDetectoresAzure() {
12
12
  return [...detectoresRegistrados];
13
13
  }
14
+ function processarResultadosPlugins(plugResults, ocorrencias, relPath) {
15
+ for (const results of plugResults) {
16
+ for (const item of results) {
17
+ ocorrencias.push({
18
+ tipo: `AZURE_${item.tipo.toUpperCase().replace(/-/g, '_')}`,
19
+ mensagem: item.descricao,
20
+ relPath,
21
+ linha: item.linha ?? 1,
22
+ coluna: 1,
23
+ sugestao: item.sugestao ?? '',
24
+ nivel: item.severidade === 'critica' || item.severidade === 'alta' ? 'erro' : item.severidade === 'media' ? 'aviso' : 'info',
25
+ });
26
+ }
27
+ }
28
+ }
14
29
  export const analistaAzurePipelines = {
15
30
  nome: 'azure-pipelines',
16
31
  categoria: 'workflows',
@@ -23,53 +38,44 @@ export const analistaAzurePipelines = {
23
38
  const securityResults = await Promise.resolve(detectorAzureSecurity.aplicar(conteudo, relPath, null, _fc, contexto));
24
39
  const performanceResults = await Promise.resolve(detectorAzurePerformance.aplicar(conteudo, relPath, null, _fc, contexto));
25
40
  const estruturaResults = await Promise.resolve(detectorAzureEstrutura.aplicar(conteudo, relPath, null, _fc, contexto));
26
- ocorrencias.push(...securityResults, ...performanceResults, ...estruturaResults);
41
+ for (const r of [securityResults, performanceResults, estruturaResults]) {
42
+ if (r) {
43
+ ocorrencias.push(...(Array.isArray(r) ? r : [r]));
44
+ }
45
+ }
27
46
  // 2. Análise Estrutural básica
28
47
  const doc = parseDocument(conteudo);
29
48
  const configData = doc.toJS();
30
- if (configData) {
31
- // Verificar versão antiga (v0.x)
32
- if (configData.version && parseFloat(String(configData.version)) < 1.0) {
49
+ // Verificar versão antiga (v0.x)
50
+ const version = configData.version;
51
+ if ((typeof version === 'string' || typeof version === 'number') && parseFloat(String(version)) < 1.0) {
52
+ ocorrencias.push({
53
+ tipo: 'AZURE_OBSOLETE_VERSION',
54
+ mensagem: 'Versão do schema do Azure Pipelines está obsoleta',
55
+ relPath,
56
+ linha: 1,
57
+ nivel: 'aviso',
58
+ sugestao: 'Remova o campo "version" para usar o schema YAML moderno',
59
+ });
60
+ }
61
+ // Detectar excesso de variáveis globais
62
+ if (configData.variables && typeof configData.variables === 'object') {
63
+ const varCount = Object.keys(configData.variables).length;
64
+ if (varCount > 20) {
33
65
  ocorrencias.push({
34
- tipo: 'AZURE_OBSOLETE_VERSION',
35
- mensagem: 'Versão do schema do Azure Pipelines está obsoleta',
66
+ tipo: 'AZURE_TOO_MANY_VARIABLES',
67
+ mensagem: messages.RelatorioAzureMensagens.tooManyVariables,
36
68
  relPath,
37
69
  linha: 1,
38
- nivel: 'aviso',
39
- sugestao: 'Remova o campo "version" para usar o schema YAML moderno',
70
+ nivel: 'info',
71
+ sugestao: messages.RelatorioAzureMensagens.tooManyVariablesSugestao,
40
72
  });
41
73
  }
42
- // Detectar excesso de variáveis globais
43
- if (configData.variables && typeof configData.variables === 'object') {
44
- const varCount = Object.keys(configData.variables).length;
45
- if (varCount > 20) {
46
- ocorrencias.push({
47
- tipo: 'AZURE_TOO_MANY_VARIABLES',
48
- mensagem: messages.RelatorioAzureMensagens.tooManyVariables,
49
- relPath,
50
- linha: 1,
51
- nivel: 'info',
52
- sugestao: messages.RelatorioAzureMensagens.tooManyVariablesSugestao,
53
- });
54
- }
55
- }
56
74
  }
57
75
  // 3. Plugins registrados
58
76
  const caminhos = contexto?.arquivos.map(arquivo => arquivo.relPath) ?? [];
59
77
  const plugResults = await Promise.all(detectoresRegistrados.map(detector => Promise.resolve(detector.testar(configData, { conteudo, caminhos })).catch(() => [])));
60
- for (const results of plugResults) {
61
- for (const item of results) {
62
- ocorrencias.push({
63
- tipo: `AZURE_${item.tipo.toUpperCase().replace(/-/g, '_')}`,
64
- mensagem: item.descricao,
65
- relPath,
66
- linha: item.linha ?? 1,
67
- coluna: 1,
68
- sugestao: item.sugestao ?? '',
69
- nivel: item.severidade === 'critica' || item.severidade === 'alta' ? 'erro' : item.severidade === 'media' ? 'aviso' : 'info',
70
- });
71
- }
72
- }
78
+ processarResultadosPlugins(plugResults, ocorrencias, relPath);
73
79
  }
74
80
  catch {
75
81
  // Falha silenciosa no parse