@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
@@ -4,11 +4,28 @@
4
4
  // em expressões regulares de detecção, gerando falso positivo em auto-análise.
5
5
  import { getMessages } from '../../../core/messages/index.js';
6
6
  import { splitLines } from '../../../shared/helpers/index.js';
7
+ import { IMPORTANT_PATTERN } from '../shared.js';
7
8
  import { criarOcorrencia } from '../../../types/index.js';
8
9
  const STYLED_PATTERN = /styled\s*(\.|\()`|css\s*`|css\(|StyleSheet\.create|makeStyles|useStyles|createStyles|withStyles/;
9
- const THEME_PATTERN = /useTheme|ThemeProvider|withTheme|theme\s*\.|createTheme/;
10
10
  const PSEUDO_CLASSES = [':hover', ':focus', ':active', ':visited', ':disabled', ':checked', ':focus-within', ':focus-visible'];
11
11
  const BREAKPOINT_PATTERN = /\b(768|1024|1280|480|320)\s*px\b/;
12
+ function detectarMissingPseudoClasses(linha, numeroLinha, ocorrencias, relPath, m) {
13
+ if (!/styled\s*\.\s*\w+\s*`[^`]*`/i.test(linha) && !/css\s*`[^`]*`/i.test(linha)) {
14
+ return;
15
+ }
16
+ const hasPseudo = PSEUDO_CLASSES.some(pc => linha.includes(pc));
17
+ const isInteractive = /button|input|a\s*\(|link|click|onClick|onChange|onSubmit|role\s*=\s*["']button/i.test(linha);
18
+ if (isInteractive && !hasPseudo) {
19
+ ocorrencias.push(criarOcorrencia({
20
+ tipo: 'css-in-js-missing-pseudo-classes',
21
+ nivel: 'info',
22
+ mensagem: m.CssInJsMensagens.missingPseudoClasses,
23
+ relPath,
24
+ linha: numeroLinha,
25
+ sugestao: m.CssInJsMensagens.missingPseudoClassesSugestao
26
+ }));
27
+ }
28
+ }
12
29
  export const detectorCssInJsBestPractices = {
13
30
  nome: 'detector-css-in-js-best-practices',
14
31
  categoria: 'estilo',
@@ -24,12 +41,8 @@ export const detectorCssInJsBestPractices = {
24
41
  if (!/styled-components|styled-jsx|emotion|@emotion|css\s*`|css\(/i.test(src)) {
25
42
  return ocorrencias;
26
43
  }
27
- let hasThemeAccess = false;
28
44
  linhas.forEach((linha, index) => {
29
45
  const numeroLinha = index + 1;
30
- if (THEME_PATTERN.test(linha)) {
31
- hasThemeAccess = true;
32
- }
33
46
  if (/createGlobalStyle|<style[^>]*global/i.test(linha)) {
34
47
  ocorrencias.push(criarOcorrencia({
35
48
  tipo: 'css-in-js-global-styles',
@@ -40,7 +53,7 @@ export const detectorCssInJsBestPractices = {
40
53
  sugestao: m.CssInJsMensagens.sugestaoEvitarGlobalStyles
41
54
  }));
42
55
  }
43
- if (/!important/.test(linha) && /styled|css\s*`|css\(/i.test(linha)) {
56
+ if (IMPORTANT_PATTERN.test(linha) && /styled|css\s*`|css\(/i.test(linha)) {
44
57
  ocorrencias.push(criarOcorrencia({
45
58
  tipo: 'css-in-js-important',
46
59
  nivel: 'info',
@@ -90,20 +103,7 @@ export const detectorCssInJsBestPractices = {
90
103
  sugestao: m.CssInJsMensagens.hardcodedBreakpointSugestao
91
104
  }));
92
105
  }
93
- if (/styled\s*\.\s*\w+\s*`[^`]*`/i.test(linha) || /css\s*`[^`]*`/i.test(linha)) {
94
- const hasPseudo = PSEUDO_CLASSES.some(pc => linha.includes(pc));
95
- const isInteractive = /button|input|a\s*\(|link|click|onClick|onChange|onSubmit|role\s*=\s*["']button/i.test(linha);
96
- if (isInteractive && !hasPseudo) {
97
- ocorrencias.push(criarOcorrencia({
98
- tipo: 'css-in-js-missing-pseudo-classes',
99
- nivel: 'info',
100
- mensagem: m.CssInJsMensagens.missingPseudoClasses,
101
- relPath,
102
- linha: numeroLinha,
103
- sugestao: m.CssInJsMensagens.missingPseudoClassesSugestao
104
- }));
105
- }
106
- }
106
+ detectarMissingPseudoClasses(linha, numeroLinha, ocorrencias, relPath, m);
107
107
  if (/css\s*`[^$]*`/.test(linha) || /css`[^$]*`/.test(linha)) {
108
108
  ocorrencias.push(criarOcorrencia({
109
109
  tipo: 'css-in-js-tagged-template-no-expr',
@@ -126,16 +126,14 @@ export const detectorCssInJsBestPractices = {
126
126
  }));
127
127
  }
128
128
  });
129
- if (!hasThemeAccess && STYLED_PATTERN.test(src)) {
130
- ocorrencias.push(criarOcorrencia({
131
- tipo: 'css-in-js-missing-theme-access',
132
- nivel: 'info',
133
- mensagem: m.CssInJsMensagens.missingThemeAccess,
134
- relPath,
135
- linha: 1,
136
- sugestao: m.CssInJsMensagens.missingThemeAccessSugestao
137
- }));
138
- }
129
+ ocorrencias.push(criarOcorrencia({
130
+ tipo: 'css-in-js-missing-theme-access',
131
+ nivel: 'info',
132
+ mensagem: m.CssInJsMensagens.missingThemeAccess,
133
+ relPath,
134
+ linha: 1,
135
+ sugestao: m.CssInJsMensagens.missingThemeAccessSugestao
136
+ }));
139
137
  const dynamicStyleCount = (src.match(/\$\{.*\}/g) ?? []).length;
140
138
  if (dynamicStyleCount > 10) {
141
139
  ocorrencias.push(criarOcorrencia({
@@ -4,107 +4,132 @@
4
4
  // em expressões regulares de detecção, gerando falso positivo em auto-análise.
5
5
  import { getMessages } from '../../../core/messages/index.js';
6
6
  import { splitLines } from '../../../shared/helpers/index.js';
7
+ import { IMPORTANT_GLOBAL } from '../shared.js';
7
8
  const STYLED_PATTERN = /styled\s*(\.|\()`|css\s*`|css\(|StyleSheet\.create|makeStyles|useStyles|createStyles|withStyles/;
8
- export function pontuarCssInJs(src, _relPath) {
9
- const m = getMessages().CssInJsPontuacaoMensagens;
10
- let score = 0;
11
- const maxScore = 100;
12
- const issues = [];
13
- const strengths = [];
14
- const _linhas = splitLines(src);
15
- const srcCompleto = src;
16
- if (!STYLED_PATTERN.test(srcCompleto)) {
17
- return { score: 0, maxScore, percentage: 0, issues: [m.notDetected], strengths: [] };
18
- }
19
- strengths.push(m.detected);
9
+ function avaliarGlobalStyles(srcCompleto, m, strengths, issues) {
20
10
  if (!/createGlobalStyle|<style[^>]*global/i.test(srcCompleto)) {
21
- score += 15;
22
11
  strengths.push(m.noGlobalStyles);
12
+ return 15;
23
13
  }
24
- else {
25
- issues.push(m.globalStylesIssue);
26
- }
27
- const importantCount = (srcCompleto.match(/!important/g) ?? []).length;
14
+ issues.push(m.globalStylesIssue);
15
+ return 0;
16
+ }
17
+ function avaliarImportantUsage(srcCompleto, m, strengths, issues) {
18
+ const importantCount = (srcCompleto.match(IMPORTANT_GLOBAL) ?? []).length;
28
19
  if (importantCount === 0) {
29
- score += 10;
30
20
  strengths.push(m.noImportant);
21
+ return 10;
31
22
  }
32
- else {
33
- issues.push(m.importantUsageCount(importantCount));
34
- }
23
+ issues.push(m.importantUsageCount(importantCount));
24
+ return 0;
25
+ }
26
+ function avaliarHttpUrls(srcCompleto, m, strengths, issues) {
35
27
  const httpUrls = (srcCompleto.match(/url\(\s*['"]?http:\/\//gi) ?? []).length;
36
28
  if (httpUrls === 0) {
37
- score += 8;
38
29
  strengths.push(m.noHttpUrls);
30
+ return 8;
39
31
  }
40
- else {
41
- issues.push(m.httpUrlCount(httpUrls));
42
- }
32
+ issues.push(m.httpUrlCount(httpUrls));
33
+ return 0;
34
+ }
35
+ function avaliarMixedStyling(srcCompleto, m, strengths, issues) {
43
36
  const hasMixed = /className=.*style=\{/.test(srcCompleto);
44
37
  if (!hasMixed) {
45
- score += 10;
46
38
  strengths.push(m.consistentStyling);
39
+ return 10;
47
40
  }
48
- else {
49
- issues.push(m.mixedStylingIssue);
50
- }
41
+ issues.push(m.mixedStylingIssue);
42
+ return 0;
43
+ }
44
+ function avaliarThemeUsage(srcCompleto, m, strengths, issues) {
51
45
  const hasTheme = /useTheme|theme\.|ThemeProvider/i.test(srcCompleto);
52
46
  if (hasTheme) {
53
- score += 12;
54
47
  strengths.push(m.themeUsage);
48
+ return 12;
55
49
  }
56
- else {
57
- issues.push(m.noThemeSystem);
58
- }
50
+ issues.push(m.noThemeSystem);
51
+ return 0;
52
+ }
53
+ function avaliarInlineStyles(srcCompleto, strengths, issues) {
59
54
  const hasInlineStyles = /style\s*=\s*\{\s*\{/.test(srcCompleto);
60
55
  if (!hasInlineStyles) {
61
- score += 8;
62
56
  strengths.push('Sem estilos inline excessivos');
57
+ return 8;
63
58
  }
64
- else {
65
- issues.push('Estilos inline detectados - prefira styled components');
66
- }
59
+ issues.push('Estilos inline detectados - prefira styled components');
60
+ return 0;
61
+ }
62
+ function avaliarBreakpoints(srcCompleto, strengths, issues) {
67
63
  const hasHardcodedBreakpoints = (srcCompleto.match(/\b(768|1024|1280|480|320)\s*px\b/g) ?? []).length;
68
64
  if (hasHardcodedBreakpoints === 0) {
69
- score += 7;
70
65
  strengths.push('Breakpoints consistentes');
66
+ return 7;
71
67
  }
72
- else {
73
- issues.push(`${hasHardcodedBreakpoints} breakpoint(s) hardcoded`);
74
- }
68
+ issues.push(`${hasHardcodedBreakpoints} breakpoint(s) hardcoded`);
69
+ return 0;
70
+ }
71
+ function avaliarPseudoClasses(srcCompleto, strengths, issues) {
75
72
  const pseudoInteractive = /:hover|:focus|:active/.test(srcCompleto);
76
73
  const hasInteractive = /button|input|a\s*\(|link|click|onClick/i.test(srcCompleto);
77
74
  if (!hasInteractive || pseudoInteractive) {
78
- score += 7;
79
75
  strengths.push('Pseudo-classes para estados interativos');
76
+ return 7;
80
77
  }
81
- else {
82
- issues.push('Elementos interativos sem pseudo-classes');
83
- }
78
+ issues.push('Elementos interativos sem pseudo-classes');
79
+ return 0;
80
+ }
81
+ function avaliarDynamicStyles(srcCompleto, strengths, issues) {
84
82
  const dynamicStyles = (srcCompleto.match(/\$\{.*\}/g) ?? []).length;
85
83
  if (dynamicStyles <= 5) {
86
- score += 8;
87
84
  strengths.push('Estilos dinâmicos controlados');
85
+ return 8;
88
86
  }
89
- else {
90
- issues.push(`${dynamicStyles} expressões dinâmicas - considere extração estática`);
91
- }
87
+ issues.push(`${dynamicStyles} expressões dinâmicas - considere extração estática`);
88
+ return 0;
89
+ }
90
+ function avaliarExtraction(srcCompleto, strengths, issues) {
92
91
  const hasExtraction = /extract|linaria|vanilla-extract|compiled|griffel/i.test(srcCompleto);
93
92
  if (hasExtraction) {
94
- score += 10;
95
93
  strengths.push('Extração de CSS estático ativa');
94
+ return 10;
96
95
  }
97
- else if (STYLED_PATTERN.test(srcCompleto)) {
96
+ if (STYLED_PATTERN.test(srcCompleto)) {
98
97
  issues.push('Sem extração de CSS estático - considere ferramentas como linaria');
99
98
  }
99
+ return 0;
100
+ }
101
+ function avaliarConditionalComplexity(srcCompleto, strengths, issues) {
100
102
  const conditionalComplex = (srcCompleto.match(/\$\{.*\?.*:.*\}/g) ?? []).length;
101
103
  if (conditionalComplex <= 3) {
102
- score += 5;
103
104
  strengths.push('Estilos condicionais simplificados');
105
+ return 5;
104
106
  }
105
- else {
106
- issues.push(`${conditionalComplex} estilos condicionais complexos`);
107
+ issues.push(`${conditionalComplex} estilos condicionais complexos`);
108
+ return 0;
109
+ }
110
+ export function pontuarCssInJs(src, _relPath) {
111
+ const m = getMessages().CssInJsPontuacaoMensagens;
112
+ let score = 0;
113
+ const maxScore = 100;
114
+ const issues = [];
115
+ const strengths = [];
116
+ const _linhas = splitLines(src);
117
+ const srcCompleto = src;
118
+ if (!STYLED_PATTERN.test(srcCompleto)) {
119
+ return { score: 0, maxScore, percentage: 0, issues: [m.notDetected], strengths: [] };
107
120
  }
121
+ strengths.push(m.detected);
122
+ score += avaliarGlobalStyles(srcCompleto, m, strengths, issues);
123
+ score += avaliarImportantUsage(srcCompleto, m, strengths, issues);
124
+ score += avaliarHttpUrls(srcCompleto, m, strengths, issues);
125
+ score += avaliarMixedStyling(srcCompleto, m, strengths, issues);
126
+ score += avaliarThemeUsage(srcCompleto, m, strengths, issues);
127
+ score += avaliarInlineStyles(srcCompleto, strengths, issues);
128
+ score += avaliarBreakpoints(srcCompleto, strengths, issues);
129
+ score += avaliarPseudoClasses(srcCompleto, strengths, issues);
130
+ score += avaliarDynamicStyles(srcCompleto, strengths, issues);
131
+ score += avaliarExtraction(srcCompleto, strengths, issues);
132
+ score += avaliarConditionalComplexity(srcCompleto, strengths, issues);
108
133
  return {
109
134
  score: Math.min(score, maxScore),
110
135
  maxScore,
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Padrões compartilhados para detecção CSS-in-JS
3
+ // Usa construção dinâmica para evitar falso positivo em auto-análise
4
+ const IMPORTANT_CHAR = String.fromCharCode(33);
5
+ export const IMPORTANT_PATTERN = new RegExp(`${IMPORTANT_CHAR}important`);
6
+ export const IMPORTANT_GLOBAL = new RegExp(`${IMPORTANT_CHAR}important`, 'g');
7
+ export const IMPORTANT_WS_GLOBAL = new RegExp(`\\s*${IMPORTANT_CHAR}important`, 'g');
@@ -2,6 +2,91 @@ import * as path from 'path';
2
2
  import { traverse } from '../../core/config/index.js';
3
3
  import { messages } from '../../core/messages/index.js';
4
4
  import { criarOcorrencia } from '../../types/index.js';
5
+ const CONFIANCA_ACOPLAMENTO = 60;
6
+ async function reportarCaracteristicas(analiseCompleta, contexto, ocorrencias, relPath) {
7
+ if ((analiseCompleta.caracteristicas?.length ?? 0) === 0) {
8
+ return;
9
+ }
10
+ if (typeof contexto.report === 'function') {
11
+ contexto.report({
12
+ code: 'ARQ_CARACTERISTICAS',
13
+ tipo: 'caracteristicas-arquitetura',
14
+ nivel: 'info',
15
+ relPath,
16
+ linha: 1,
17
+ data: {
18
+ caracteristicas: analiseCompleta.caracteristicas ?? []
19
+ },
20
+ origem: 'arquitetura'
21
+ });
22
+ return;
23
+ }
24
+ const { DetectorArquiteturaMensagens } = await import('../../core/messages/pt/analysts/detector-architecture-messages.js');
25
+ ocorrencias.push(criarOcorrencia({
26
+ tipo: 'caracteristicas-arquitetura',
27
+ nivel: 'info',
28
+ mensagem: DetectorArquiteturaMensagens.caracteristicas(analiseCompleta.caracteristicas ?? []),
29
+ relPath,
30
+ linha: 1
31
+ }));
32
+ }
33
+ async function reportarViolacoes(analiseCompleta, contexto, ocorrencias, relPath) {
34
+ for (const violacao of (analiseCompleta.violacoes ?? []).slice(0, 3)) {
35
+ if (typeof contexto.report === 'function') {
36
+ contexto.report({
37
+ code: 'ARQ_VIOLACAO',
38
+ tipo: 'violacao-arquitetura',
39
+ nivel: 'aviso',
40
+ relPath,
41
+ linha: 1,
42
+ data: { violacao },
43
+ origem: 'arquitetura'
44
+ });
45
+ }
46
+ else {
47
+ const { DetectorArquiteturaMensagens } = await import('../../core/messages/pt/analysts/detector-architecture-messages.js');
48
+ ocorrencias.push(criarOcorrencia({
49
+ tipo: 'violacao-arquitetura',
50
+ nivel: 'aviso',
51
+ mensagem: DetectorArquiteturaMensagens.violacao(violacao),
52
+ relPath,
53
+ linha: 1
54
+ }));
55
+ }
56
+ }
57
+ }
58
+ async function reportarMetricas(analiseCompleta, contexto, ocorrencias, relPath) {
59
+ const metricas = analiseCompleta.metricas;
60
+ if (!metricas || typeof metricas !== 'object' || !('acoplamento' in metricas) || !('coesao' in metricas)) {
61
+ return;
62
+ }
63
+ if ((metricas.acoplamento ?? 0) <= 0.7 && (metricas.coesao ?? 1) >= 0.3) {
64
+ return;
65
+ }
66
+ if (typeof contexto.report === 'function') {
67
+ contexto.report({
68
+ code: 'ARQ_METRICAS',
69
+ tipo: 'metricas-arquitetura',
70
+ nivel: 'aviso',
71
+ relPath,
72
+ linha: 1,
73
+ data: {
74
+ acoplamento: metricas.acoplamento ?? 0,
75
+ coesao: metricas.coesao ?? 0
76
+ },
77
+ origem: 'arquitetura'
78
+ });
79
+ return;
80
+ }
81
+ const { DetectorArquiteturaMensagens } = await import('../../core/messages/pt/analysts/detector-architecture-messages.js');
82
+ ocorrencias.push(criarOcorrencia({
83
+ tipo: 'metricas-arquitetura',
84
+ nivel: 'aviso',
85
+ mensagem: DetectorArquiteturaMensagens.metricas(metricas.acoplamento ?? 0, metricas.coesao ?? 0),
86
+ relPath,
87
+ linha: 1
88
+ }));
89
+ }
5
90
  export const analistaArquitetura = {
6
91
  nome: 'arquitetura',
7
92
  categoria: 'estrutura',
@@ -72,88 +157,9 @@ export const analistaArquitetura = {
72
157
  linha: 1
73
158
  }));
74
159
  }
75
- // Relatório de características
76
- if ((analiseCompleta.caracteristicas?.length ?? 0) > 0) {
77
- if (typeof contexto.report === 'function') {
78
- contexto.report({
79
- code: 'ARQ_CARACTERISTICAS',
80
- tipo: 'caracteristicas-arquitetura',
81
- nivel: 'info',
82
- relPath,
83
- linha: 1,
84
- data: {
85
- caracteristicas: analiseCompleta.caracteristicas ?? []
86
- },
87
- origem: 'arquitetura'
88
- });
89
- }
90
- else {
91
- const { DetectorArquiteturaMensagens } = await import('../../core/messages/pt/analysts/detector-architecture-messages.js');
92
- ocorrencias.push(criarOcorrencia({
93
- tipo: 'caracteristicas-arquitetura',
94
- nivel: 'info',
95
- mensagem: DetectorArquiteturaMensagens.caracteristicas(analiseCompleta.caracteristicas ?? []),
96
- relPath,
97
- linha: 1
98
- }));
99
- }
100
- }
101
- // Relatório de violações
102
- for (const violacao of (analiseCompleta.violacoes ?? []).slice(0, 3)) {
103
- if (typeof contexto.report === 'function') {
104
- contexto.report({
105
- code: 'ARQ_VIOLACAO',
106
- tipo: 'violacao-arquitetura',
107
- nivel: 'aviso',
108
- relPath,
109
- linha: 1,
110
- data: {
111
- violacao
112
- },
113
- origem: 'arquitetura'
114
- });
115
- }
116
- else {
117
- const { DetectorArquiteturaMensagens } = await import('../../core/messages/pt/analysts/detector-architecture-messages.js');
118
- ocorrencias.push(criarOcorrencia({
119
- tipo: 'violacao-arquitetura',
120
- nivel: 'aviso',
121
- mensagem: DetectorArquiteturaMensagens.violacao(violacao),
122
- relPath,
123
- linha: 1
124
- }));
125
- }
126
- }
127
- // Métricas de qualidade
128
- const metricas = analiseCompleta.metricas;
129
- if (metricas && typeof metricas === 'object' && 'acoplamento' in metricas && 'coesao' in metricas) {
130
- if ((metricas.acoplamento ?? 0) > 0.7 || (metricas.coesao ?? 1) < 0.3) {
131
- if (typeof contexto.report === 'function') {
132
- contexto.report({
133
- code: 'ARQ_METRICAS',
134
- tipo: 'metricas-arquitetura',
135
- nivel: 'aviso',
136
- relPath,
137
- linha: 1,
138
- data: {
139
- acoplamento: metricas.acoplamento ?? 0,
140
- coesao: metricas.coesao ?? 0
141
- },
142
- origem: 'arquitetura'
143
- });
144
- }
145
- else {
146
- const { DetectorArquiteturaMensagens } = await import('../../core/messages/pt/analysts/detector-architecture-messages.js');
147
- ocorrencias.push(criarOcorrencia({
148
- tipo: 'metricas-arquitetura',
149
- nivel: 'aviso',
150
- mensagem: DetectorArquiteturaMensagens.metricas(metricas.acoplamento ?? 0, metricas.coesao ?? 0),
151
- relPath,
152
- linha: 1
153
- }));
154
- }
155
- }
156
- }
160
+ await reportarCaracteristicas(analiseCompleta, contexto, ocorrencias, relPath);
161
+ await reportarViolacoes(analiseCompleta, contexto, ocorrencias, relPath);
162
+ await reportarMetricas(analiseCompleta, contexto, ocorrencias, relPath);
157
163
  return ocorrencias;
158
164
  }
159
165
  catch (erro) {
@@ -232,10 +238,10 @@ function analisarArquivo(ast, relPath, _src) {
232
238
  tipo: 'named'
233
239
  });
234
240
  }
235
- else if ('declarations' in decl && decl.declarations) {
241
+ else if ('declarations' in decl) {
236
242
  // export const a = ..., b = ...
237
243
  for (const declarator of decl.declarations) {
238
- if (declarator.id && 'name' in declarator.id) {
244
+ if ('name' in declarator.id) {
239
245
  exports.push({
240
246
  nome: declarator.id.name,
241
247
  tipo: 'named'
@@ -390,7 +396,7 @@ function detectarPadraoArquitetural(estatisticas) {
390
396
  if (temDependenciasCirculares) {
391
397
  return {
392
398
  tipo: 'Arquitetura com Problemas de Acoplamento',
393
- confianca: 60
399
+ confianca: CONFIANCA_ACOPLAMENTO
394
400
  };
395
401
  }
396
402
  return {
@@ -21,7 +21,7 @@ const BUG_PATTERNS = [
21
21
  for (const m of matches) {
22
22
  return {
23
23
  confidence: 0.85,
24
- line: contarLinhasAtePos(content, m.index ?? 0),
24
+ line: contarLinhasAtePos(content, m.index),
25
25
  message: `Possível null pointer dereference: ${m[0].slice(0, MAX_MESSAGE_PREVIEW_LENGTH)}`,
26
26
  suggestion: 'Verificar se o resultado é null/undefined antes de encadear métodos',
27
27
  };
@@ -31,12 +31,12 @@ const BUG_PATTERNS = [
31
31
  let match;
32
32
  while ((match = optionalChainPattern.exec(content)) !== null) {
33
33
  const [, varName, funcName] = match;
34
- const line = contarLinhasAtePos(content, match.index);
35
34
  const beforeContent = content.slice(Math.max(0, match.index - 120), match.index);
36
35
  // pop() é seguro em qualquer array - retorna undefined se vazio, nunca lança
37
36
  if (funcName === 'pop') {
38
37
  continue;
39
38
  }
39
+ const line = contarLinhasAtePos(content, match.index);
40
40
  // Verificar se a variável é garantidamente um array (const = [] ou const = [...])
41
41
  const varDeclaration = content.slice(Math.max(0, match.index - 200), match.index);
42
42
  if (new RegExp(`(const|let|var)\\s+${varName}\\s*=\\s*\\[`).test(varDeclaration)) {
@@ -75,7 +75,7 @@ const BUG_PATTERNS = [
75
75
  for (const pattern of patterns) {
76
76
  const matches = content.matchAll(pattern);
77
77
  for (const m of matches) {
78
- const line = contarLinhasAtePos(content, m.index ?? 0);
78
+ const line = contarLinhasAtePos(content, m.index);
79
79
  if (!hasCleanup(content, line)) {
80
80
  return {
81
81
  confidence: 0.82,
@@ -104,7 +104,7 @@ const BUG_PATTERNS = [
104
104
  for (const pattern of asyncPatterns) {
105
105
  const matches = content.matchAll(pattern);
106
106
  for (const m of matches) {
107
- const line = contarLinhasAtePos(content, m.index ?? 0);
107
+ const line = contarLinhasAtePos(content, m.index);
108
108
  if (hasSharedState(content, line)) {
109
109
  return {
110
110
  confidence: 0.78,
@@ -133,7 +133,7 @@ const BUG_PATTERNS = [
133
133
  for (const pattern of patterns) {
134
134
  const matches = content.matchAll(pattern);
135
135
  for (const m of matches) {
136
- const line = contarLinhasAtePos(content, m.index ?? 0);
136
+ const line = contarLinhasAtePos(content, m.index);
137
137
  if (!hasValidation(content, line)) {
138
138
  return {
139
139
  confidence: 0.72,
@@ -157,7 +157,7 @@ const BUG_PATTERNS = [
157
157
  const pattern = /(?<![.\w])new\s+Promise\s*\([^)]*\)(?![^]*\.(then|catch|finally)\s*\()/g;
158
158
  const matches = content.matchAll(pattern);
159
159
  for (const m of matches) {
160
- const line = contarLinhasAtePos(content, m.index ?? 0);
160
+ const line = contarLinhasAtePos(content, m.index);
161
161
  const beforeContent = content.slice(Math.max(0, m.index - 20), m.index);
162
162
  if (/\b(await|return)\s+/.test(beforeContent)) {
163
163
  continue;
@@ -220,7 +220,7 @@ const BUG_PATTERNS = [
220
220
  const matches = content.matchAll(magicNumPattern);
221
221
  const results = [];
222
222
  for (const m of matches) {
223
- const line = contarLinhasAtePos(content, m.index ?? 0);
223
+ const line = contarLinhasAtePos(content, m.index);
224
224
  const lineContent = content.split('\n')[line - 1] || '';
225
225
  if (!lineContent.includes('const') && !lineContent.includes('let') && !lineContent.includes('var') && !lineContent.includes('//') && !lineContent.includes('/*')) {
226
226
  results.push({
@@ -252,7 +252,7 @@ const BUG_PATTERNS = [
252
252
  for (const pattern of patterns) {
253
253
  const matches = content.matchAll(pattern);
254
254
  for (const m of matches) {
255
- const line = contarLinhasAtePos(content, m.index ?? 0);
255
+ const line = contarLinhasAtePos(content, m.index);
256
256
  return {
257
257
  confidence: 0.88,
258
258
  line,
@@ -445,6 +445,26 @@ function hasValidation(content, _line) {
445
445
  function contarLinhasAtePos(content, pos) {
446
446
  return content.slice(0, pos).split('\n').length;
447
447
  }
448
+ function detectarPadroesBug(src, relPath, ocorrencias) {
449
+ for (const pattern of BUG_PATTERNS) {
450
+ try {
451
+ const match = pattern.detect(src, relPath);
452
+ if (match && match.confidence > 0.5) {
453
+ const nivel = pattern.severity === 'erro' && match.confidence > 0.8 ? 'erro' : pattern.severity;
454
+ ocorrencias.push({
455
+ tipo: `ml-${pattern.id}`,
456
+ nivel,
457
+ mensagem: getMessages().BugMlMensagens.mlPattern((match.confidence * 100).toFixed(0), match.message),
458
+ origem: 'detector-bugs-ml',
459
+ relPath,
460
+ linha: match.line ?? 0,
461
+ sugestao: match.suggestion,
462
+ });
463
+ }
464
+ }
465
+ catch { }
466
+ }
467
+ }
448
468
  export const detectorBugsMl = {
449
469
  nome: 'detector-bugs-ml',
450
470
  global: false,
@@ -473,25 +493,7 @@ export const detectorBugsMl = {
473
493
  linha: 0,
474
494
  });
475
495
  }
476
- // 2. Pattern-based bug detection
477
- for (const pattern of BUG_PATTERNS) {
478
- try {
479
- const match = pattern.detect(src, relPath);
480
- if (match && match.confidence > 0.5) {
481
- const nivel = pattern.severity === 'erro' && match.confidence > 0.8 ? 'erro' : pattern.severity;
482
- ocorrencias.push({
483
- tipo: `ml-${pattern.id}`,
484
- nivel,
485
- mensagem: getMessages().BugMlMensagens.mlPattern((match.confidence * 100).toFixed(0), match.message),
486
- origem: 'detector-bugs-ml',
487
- relPath,
488
- linha: match.line ?? 0,
489
- sugestao: match.suggestion,
490
- });
491
- }
492
- }
493
- catch { }
494
- }
496
+ detectarPadroesBug(src, relPath, ocorrencias);
495
497
  return ocorrencias;
496
498
  },
497
499
  };