@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,19 +4,19 @@ import { traverse } from '../../../core/config/index.js';
4
4
  import { messages } from '../../../core/messages/index.js';
5
5
  import { isBabelNode } from '../../../types/index.js';
6
6
  export function extractHandlerInfo(nodeParam) {
7
- if (!nodeParam || !isBabelNode(nodeParam)) {
7
+ if (!isBabelNode(nodeParam)) {
8
8
  return null;
9
9
  }
10
10
  const node = nodeParam;
11
11
  const build = (fn, bodyBlock, isAnonymous) => {
12
12
  const rawParams = Array.isArray(fn.params) ? fn.params : [];
13
13
  const params = rawParams.filter((p) => textoTitulo.isIdentifier(p));
14
- return { func: fn, bodyBlock, isAnonymous, params, totalParams: (fn.params ?? []).length };
14
+ return { func: fn, bodyBlock, isAnonymous, params, totalParams: fn.params.length };
15
15
  };
16
- if (textoTitulo.isFunctionDeclaration(node) && node.body && textoTitulo.isBlockStatement(node.body)) {
16
+ if (textoTitulo.isFunctionDeclaration(node) && textoTitulo.isBlockStatement(node.body)) {
17
17
  return build(node, node.body, !node.id);
18
18
  }
19
- if ((textoTitulo.isFunctionExpression(node) || textoTitulo.isArrowFunctionExpression(node)) && node.body && textoTitulo.isBlockStatement(node.body)) {
19
+ if ((textoTitulo.isFunctionExpression(node) || textoTitulo.isArrowFunctionExpression(node)) && textoTitulo.isBlockStatement(node.body)) {
20
20
  return build(node, node.body, textoTitulo.isFunctionExpression(node) ? !node.id : true);
21
21
  }
22
22
  return null;
@@ -58,8 +58,8 @@ function detectarNewCommand(node, state) {
58
58
  state.hasFrameworkSignal = true;
59
59
  let nome = '';
60
60
  const arg0 = newExpr.arguments[0];
61
- if (arg0 && textoTitulo.isStringLiteral(arg0)) {
62
- nome = (arg0).value;
61
+ if (textoTitulo.isStringLiteral(arg0)) {
62
+ nome = arg0.value;
63
63
  }
64
64
  if (state.comandosInvocados === 0) {
65
65
  state.comandosInvocados++;
@@ -89,7 +89,7 @@ function detectarDiscordJs(node, state) {
89
89
  if (state.comandosInvocados === 0) {
90
90
  state.comandosInvocados++;
91
91
  const arg0 = call.arguments[0];
92
- const nome = prop.name === 'setName' && arg0 && textoTitulo.isStringLiteral(arg0) ? (arg0).value : 'slash-command';
92
+ const nome = prop.name === 'setName' && textoTitulo.isStringLiteral(arg0) ? arg0.value : 'slash-command';
93
93
  state.comandoNomes.push(nome);
94
94
  }
95
95
  return;
@@ -141,10 +141,10 @@ function detectarGenericCommand(node, state, registrar) {
141
141
  }
142
142
  let comandoNome = '';
143
143
  const primeiroArg = call.arguments[0];
144
- if (primeiroArg && textoTitulo.isStringLiteral(primeiroArg)) {
145
- comandoNome = (primeiroArg).value;
144
+ if (textoTitulo.isStringLiteral(primeiroArg)) {
145
+ comandoNome = primeiroArg.value;
146
146
  }
147
- const handler = call.arguments && call.arguments.length > 1 ? call.arguments[1] : undefined;
147
+ const handler = call.arguments.length > 1 ? call.arguments[1] : undefined;
148
148
  registrar(call, comandoNome, handler, 'generico');
149
149
  }
150
150
  function detectarCommanderAction(node, state, registrar) {
@@ -160,7 +160,7 @@ function detectarCommanderAction(node, state, registrar) {
160
160
  if (!textoTitulo.isIdentifier(prop) || prop.name !== 'action') {
161
161
  return;
162
162
  }
163
- const handler = call.arguments && call.arguments[0];
163
+ const handler = call.arguments[0];
164
164
  const nome = extrairNomeDeCadeia(call);
165
165
  registrar(call, nome, handler, 'commander');
166
166
  }
@@ -177,11 +177,11 @@ function detectarCommanderCommand(node, state, registrar) {
177
177
  if (!textoTitulo.isIdentifier(prop) || prop.name !== 'command') {
178
178
  return;
179
179
  }
180
- const args = call.arguments || [];
180
+ const args = call.arguments;
181
181
  const nameArg = args[0];
182
182
  let nome = '';
183
- if (nameArg && textoTitulo.isStringLiteral(nameArg)) {
184
- nome = (nameArg).value;
183
+ if (textoTitulo.isStringLiteral(nameArg)) {
184
+ nome = nameArg.value;
185
185
  }
186
186
  let handler;
187
187
  for (let i = args.length - 1; i >= 0; i--) {
@@ -210,7 +210,7 @@ function detectarYargs(node, state, registrar) {
210
210
  if (!textoTitulo.isIdentifier(obj) || !/yargs?/i.test(obj.name)) {
211
211
  return;
212
212
  }
213
- const args = call.arguments || [];
213
+ const args = call.arguments;
214
214
  let nome = '';
215
215
  if (args[0] && textoTitulo.isStringLiteral(args[0])) {
216
216
  nome = (args[0]).value;
@@ -236,7 +236,7 @@ function detectarOclif(node, state, registrar) {
236
236
  const k = method.key;
237
237
  return textoTitulo.isIdentifier(k) && k.name === 'run';
238
238
  };
239
- const bodyElem = Array.isArray(bodyArray) ? bodyArray.find(isRunMethod) : undefined;
239
+ const bodyElem = Array.isArray(bodyArray) ? bodyArray?.find(isRunMethod) : undefined;
240
240
  if (bodyElem?.body && textoTitulo.isBlockStatement(bodyElem.body)) {
241
241
  registrar(textoTitulo.callExpression(textoTitulo.identifier('oclifRun'), []), classNome, bodyElem, 'oclif');
242
242
  }
@@ -262,14 +262,14 @@ function detectarVarUsage(node, state) {
262
262
  return;
263
263
  }
264
264
  const fnBody = (node).body;
265
- if (!fnBody || !textoTitulo.isBlockStatement(fnBody)) {
265
+ if (!textoTitulo.isBlockStatement(fnBody)) {
266
266
  return;
267
267
  }
268
268
  const createdVars = new Set();
269
- for (const stmt of fnBody.body || []) {
269
+ for (const stmt of fnBody.body) {
270
270
  if (textoTitulo.isVariableDeclaration(stmt)) {
271
271
  for (const decl of stmt.declarations) {
272
- if (decl.id && textoTitulo.isIdentifier(decl.id) && decl.init && textoTitulo.isNewExpression(decl.init) && textoTitulo.isIdentifier(decl.init.callee) && state.commandClassNomes.has(decl.init.callee.name)) {
272
+ if (textoTitulo.isIdentifier(decl.id) && decl.init && textoTitulo.isNewExpression(decl.init) && textoTitulo.isIdentifier(decl.init.callee) && state.commandClassNomes.has(decl.init.callee.name)) {
273
273
  createdVars.add(decl.id.name);
274
274
  }
275
275
  }
@@ -297,7 +297,7 @@ function criarRegistrar(state) {
297
297
  if (comandoNome) {
298
298
  state.comandoNomes.push(comandoNome);
299
299
  }
300
- const userInfo = extractHandlerInfo(handler);
300
+ const userInfo = handler ? extractHandlerInfo(handler) : null;
301
301
  const registro = {
302
302
  comandoNome,
303
303
  id: undefined,
@@ -315,7 +315,7 @@ function criarRegistrar(state) {
315
315
  function extrairNomeDeCadeia(call) {
316
316
  let current = call;
317
317
  const visitados = new Set();
318
- while (current && !visitados.has(current)) {
318
+ while (!visitados.has(current)) {
319
319
  visitados.add(current);
320
320
  if (textoTitulo.isCallExpression(current) && textoTitulo.isMemberExpression(current.callee)) {
321
321
  const callee = current.callee;
@@ -323,7 +323,7 @@ function extrairNomeDeCadeia(call) {
323
323
  if (textoTitulo.isIdentifier(prop) && prop.name === 'command') {
324
324
  const arg0 = current.arguments[0];
325
325
  if (arg0 && textoTitulo.isStringLiteral(arg0)) {
326
- return arg0.value;
326
+ return (arg0).value;
327
327
  }
328
328
  }
329
329
  const owner = callee.object;
@@ -5,9 +5,9 @@ import { criarAnalista, criarOcorrencia, isBabelNode } from '../../../types/inde
5
5
  function isNodePath(x) {
6
6
  return typeof x === 'object' && x !== null && 'node' in x && isBabelNode(x.node) && typeof x.traverse === 'function';
7
7
  }
8
- const LIMITE_LINHAS = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_LINHAS ?? 30;
9
- const LIMITE_PARAMETROS = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_PARAMETROS ?? 4;
10
- const LIMITE_ANINHAMENTO = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_ANINHAMENTO ?? 3;
8
+ const LIMITE_LINHAS = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_LINHAS;
9
+ const LIMITE_PARAMETROS = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_PARAMETROS;
10
+ const LIMITE_ANINHAMENTO = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_ANINHAMENTO;
11
11
  const LIMITE_COMPLEXIDADE_COGNITIVA = 15;
12
12
  const LIMITE_RESPONSABILIDADES = 3;
13
13
  const LIMITE_CICLOMATICA = 10;
@@ -73,7 +73,7 @@ function calcularCiclomatica(body) {
73
73
  WhileStatement() { score++; },
74
74
  DoWhileStatement() { score++; },
75
75
  SwitchCase(path) {
76
- if (!path.node.consequent || path.node.consequent.length === 0) {
76
+ if (path.node.consequent.length === 0) {
77
77
  return;
78
78
  }
79
79
  score++;
@@ -122,7 +122,7 @@ function verificarEarlyReturn(fn) {
122
122
  const fnParent = path.getFunctionParent();
123
123
  if (fnParent?.node === fn) {
124
124
  const grandParent = path.parentPath;
125
- if (grandParent && textoTitulo.isIfStatement(grandParent.node)) {
125
+ if (textoTitulo.isIfStatement(grandParent.node)) {
126
126
  encontrouEarlyReturn = true;
127
127
  }
128
128
  }
@@ -51,7 +51,7 @@ export const analistaPadroesUso = {
51
51
  }
52
52
  let astWrap = astInput;
53
53
  if (!astWrap && contexto?.arquivos) {
54
- const found = contexto.arquivos.find((arquivo) => arquivo.relPath === relPath) ?? contexto.arquivos[0];
54
+ const found = contexto.arquivos?.find((arquivo) => arquivo.relPath === relPath) ?? contexto.arquivos[0];
55
55
  astWrap = found.ast ?? undefined;
56
56
  }
57
57
  const hasNodeProp = (valor) => typeof valor === 'object' && valor !== null && 'node' in valor;
@@ -131,7 +131,7 @@ export const analistaPadroesUso = {
131
131
  // Type assertion as Type without validation
132
132
  if (textoTitulo.isTSAsExpression(node)) {
133
133
  const parent = path.parentPath.node;
134
- if (parent && !textoTitulo.isVariableDeclarator(parent)) {
134
+ if (!textoTitulo.isVariableDeclarator(parent)) {
135
135
  push({ tipo: 'info', mensagem: messages.PadroesUsoMensagens.typeAssertionWithoutValidation, relPath, linha: node.loc?.start.line, coluna: node.loc?.start.column, nivel: 'info' });
136
136
  }
137
137
  }
@@ -163,6 +163,10 @@ export const analistaPadroesUso = {
163
163
  push({ tipo: 'info', mensagem: messages.PadroesUsoMensagens.uselessConditional, relPath, linha: node.loc?.start.line, coluna: node.loc?.start.column, nivel: 'info' });
164
164
  }
165
165
  }
166
+ // satisfies keyword usage (TypeScript 4.9+)
167
+ if (textoTitulo.isTSSatisfiesExpression(node)) {
168
+ push({ tipo: 'info', mensagem: messages.PadroesUsoMensagens.satisfiesUsage, relPath, linha: node.loc?.start.line, coluna: node.loc?.start.column, nivel: 'info' });
169
+ }
166
170
  }
167
171
  });
168
172
  // Magic strings detection (via text scan)
@@ -20,7 +20,7 @@ const visitorAsync = {
20
20
  if (binding && binding.path.isFunction() && !binding.path.node.async) {
21
21
  return;
22
22
  }
23
- const occurrences = state.ocorrencias || [];
23
+ const occurrences = state.ocorrencias;
24
24
  occurrences.push({
25
25
  tipo: 'floating-promise',
26
26
  linha: path.node.loc?.start.line ?? 0,
@@ -40,10 +40,10 @@ const visitorAsync = {
40
40
  const propName = prop.type === 'Identifier' ? prop.name : '';
41
41
  if (propName === 'map' || propName === 'forEach') {
42
42
  const arg = path.node.arguments[0];
43
- if (arg && (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression')) {
43
+ if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
44
44
  if (arg.async) {
45
45
  const isForEach = propName === 'forEach';
46
- const occurrences = state.ocorrencias || [];
46
+ const occurrences = state.ocorrencias;
47
47
  occurrences.push({
48
48
  tipo: isForEach ? 'async-in-foreach' : 'async-in-map-without-all',
49
49
  linha: path.node.loc?.start.line ?? 0,
@@ -60,7 +60,7 @@ const visitorAsync = {
60
60
  if (propName === 'then' && textoTitulo.isCallExpression(callee.object) && textoTitulo.isMemberExpression(callee.object.callee)) {
61
61
  const innerProp = callee.object.callee.property;
62
62
  if (textoTitulo.isIdentifier(innerProp) && innerProp.name === 'all') {
63
- const _hasCatch = path.parentPath && textoTitulo.isCallExpression(path.parentPath.node) && path.parentPath.node.arguments.length > 0;
63
+ const _hasCatch = textoTitulo.isCallExpression(path.parentPath.node) && path.parentPath.node.arguments.length > 0;
64
64
  let hasErrorHandler = false;
65
65
  try {
66
66
  path.parentPath.traverse({
@@ -72,7 +72,8 @@ const visitorAsync = {
72
72
  });
73
73
  }
74
74
  catch { }
75
- if (!hasErrorHandler) {
75
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare, @typescript-eslint/no-unnecessary-condition
76
+ if (hasErrorHandler === false) {
76
77
  state.ocorrencias.push({
77
78
  tipo: 'promise-all-no-error',
78
79
  linha: path.node.loc?.start.line ?? 0,
@@ -88,7 +89,7 @@ const visitorAsync = {
88
89
  // Promise nesting: .then() inside .then()
89
90
  if (propName === 'then') {
90
91
  const arg = path.node.arguments[0];
91
- if (arg && (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression')) {
92
+ if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
92
93
  const body = arg.body;
93
94
  if (body.type === 'BlockStatement') {
94
95
  for (const stmt of body.body) {
@@ -119,7 +120,7 @@ const visitorAsync = {
119
120
  // Promise constructor anti-pattern: new Promise((resolve, reject) => { ... })
120
121
  if (callee.type === 'Identifier' && callee.name === 'Promise' && path.node.arguments.length === 1) {
121
122
  const executor = path.node.arguments[0];
122
- if (executor && (executor.type === 'ArrowFunctionExpression' || executor.type === 'FunctionExpression')) {
123
+ if (executor.type === 'ArrowFunctionExpression' || executor.type === 'FunctionExpression') {
123
124
  const executorBody = executor.type === 'ArrowFunctionExpression' ? executor.body : executor.body;
124
125
  if (executorBody.type === 'BlockStatement') {
125
126
  for (const stmt of executorBody.body) {
@@ -140,11 +141,12 @@ const visitorAsync = {
140
141
  }
141
142
  }
142
143
  // return await misuse (outside try/catch)
143
- if (callee.type === 'Identifier' && path.parentPath && textoTitulo.isReturnStatement(path.parentPath.node)) {
144
+ if (callee.type === 'Identifier' && textoTitulo.isReturnStatement(path.parentPath.node)) {
144
145
  const fnParent = path.getFunctionParent();
145
146
  if (fnParent) {
146
147
  let inTryCatch = false;
147
148
  let current = path.parentPath;
149
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
148
150
  while (current) {
149
151
  if (textoTitulo.isTryStatement(current.node)) {
150
152
  inTryCatch = true;
@@ -188,6 +190,21 @@ const visitorAsync = {
188
190
  }
189
191
  state.lastAwaitLine = currentLine;
190
192
  },
193
+ // Top-level await and for-await-of detection via text fallback
194
+ // These are checked in the aplicar method
195
+ ForOfStatement(path, state) {
196
+ if (path.node.await) {
197
+ state.ocorrencias.push({
198
+ tipo: 'for-await-of',
199
+ linha: path.node.loc?.start.line ?? 0,
200
+ coluna: path.node.loc?.start.column ?? 0,
201
+ severidade: 'baixa',
202
+ nivel: 'info',
203
+ mensagem: messages.DetectorJsTsMensagens.forAwaitOf,
204
+ relPath: state.relPath
205
+ });
206
+ }
207
+ },
191
208
  Function(path, state) {
192
209
  // Async function without await
193
210
  if (path.node.async) {
@@ -198,7 +215,8 @@ const visitorAsync = {
198
215
  });
199
216
  }
200
217
  catch { }
201
- if (!hasAwait) {
218
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare, @typescript-eslint/no-unnecessary-condition
219
+ if (hasAwait === false) {
202
220
  state.ocorrencias.push({
203
221
  tipo: 'async-without-await',
204
222
  linha: path.node.loc?.start.line ?? 0,
@@ -256,6 +274,63 @@ export const analistaAntiPadroesAsync = {
256
274
  };
257
275
  const nodeToTraverse = ('node' in ast ? ast.node : ast);
258
276
  traverse(nodeToTraverse, visitorAsync, undefined, stateObj);
277
+ // Top-level await detection via text
278
+ if (/^\s*await\s+/m.test(src)) {
279
+ const topLevelAwaitLine = (() => {
280
+ const m = src.match(/^\s*await\s+/m);
281
+ return m ? src.substring(0, m.index).split('\n').length : 1;
282
+ })();
283
+ const fnParentLines = new Set();
284
+ const fnVisitor = {
285
+ Function(path) {
286
+ if (path.node.loc) {
287
+ for (let i = path.node.loc.start.line; i <= path.node.loc.end.line; i++) {
288
+ fnParentLines.add(i);
289
+ }
290
+ }
291
+ }
292
+ };
293
+ traverse(nodeToTraverse, fnVisitor, undefined, {});
294
+ if (!fnParentLines.has(topLevelAwaitLine)) {
295
+ stateObj.ocorrencias.push({
296
+ tipo: 'top-level-await',
297
+ linha: topLevelAwaitLine,
298
+ coluna: 0,
299
+ severidade: 'baixa',
300
+ nivel: 'info',
301
+ mensagem: messages.DetectorJsTsMensagens.topLevelAwait,
302
+ relPath
303
+ });
304
+ }
305
+ }
306
+ // Promise.withResolvers detection via text
307
+ if (/Promise\.withResolvers\s*\(/g.test(src)) {
308
+ const match = /Promise\.withResolvers\s*\(/g.exec(src);
309
+ const linha = match ? src.substring(0, match.index).split('\n').length : 1;
310
+ stateObj.ocorrencias.push({
311
+ tipo: 'promise-with-resolvers',
312
+ linha,
313
+ coluna: 0,
314
+ severidade: 'baixa',
315
+ nivel: 'info',
316
+ mensagem: messages.DetectorJsTsMensagens.promiseWithResolvers,
317
+ relPath
318
+ });
319
+ }
320
+ // Promise.allSettled detection
321
+ if (/Promise\.allSettled\s*\(/g.test(src)) {
322
+ const match = /Promise\.allSettled\s*\(/g.exec(src);
323
+ const linha = match ? src.substring(0, match.index).split('\n').length : 1;
324
+ stateObj.ocorrencias.push({
325
+ tipo: 'promise-all-settled',
326
+ linha,
327
+ coluna: 0,
328
+ severidade: 'baixa',
329
+ nivel: 'info',
330
+ mensagem: messages.DetectorJsTsMensagens.promiseAllSettled,
331
+ relPath
332
+ });
333
+ }
259
334
  return stateObj.ocorrencias.map(ocorrencia => criarOcorrencia({
260
335
  tipo: ocorrencia.tipo ?? 'anti-padroes-async',
261
336
  nivel: ocorrencia.nivel ?? 'aviso',
@@ -39,9 +39,9 @@ export const analistaConstrucoesSintaticas = {
39
39
  }
40
40
  // Destructuring without defaults
41
41
  for (const declarator of path.node.declarations) {
42
- if (declarator.id && textoTitulo.isObjectPattern(declarator.id)) {
42
+ if (textoTitulo.isObjectPattern(declarator.id)) {
43
43
  for (const prop of declarator.id.properties) {
44
- if (textoTitulo.isObjectProperty(prop) && prop.value && textoTitulo.isIdentifier(prop.value) && !prop.value.typeAnnotation) {
44
+ if (textoTitulo.isObjectProperty(prop) && textoTitulo.isIdentifier(prop.value) && !prop.value.typeAnnotation) {
45
45
  if (!prop.value.optional) {
46
46
  pushExtra('destructuring-without-default', 'info', messages.DetectorConstrucoesSintaticasMensagens.destructuringWithoutDefault, path.node.loc?.start.line ?? 1);
47
47
  }
@@ -146,14 +146,18 @@ export const analistaConstrucoesSintaticas = {
146
146
  // Nullish coalescing vs OR misuse: detecting if (x || defaultValue) where x could be '' or 0
147
147
  if (path.node.operator === '||') {
148
148
  const left = path.node.left;
149
- if (left && (textoTitulo.isMemberExpression(left) || textoTitulo.isIdentifier(left))) {
149
+ if (textoTitulo.isMemberExpression(left) || textoTitulo.isIdentifier(left)) {
150
150
  const right = path.node.right;
151
- if (right && (textoTitulo.isStringLiteral(right) || textoTitulo.isNumericLiteral(right))) {
151
+ if (textoTitulo.isStringLiteral(right) || textoTitulo.isNumericLiteral(right)) {
152
152
  pushExtra('nullish-vs-or', 'info', messages.DetectorConstrucoesSintaticasMensagens.nullishVsOrMisuse, path.node.loc?.start.line ?? 1);
153
153
  }
154
154
  }
155
155
  }
156
156
  },
157
+ // ES2025: Promise.withResolvers
158
+ // ES2025: RegExp.escape
159
+ // ES2026: Error.isError
160
+ // ES2026: Array.fromAsync
157
161
  OptionalMemberExpression(path) {
158
162
  // Optional chaining where not needed: obj?.prop where obj is always defined
159
163
  if ('optional' in path.node && path.node.optional) {
@@ -172,7 +176,7 @@ export const analistaConstrucoesSintaticas = {
172
176
  SpreadElement(path) {
173
177
  // Unnecessary object spread: {...obj, prop: val} could be obj.prop = val
174
178
  const parent = path.parentPath;
175
- if (parent && textoTitulo.isObjectExpression(parent.node)) {
179
+ if (textoTitulo.isObjectExpression(parent.node)) {
176
180
  const arg = path.node.argument;
177
181
  if (textoTitulo.isIdentifier(arg) && parent.node.properties.length >= 2) {
178
182
  const otherSpread = parent.node.properties.filter(p => textoTitulo.isSpreadElement(p) && p !== path.node);
@@ -187,7 +191,7 @@ export const analistaConstrucoesSintaticas = {
187
191
  // Getter/setter without validation
188
192
  if (path.node.kind === 'set') {
189
193
  const body = path.node.body;
190
- if (body && textoTitulo.isBlockStatement(body)) {
194
+ if (textoTitulo.isBlockStatement(body)) {
191
195
  let hasValidation = false;
192
196
  for (const stmt of body.body) {
193
197
  if (textoTitulo.isIfStatement(stmt)) {
@@ -202,16 +206,35 @@ export const analistaConstrucoesSintaticas = {
202
206
  }
203
207
  }
204
208
  });
209
+ // Text-based detection for ES2025/ES2026 patterns
210
+ const esPatterns = [
211
+ [/\busing\s+\w+\s*=\s*new\s+/g, 'explicit-resource-management', (linha) => { pushExtra('explicit-resource-management', 'info', 'Explicit Resource Management with "using" (ES2026)', linha); }],
212
+ [/\bawait\s+using\s+/g, 'explicit-resource-management-async', (linha) => { pushExtra('explicit-resource-management-async', 'info', 'Async Resource Management with "await using" (ES2026)', linha); }],
213
+ [/\bTemporal\.\w+/g, 'temporal-api-usage', (linha) => { pushExtra('temporal-api-usage', 'info', 'Temporal API usage (ES2026)', linha); }],
214
+ [/Promise\.withResolvers\s*\(/g, 'promise-with-resolvers', (linha) => { pushExtra('promise-with-resolvers', 'info', 'Promise.withResolvers() (ES2025)', linha); }],
215
+ [/Promise\.try\s*\(/g, 'promise-try', (linha) => { pushExtra('promise-try', 'info', 'Promise.try() (ES2025)', linha); }],
216
+ [/RegExp\.escape\s*\(/g, 'regexp-escape', (linha) => { pushExtra('regexp-escape', 'info', 'RegExp.escape() (ES2025)', linha); }],
217
+ [/Error\.isError\s*\(/g, 'error-is-error', (linha) => { pushExtra('error-is-error', 'info', 'Error.isError() (ES2026)', linha); }],
218
+ [/Array\.fromAsync\s*\(/g, 'array-from-async', (linha) => { pushExtra('array-from-async', 'info', 'Array.fromAsync() (ES2026)', linha); }],
219
+ [/\bIterator\.from\s*\(/g, 'iterator-from', (linha) => { pushExtra('iterator-from', 'info', 'Iterator.from() (ES2025)', linha); }],
220
+ ];
221
+ for (const [pattern, , fn] of esPatterns) {
222
+ let m;
223
+ while ((m = pattern.exec(src)) !== null) {
224
+ const position = m.index;
225
+ if (!isInStringOrComment(src, position)) {
226
+ const linha = src.substring(0, position).split('\n').length;
227
+ fn(linha);
228
+ }
229
+ }
230
+ }
205
231
  // Template literal overuse detection via text fallback
206
232
  const templateLiteralPadrao = /`([^`]{0,10})`/g;
207
233
  let match;
208
234
  while ((match = templateLiteralPadrao.exec(src)) !== null) {
209
235
  const content = match[1];
210
236
  if (content && !content.includes('${') && content.length < 10) {
211
- const position = match.index;
212
- if (position == null) {
213
- continue;
214
- }
237
+ const position = match.index ?? 0;
215
238
  if (!isInStringOrComment(src, position)) {
216
239
  const linha = src.substring(0, position).split('\n').length;
217
240
  pushExtra('template-literal-overuse', 'info', messages.DetectorConstrucoesSintaticasMensagens.templateLiteralOveruse, linha);
@@ -257,8 +257,8 @@ function analisarDependencias(packageJson) {
257
257
  return evidencias;
258
258
  }
259
259
  const deps = {
260
- ...(packageJson.dependencies || {}),
261
- ...(packageJson.devDependencies || {})
260
+ ...(packageJson.dependencies ?? {}),
261
+ ...(packageJson.devDependencies ?? {})
262
262
  };
263
263
  if (config.VERBOSE) {
264
264
  console.log(DetectorContextoExtraMensagens.debugDependencias, Object.keys(deps));
@@ -283,7 +283,7 @@ function analisarScripts(packageJson) {
283
283
  if (!packageJson) {
284
284
  return evidencias;
285
285
  }
286
- const scripts = packageJson.scripts || {};
286
+ const scripts = packageJson.scripts ?? {};
287
287
  for (const [tecnologia, padroes] of Object.entries(PADROES_TECNOLOGIA)) {
288
288
  for (const script of padroes.scripts) {
289
289
  if (Object.keys(scripts).some(key => key.includes(script) || scripts[key].includes(script))) {
@@ -304,7 +304,7 @@ function analisarEstrutura(estruturaDetectada) {
304
304
  for (const [tecnologia, padroes] of Object.entries(PADROES_TECNOLOGIA)) {
305
305
  for (const estrutura of padroes.estrutura) {
306
306
  // Verificação mais rigorosa para evitar falsos positivos
307
- const matchExato = estruturaDetectada.find(dir => {
307
+ const matchExato = estruturaDetectada?.find(dir => {
308
308
  // Match exato do caminho
309
309
  if (dir === estrutura) {
310
310
  return true;
@@ -432,7 +432,7 @@ function analisarPadroesCodigo(arquivos) {
432
432
  */
433
433
  function verificarAntiPatterns(arquivos, tecnologia) {
434
434
  const padraoTecnologia = PADROES_TECNOLOGIA[tecnologia];
435
- if (!padraoTecnologia.antiPatterns) {
435
+ if (padraoTecnologia.antiPatterns.length === 0) {
436
436
  return false; // Sem anti-patterns definidos
437
437
  }
438
438
  for (const arquivo of arquivos) {
@@ -584,7 +584,7 @@ export function detectarContextoInteligente(estruturaDetectada, arquivos, packag
584
584
  let confiancaTotal = calcularConfiancaTotal(evidencias);
585
585
  // Verificação de dependências obrigatórias para evitar falsos positivos
586
586
  const padraoTecnologia = PADROES_TECNOLOGIA[tecnologia];
587
- if (padraoTecnologia && padraoTecnologia.dependencias.length > 0) {
587
+ if (padraoTecnologia.dependencias.length > 0) {
588
588
  const temDependenciaObrigatoria = evidencias.some(erro => erro.tipo === 'dependencia' && padraoTecnologia.dependencias.includes(erro.valor));
589
589
  // Se não tem nenhuma dependência obrigatória, penalizar severamente
590
590
  if (!temDependenciaObrigatoria) {
@@ -107,7 +107,7 @@ const visitorMemoria = {
107
107
  return;
108
108
  }
109
109
  // Detect closures that return functions referencing large objects
110
- if (path.node.body && textoTitulo.isBlockStatement(path.node.body)) {
110
+ if (textoTitulo.isBlockStatement(path.node.body)) {
111
111
  let hasReturnFunction = false;
112
112
  let referencesLargeData = false;
113
113
  try {
@@ -60,8 +60,8 @@ const ANALISTA = {
60
60
  let sugestao = '';
61
61
  // Detectar padrões específicos
62
62
  if (anyMatch[1] !== 'any') {
63
- mensagem = messages.DetectorJsTsMensagens.tipoAnyComUtilidade(varNome ?? '', anyMatch[1] ?? 'any');
64
- sugestao = messages.DetectorJsTsMensagens.tipoAnyComUtilidadeSugestao(anyMatch[1] ?? 'any');
63
+ mensagem = messages.DetectorJsTsMensagens.tipoAnyComUtilidade(varNome ?? '', anyMatch[1]);
64
+ sugestao = messages.DetectorJsTsMensagens.tipoAnyComUtilidadeSugestao(anyMatch[1]);
65
65
  }
66
66
  else if (/catch\s*\(\s*\w+\s*:\s*any\s*\)/.test(lineContext)) {
67
67
  mensagem = messages.DetectorJsTsMensagens.anyCatchBlock(varNome ?? undefined);
@@ -252,6 +252,37 @@ const ANALISTA = {
252
252
  contexto: lineContext
253
253
  });
254
254
  }
255
+ // ─── DETECTAR 'as' QUE PODEM SER SUBSTITUÍDOS POR 'satisfies' ─
256
+ const asTypePadrao = /\bas\s+([A-Za-z_$][A-Za-z0-9_$.]+)\b(?!\s*[=(])/g;
257
+ let asTypeMatch;
258
+ while ((asTypeMatch = asTypePadrao.exec(src)) !== null) {
259
+ const position = asTypeMatch.index ?? 0;
260
+ if (isInStringOrComment(src, position)) {
261
+ continue;
262
+ }
263
+ const linha = splitLines(src.substring(0, position)).length;
264
+ const lineContext = splitLines(src)[linha - 1]?.trim() || '';
265
+ // Skip if any type as it's already caught above
266
+ if (asTypeMatch[1] === 'any') {
267
+ continue;
268
+ }
269
+ // Skip if used in destructuring patterns (as newName)
270
+ if (/:\s*\w+\s+as\s+\w+/.test(lineContext)) {
271
+ continue;
272
+ }
273
+ if (shouldSuppressOccurrence('tipo-inseguro-as-satisfies', relPath)) {
274
+ continue;
275
+ }
276
+ const mensagemCompleta = `${messages.DetectorJsTsMensagens.satisfiesAvailable} | [IDEIA] ${messages.DetectorJsTsMensagens.satisfiesAvailableSugestao}`;
277
+ ocorrencias.push({
278
+ tipo: 'tipo-inseguro-as-satisfies',
279
+ nivel: 'info',
280
+ mensagem: mensagemCompleta,
281
+ relPath,
282
+ linha,
283
+ contexto: lineContext
284
+ });
285
+ }
255
286
  // Detectar uso de unknown
256
287
  const unknownPadrao = /:\s*unknown\b/g;
257
288
  let unknownMatch;
@@ -83,7 +83,7 @@ function collectPhpIssues(src, relPath) {
83
83
  // --- Code Quality: long function/method ---
84
84
  const funcMatches = src.matchAll(/(?:^|\n)\s*(?:public|private|protected|static)?\s*function\s+\w+\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{/g);
85
85
  for (const funcMatch of funcMatches) {
86
- const startIdx = (funcMatch.index ?? 0) + (funcMatch[0].length ?? 0);
86
+ const startIdx = funcMatch.index + funcMatch[0].length;
87
87
  let braceCount = 1;
88
88
  let endIdx = startIdx;
89
89
  for (let i = startIdx; i < src.length && braceCount > 0; i++) {
@@ -98,7 +98,7 @@ function collectPhpIssues(src, relPath) {
98
98
  const body = src.slice(startIdx, endIdx);
99
99
  const lines = body.split('\n').length;
100
100
  if (lines > 60) {
101
- const line = lineOf(funcMatch.index ?? 0);
101
+ const line = lineOf(funcMatch.index);
102
102
  ocorrencias.push(warn(messages.PhpMensagens.longFunction, relPath, line));
103
103
  }
104
104
  }
@@ -111,7 +111,7 @@ function collectPhpIssues(src, relPath) {
111
111
  }
112
112
  // --- Style: naming convention (snake_case) ---
113
113
  for (const match of scanWithoutStrings.matchAll(/\bfunction\s+([a-z][a-zA-Z0-9]*)\s*\(/g)) {
114
- const funcName = match[1] ?? '';
114
+ const funcName = match[1];
115
115
  if (/^[a-z]+[A-Z]/.test(funcName)) {
116
116
  const line = lineOf(match.index);
117
117
  ocorrencias.push(warn(messages.PhpMensagens.camelCaseFunction, relPath, line, messages.SeverityNiveis.suggestion));
@@ -48,7 +48,7 @@ function detectBestPracticesIssues(src, relPath) {
48
48
  // Magic numbers (numeric literals that aren't 0, 1, -1, or common config values)
49
49
  for (const match of scan.matchAll(/(?<!\$)[\s(,=[+\-*/%&|^]=?](\d{3,})\b(?!\s*=>)/g)) {
50
50
  const line = lineOf(match.index);
51
- const context = scan.slice(Math.max(0, (match.index ?? 0) - 40), match.index ?? 0);
51
+ const context = scan.slice(Math.max(0, match.index - 40), match.index);
52
52
  if (!context.includes('define') && !context.includes('const') && !context.includes('LIMIT') && !context.includes('offset') && !context.includes('count') && !context.includes('max') && !context.includes('min') && !context.includes('timeout') && !context.includes('port') && !context.includes('sleep')) {
53
53
  ocorrencias.push({
54
54
  relPath,
@@ -62,8 +62,8 @@ function detectBestPracticesIssues(src, relPath) {
62
62
  }
63
63
  // Complex functions (cyclomatic complexity via brace counting)
64
64
  for (const funcMatch of scan.matchAll(/(?:^|\n)\s*(?:public|private|protected|static)?\s*function\s+\w+\s*\([^)]*\)\s*(?::\s*\w+(?:\s*\|\s*\w+)*)?\s*\{/g)) {
65
- const funcStart = funcMatch.index ?? 0;
66
- const bodyStart = funcStart + (funcMatch[0].length ?? 0);
65
+ const funcStart = funcMatch.index;
66
+ const bodyStart = funcStart + funcMatch[0].length;
67
67
  let braceCount = 1;
68
68
  let bodyEnd = bodyStart;
69
69
  for (let i = bodyStart; i < scan.length && braceCount > 0; i++) {
@@ -95,7 +95,7 @@ function detectBestPracticesIssues(src, relPath) {
95
95
  for (const op of riskyOps) {
96
96
  for (const match of scan.matchAll(new RegExp(`\\b${op}\\s*\\(`, 'gi'))) {
97
97
  const line = lineOf(match.index);
98
- const before = scan.slice(Math.max(0, (match.index ?? 0) - 100), match.index ?? 0);
98
+ const before = scan.slice(Math.max(0, match.index - 100), match.index);
99
99
  if (!before.includes('@') && !before.includes('try') && !before.includes('if') && !/(?:if\s*\(|try\s*\{)/.test(before)) {
100
100
  ocorrencias.push({
101
101
  relPath,
@@ -111,7 +111,7 @@ function detectBestPracticesIssues(src, relPath) {
111
111
  // Superglobal access without filtering
112
112
  for (const match of scan.matchAll(/\$(?:_GET|_POST|_REQUEST|_COOKIE|_SERVER)\s*\[/gi)) {
113
113
  const line = lineOf(match.index);
114
- const before = scan.slice(Math.max(0, (match.index ?? 0) - 150), match.index ?? 0);
114
+ const before = scan.slice(Math.max(0, match.index - 150), match.index);
115
115
  if (!before.includes('filter_input') && !before.includes('filter_var') && !before.includes('htmlspecialchars') && !before.includes('trim') && !before.includes('strip_tags') && !before.includes('intval') && !/=\s*(int|float|string|bool)\s*\$/.test(before)) {
116
116
  ocorrencias.push({
117
117
  relPath,