@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
@@ -322,6 +322,47 @@ function detectarAsyncSemTryCatch(src, problemas) {
322
322
  }
323
323
  }
324
324
  }
325
+ function detectarCookieInseguro(callee, args, path, problemas) {
326
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier' && callee.property.name === 'cookie') {
327
+ const object = callee.object;
328
+ const isRequest = object.type === 'Identifier' && (object.name === 'req' || object.name === 'request');
329
+ if (!isRequest) {
330
+ const options = args[2];
331
+ let hasHttpOnly = false;
332
+ if (options.type === 'ObjectExpression') {
333
+ hasHttpOnly = options.properties.some((prop) => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && prop.key.name === 'httpOnly' && (prop.value.type === 'BooleanLiteral' ? prop.value.value : false));
334
+ }
335
+ if (!hasHttpOnly) {
336
+ problemas.push({
337
+ tipo: 'insecure-cookie',
338
+ descricao: 'Cookie configurado sem a flag httpOnly',
339
+ severidade: 'media',
340
+ linha: path.node.loc?.start.line ?? 0,
341
+ sugestao: 'Sempre use httpOnly: true para evitar acesso via JavaScript (XSS)'
342
+ });
343
+ }
344
+ }
345
+ }
346
+ }
347
+ function detectarSQLInjectionAST(callee, args, path, problemas) {
348
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier' && ['query', 'execute', 'raw', 'queryRaw', 'executeRaw'].includes(callee.property.name)) {
349
+ const firstArg = args[0];
350
+ const isUnsafe = firstArg.type === 'TemplateLiteral' && firstArg.expressions.length > 0 || firstArg.type === 'BinaryExpression' && firstArg.operator === '+';
351
+ if (isUnsafe) {
352
+ const code = firstArg.type === 'TemplateLiteral' ? firstArg.quasis.map((delimitadorString) => delimitadorString.value.raw).join('') : '';
353
+ const temParametros = /['"`].*(\?|\$\d|:\w+).*['"`]/.test(code);
354
+ if (!temParametros) {
355
+ problemas.push({
356
+ tipo: 'sql-injection',
357
+ descricao: 'Possível SQL Injection detectada via AST (concatenação no primeiro argumento)',
358
+ severidade: 'critica',
359
+ linha: path.node.loc?.start.line ?? 0,
360
+ sugestao: 'Use queries parametrizadas ao invés de concatenar strings ou template literals com variáveis'
361
+ });
362
+ }
363
+ }
364
+ }
365
+ }
325
366
  function detectarProblemasAST(ast, problemas) {
326
367
  try {
327
368
  traverse(ast.node, {
@@ -351,48 +392,8 @@ function detectarProblemasAST(ast, problemas) {
351
392
  sugestao: 'Use função ao invés de string'
352
393
  });
353
394
  }
354
- // 2. res.cookie() sem httpOnly
355
- if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier' && callee.property.name === 'cookie') {
356
- const object = callee.object;
357
- const isRequest = object.type === 'Identifier' && (object.name === 'req' || object.name === 'request');
358
- if (!isRequest) {
359
- // Heurística: assume-se que se não é req/request, é provável ser a resposta (res)
360
- const options = args[2];
361
- let hasHttpOnly = false;
362
- if (options.type === 'ObjectExpression') {
363
- hasHttpOnly = options.properties.some(prop => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && prop.key.name === 'httpOnly' && (prop.value.type === 'BooleanLiteral' ? prop.value.value : false));
364
- }
365
- if (!hasHttpOnly) {
366
- problemas.push({
367
- tipo: 'insecure-cookie',
368
- descricao: 'Cookie configurado sem a flag httpOnly',
369
- severidade: 'media',
370
- linha: path.node.loc?.start.line ?? 0,
371
- sugestao: 'Sempre use httpOnly: true para evitar acesso via JavaScript (XSS)'
372
- });
373
- }
374
- }
375
- }
376
- // 3. SQL Injection (básico via AST)
377
- if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier' && ['query', 'execute', 'raw', 'queryRaw', 'executeRaw'].includes(callee.property.name)) {
378
- const firstArg = args[0];
379
- // Se o primeiro argumento é uma TemplateLiteral com expressões ou uma BinaryExpression (+)
380
- const isUnsafe = firstArg && (firstArg.type === 'TemplateLiteral' && firstArg.expressions.length > 0 || firstArg.type === 'BinaryExpression' && firstArg.operator === '+');
381
- if (isUnsafe) {
382
- // Verificar se parece usar parâmetros de qualquer forma
383
- const code = firstArg.type === 'TemplateLiteral' ? firstArg.quasis.map(delimitadorString => delimitadorString.value.raw).join('') : '';
384
- const temParametros = /['"`].*(\?|\$\d|:\w+).*['"`]/.test(code);
385
- if (!temParametros) {
386
- problemas.push({
387
- tipo: 'sql-injection',
388
- descricao: 'Possível SQL Injection detectada via AST (concatenação no primeiro argumento)',
389
- severidade: 'critica',
390
- linha: path.node.loc?.start.line ?? 0,
391
- sugestao: 'Use queries parametrizadas ao invés de concatenar strings ou template literals com variáveis'
392
- });
393
- }
394
- }
395
- }
395
+ detectarCookieInseguro(callee, args, path, problemas);
396
+ detectarSQLInjectionAST(callee, args, path, problemas);
396
397
  }
397
398
  });
398
399
  }
@@ -4,6 +4,32 @@ import { config, getAllExpectedDirNames, getDirVariantPattern, getNameConvention
4
4
  import { messages } from '../../core/messages/index.js';
5
5
  import { grafoDependencias } from './detector-dependencies.js';
6
6
  export const sinaisDetectados = {};
7
+ function verificarConvencoesNomesDiretorios(ocorrencias, caminhosNorm) {
8
+ const expectedDirs = getAllExpectedDirNames();
9
+ if (expectedDirs.length === 0) {
10
+ return;
11
+ }
12
+ const topLevelDirs = new Set(caminhosNorm.filter(caminho => caminho.includes('/') && !caminho.startsWith('node_modules/') && !caminho.startsWith('dist/')).map(caminho => caminho.split('/')[0]));
13
+ const configuredNames = new Set(Object.values(getNameConventions()).filter((valor) => typeof valor === 'string' && valor.trim().length > 0).map(valor => valor.trim().toLowerCase()));
14
+ for (const { key, expected } of expectedDirs) {
15
+ const expectedLower = expected.toLowerCase();
16
+ const match = [...topLevelDirs].find(diretorio => diretorio.toLowerCase() === expectedLower);
17
+ if (!match) {
18
+ const variantPattern = getDirVariantPattern(key);
19
+ const foundVariant = [...topLevelDirs].find(diretorio => variantPattern.test(diretorio));
20
+ if (foundVariant && !configuredNames.has(foundVariant.toLowerCase())) {
21
+ ocorrencias.push({
22
+ tipo: 'name-convention',
23
+ nivel: 'aviso',
24
+ mensagem: messages.DetectorEstruturaMensagens.nomeDiretorioNaoConforme(foundVariant, expected),
25
+ origem: 'detector-estrutura',
26
+ relPath: `[raiz do projeto]`,
27
+ linha: 0
28
+ });
29
+ }
30
+ }
31
+ }
32
+ }
7
33
  /**
8
34
  * Analisa a estrutura do projeto e detecta padrões como monorepo, fullstack, mistura de src/packages, etc.
9
35
  * Retorna ocorrências para cada sinal relevante encontrado.
@@ -24,8 +50,8 @@ export const detectorEstrutura = {
24
50
  // Conjuntos para buscas O(1) e deduplicação implícita
25
51
  const setCaminhos = new Set(caminhos);
26
52
  // Detecta contexto geral do projeto para análise inteligente
27
- const arquivoPrincipal = caminhos.find(caminho => /package\.json$/.test(caminho)) ?? caminhos[0] ?? '';
28
- const conteudoPrincipal = contexto.arquivos.find(arquivo => arquivo.relPath === arquivoPrincipal)?.content ?? '';
53
+ const arquivoPrincipal = caminhos?.find(caminho => /package\.json$/.test(caminho)) ?? caminhos[0];
54
+ const conteudoPrincipal = contexto.arquivos?.find(arquivo => arquivo.relPath === arquivoPrincipal)?.content ?? '';
29
55
  const contextoProjeto = detectarContextoProjeto({
30
56
  arquivo: arquivoPrincipal,
31
57
  conteudo: conteudoPrincipal,
@@ -160,8 +186,8 @@ export const detectorEstrutura = {
160
186
  // Múltiplos entrypoints
161
187
  // Lista de entrypoints potencialmente grande em repositórios com dependências; filtra ignorados
162
188
  const entrypointsAll = caminhosNorm.filter(caminho => /(^|[\\/])(cli|index|main)\.(ts|js)$/.test(caminho));
163
- const ignoredDyn = config.INCLUDE_EXCLUDE_RULES.globalExcludeGlob ?? [];
164
- const entrypoints = entrypointsAll.filter(caminho => !micromatch.isMatch(caminho, ignoredDyn || [])).sort();
189
+ const ignoredDyn = config.INCLUDE_EXCLUDE_RULES.globalExcludeGlob;
190
+ const entrypoints = entrypointsAll.filter(caminho => !micromatch.isMatch(caminho, ignoredDyn)).sort();
165
191
  if (entrypoints.length > 1) {
166
192
  const MAX_LIST = 20;
167
193
  if (entrypoints.length > MAX_LIST) {
@@ -220,30 +246,7 @@ export const detectorEstrutura = {
220
246
  linha: 0
221
247
  });
222
248
  }
223
- // Verifica convenções de nomes de diretórios
224
- const expectedDirs = getAllExpectedDirNames();
225
- if (expectedDirs.length > 0) {
226
- const topLevelDirs = new Set(caminhosNorm.filter(caminho => caminho.includes('/') && !caminho.startsWith('node_modules/') && !caminho.startsWith('dist/')).map(caminho => caminho.split('/')[0]));
227
- const configuredNames = new Set(Object.values(getNameConventions()).filter((valor) => typeof valor === 'string' && valor.trim().length > 0).map(valor => valor.trim().toLowerCase()));
228
- for (const { key, expected } of expectedDirs) {
229
- const expectedLower = expected.toLowerCase();
230
- const match = [...topLevelDirs].find(diretorio => diretorio.toLowerCase() === expectedLower);
231
- if (!match) {
232
- const variantPattern = getDirVariantPattern(key);
233
- const foundVariant = [...topLevelDirs].find(diretorio => variantPattern.test(diretorio));
234
- if (foundVariant && !configuredNames.has(foundVariant.toLowerCase())) {
235
- ocorrencias.push({
236
- tipo: 'name-convention',
237
- nivel: 'aviso',
238
- mensagem: messages.DetectorEstruturaMensagens.nomeDiretorioNaoConforme(foundVariant, expected),
239
- origem: 'detector-estrutura',
240
- relPath: `[raiz do projeto]`,
241
- linha: 0
242
- });
243
- }
244
- }
245
- }
246
- }
249
+ verificarConvencoesNomesDiretorios(ocorrencias, caminhosNorm);
247
250
  return Array.isArray(ocorrencias) ? ocorrencias : [];
248
251
  }
249
252
  };
@@ -82,8 +82,8 @@ export const analistaGithubActionsGlobal = {
82
82
  });
83
83
  }
84
84
  // README
85
- const readme = ctx.arquivos.find(arquivo => /README\.md/i.test(arquivo.relPath ?? ''));
86
- const content = readme ? readme.content ?? '' : '';
85
+ const readme = ctx.arquivos?.find(arquivo => /README\.md/i.test(arquivo.relPath));
86
+ const content = readme?.content ?? '';
87
87
  if (readme && !/Code of Conduct|Código de Conduta/i.test(content)) {
88
88
  ores.push({
89
89
  tipo: 'GITHUB_ACTIONS_DOC_GOVERNANCE_MISSING',
@@ -272,7 +272,7 @@ function analisarEstrutura(wf, probs) {
272
272
  }
273
273
  // Detect Secrets in generic maps (for environment snippets in tests)
274
274
  for (const [chave, valor] of Object.entries(wf)) {
275
- if (/(KEY|TOKEN|SECRET|PASSWORD)/i.test(chave) && valor && typeof valor !== 'object' && !String(valor).includes('${{')) {
275
+ if (/(KEY|TOKEN|SECRET|PASSWORD)/i.test(chave) && valor && typeof valor !== 'object' && (typeof valor !== 'string' || !valor.includes('${{'))) {
276
276
  probs.push({
277
277
  tipo: 'env-sensivel',
278
278
  descricao: `Secret hardcoded em ${chave}`,
@@ -344,9 +344,6 @@ function analisarEstrutura(wf, probs) {
344
344
  }
345
345
  }
346
346
  function analisarStep(string, probs) {
347
- if (!string) {
348
- return;
349
- }
350
347
  // Pinning - only for non-verified orgs
351
348
  if (string.uses && /@v\d+/.test(string.uses)) {
352
349
  const actionRef = string.uses.split('@')[0];
@@ -369,7 +366,7 @@ function analisarStep(string, probs) {
369
366
  // Env
370
367
  if (string.env) {
371
368
  for (const [chave, valor] of Object.entries(string.env)) {
372
- if (/(KEY|TOKEN|SECRET|PASSWORD)/i.test(chave) && valor && typeof valor !== 'object' && !String(valor).includes('${{')) {
369
+ if (/(KEY|TOKEN|SECRET|PASSWORD)/i.test(chave) && valor && typeof valor !== 'object' && (typeof valor !== 'string' || !valor.includes('${{'))) {
373
370
  probs.push({
374
371
  tipo: 'env-sensivel',
375
372
  descricao: `Env ${chave} hardcoded`,
@@ -451,7 +448,7 @@ const ACTIONS_AUTO_EXPLICATIVAS = [
451
448
  */
452
449
  function analisarStepsSemNome(steps, probs) {
453
450
  for (const string of steps) {
454
- if (!string || string.name) {
451
+ if (string.name) {
455
452
  continue;
456
453
  }
457
454
  if (string.uses || string.run) {
@@ -19,12 +19,7 @@ export const detectorWorkflowAcessibilidade = {
19
19
  }
20
20
  const ocorrencias = [];
21
21
  const linhas = src.split('\n');
22
- let hasTimeout = false;
23
- linhas.forEach((linha) => {
24
- if (/timeout-minutes/.test(linha)) {
25
- hasTimeout = true;
26
- }
27
- });
22
+ const hasTimeout = linhas.some(linha => /timeout-minutes/.test(linha));
28
23
  if (!hasTimeout) {
29
24
  ocorrencias.push(criarOcorrencia({
30
25
  tipo: 'workflow-sem-timeout',
@@ -46,9 +41,6 @@ export function detectarProblemasAcessibilidade(workflow) {
46
41
  }
47
42
  let hasTimeout = wf['timeout-minutes'] !== undefined;
48
43
  for (const [, job] of Object.entries(wf.jobs)) {
49
- if (!job) {
50
- continue;
51
- }
52
44
  if (job['timeout-minutes']) {
53
45
  hasTimeout = true;
54
46
  }
@@ -56,15 +56,12 @@ export const detectorWorkflowEstrutura = {
56
56
  try {
57
57
  const doc = parseDocument(src);
58
58
  const workflow = doc.toJS();
59
- if (!workflow || typeof workflow !== 'object') {
59
+ if (!workflow) {
60
60
  return ocorrencias;
61
61
  }
62
62
  const jobs = workflow.jobs ?? {};
63
63
  const jobNames = Object.keys(jobs);
64
64
  for (const [jobId, job] of Object.entries(jobs)) {
65
- if (!job) {
66
- continue;
67
- }
68
65
  // --- 1. Jobs órfãos (needs referencia job inexistente) ---
69
66
  if (job.needs) {
70
67
  const needsList = Array.isArray(job.needs) ? job.needs : [job.needs];
@@ -28,7 +28,7 @@ export const detectorWorkflowTriggerInseguro = {
28
28
  try {
29
29
  const doc = parseDocument(src);
30
30
  const workflow = doc.toJS();
31
- if (!workflow || typeof workflow !== 'object') {
31
+ if (!workflow) {
32
32
  return ocorrencias;
33
33
  }
34
34
  const onConfig = workflow.on;
@@ -51,7 +51,7 @@ export const detectorWorkflowTriggerInseguro = {
51
51
  // Workflow disparado por tags, não por branches - não aplicar esta regra
52
52
  }
53
53
  else {
54
- const branches = typeof pushConf === 'object' && pushConf?.branches ? Array.isArray(pushConf.branches) ? pushConf.branches : [pushConf.branches] : typeof pushConf === 'object' && pushConf?.branches_ignore ? Array.isArray(pushConf.branches_ignore) ? pushConf.branches_ignore : [pushConf.branches_ignore] : undefined;
54
+ const branches = typeof pushConf === 'object' && pushConf.branches ? Array.isArray(pushConf.branches) ? pushConf.branches : [pushConf.branches] : typeof pushConf === 'object' && pushConf.branches_ignore ? Array.isArray(pushConf.branches_ignore) ? pushConf.branches_ignore : [pushConf.branches_ignore] : undefined;
55
55
  // Detectar push sem filtro de branches (triggeria em todos os branches)
56
56
  if (typeof pushConf === 'object' && !pushConf.branches && !pushConf.branches_ignore && !pushConf.tags || Array.isArray(pushConf) || typeof pushConf === 'string') {
57
57
  ocorrencias.push(criarOcorrencia({
@@ -124,7 +124,7 @@ export const detectorWorkflowTriggerInseguro = {
124
124
  // --- 4. Schedule em branches sensíveis ---
125
125
  if (onConfig.schedule) {
126
126
  const pushConf = onConfig.push;
127
- const targetBranches = typeof pushConf === 'object' && pushConf?.branches ? Array.isArray(pushConf.branches) ? pushConf.branches : [pushConf.branches] : undefined;
127
+ const targetBranches = typeof pushConf === 'object' && pushConf.branches ? Array.isArray(pushConf.branches) ? pushConf.branches : [pushConf.branches] : undefined;
128
128
  if (targetBranches) {
129
129
  for (const branch of targetBranches) {
130
130
  if (typeof branch === 'string' && branch.toLowerCase() === 'production') {
@@ -154,15 +154,16 @@ export const detectorWorkflowTriggerInseguro = {
154
154
  }
155
155
  // --- 6. Verificar se workflow executa actions perigosas em triggers de push amplo ---
156
156
  if (onConfig.push && !onConfig.pull_request) {
157
+ const sectionPush = onConfig.push;
157
158
  // Se push tem apenas tags, não é push em branches
158
- const isPushToTags = onConfig.push.tags && !onConfig.push.branches && !onConfig.push['branches-ignore'];
159
+ const isPushToTags = sectionPush.tags && !sectionPush.branches && !sectionPush['branches-ignore'];
159
160
  if (!isPushToTags) {
160
161
  const linhas = splitLines(src);
161
162
  const hasDangerousAction = linhas.some(linha => {
162
163
  const usesMatch = linha.match(/uses:\s*(.+)/);
163
164
  return usesMatch && DANGEROUS_ACTIONS.some(arquivo => linha.includes(arquivo));
164
165
  });
165
- const isPushToAllBranches = !onConfig.push.branches && !onConfig.push['branches-ignore'];
166
+ const isPushToAllBranches = !sectionPush.branches && !sectionPush['branches-ignore'];
166
167
  if (isPushToAllBranches && hasDangerousAction) {
167
168
  ocorrencias.push(criarOcorrencia({
168
169
  tipo: 'trigger-push-ampla-com-actions-perigosas',
@@ -23,7 +23,7 @@ export const analistaGitLabCI = {
23
23
  // 2. Análise Estrutural via YAML AST (para detecções mais complexas)
24
24
  const doc = parseDocument(conteudo);
25
25
  const pipeline = doc.toJS();
26
- if (pipeline) {
26
+ {
27
27
  // Exemplo: Detecção de jobs sem stage definido
28
28
  const stages = pipeline.stages ?? ['build', 'test', 'deploy'];
29
29
  void stages; // Reservado para futuras detecções de stages inválidos
@@ -34,7 +34,7 @@ export const analistaGitLabCI = {
34
34
  }
35
35
  // Se o valor for um objeto com 'script', provavelmente é um job
36
36
  const job = value;
37
- if (typeof job === 'object' && job !== null && (job.script || job.trigger || job.extends)) {
37
+ if (job.script || job.trigger || job.extends) {
38
38
  // Detecção de job muito longo (ex: mais de 15 linhas de script)
39
39
  if (Array.isArray(job.script) && job.script.length > 15) {
40
40
  ocorrencias.push({
@@ -15,9 +15,6 @@ export const detectorGitLabCIEstrutura = {
15
15
  try {
16
16
  const doc = parseDocument(src);
17
17
  const pipeline = doc.toJS();
18
- if (!pipeline) {
19
- return ocorrencias;
20
- }
21
18
  const stages = pipeline.stages;
22
19
  if (stages && stages.length > 5) {
23
20
  ocorrencias.push(criarOcorrencia({
@@ -25,7 +25,7 @@ function collectBestPractices(src, relPath) {
25
25
  // Excessive function length
26
26
  const funcMatches = src.matchAll(/(?:^|\n)\s*func\s+\w+.*?\{/gs);
27
27
  for (const funcMatch of funcMatches) {
28
- const startIdx = (funcMatch.index ?? 0) + (funcMatch[0].length ?? 0);
28
+ const startIdx = funcMatch.index + funcMatch[0].length;
29
29
  let braceCount = 1;
30
30
  let endIdx = startIdx;
31
31
  for (let i = startIdx; i < src.length && braceCount > 0; i++) {
@@ -40,7 +40,7 @@ function collectBestPractices(src, relPath) {
40
40
  const funcBody = src.slice(startIdx, endIdx);
41
41
  const funcLines = funcBody.split('\n').length;
42
42
  if (funcLines > 60) {
43
- const line = lineOf(funcMatch.index ?? 0);
43
+ const line = lineOf(funcMatch.index);
44
44
  ocorrencias.push(warn(messages.GoMensagens.longFunction, relPath, line));
45
45
  }
46
46
  }
@@ -36,7 +36,7 @@ function collectConcurrencyIssues(src, relPath) {
36
36
  }
37
37
  // Select without default case (potential blocking)
38
38
  for (const match of scan.matchAll(/\bselect\s*\{/g)) {
39
- const blockStart = match.index ?? 0;
39
+ const blockStart = match.index;
40
40
  const block = src.slice(blockStart, blockStart + 500);
41
41
  if (!/\bdefault\s*:/m.test(block)) {
42
42
  const line = lineOf(blockStart);
@@ -32,7 +32,7 @@ function collectSecurityIssues(src, relPath) {
32
32
  }
33
33
  // Printf without format string
34
34
  for (const match of scan.matchAll(/\b(fmt\.(?:Print|Sprint|Fprint))\s*\(\s*([^)]+)\)/g)) {
35
- const args = match[2] ?? '';
35
+ const args = match[2];
36
36
  if (/["'`]/.test(args.trim())) {
37
37
  continue;
38
38
  }
@@ -56,7 +56,7 @@ function detectConventions(src, relPath) {
56
56
  if (impMatch) {
57
57
  const path = impMatch[1];
58
58
  if (/\.$/i.test(path)) {
59
- const absIdx = (match.index ?? 0) + block.indexOf(impLine);
59
+ const absIdx = match.index + block.indexOf(impLine);
60
60
  const line = lineOf(absIdx);
61
61
  ocorrencias.push({
62
62
  relPath,
@@ -10,8 +10,8 @@ function warn(message, relPath, line) {
10
10
  }
11
11
  function isElement(node) { return node.type === ElementType.Tag; }
12
12
  function getAttr(el, name) {
13
- const attrs = el.attribs || {};
14
- const valor = attrs[name] ?? attrs[name.toLowerCase()] ?? '';
13
+ const attrs = el.attribs;
14
+ const valor = attrs[name] || attrs[name.toLowerCase()] || '';
15
15
  return typeof valor === 'string' ? valor : '';
16
16
  }
17
17
  function walk(node, visit) {
@@ -32,7 +32,7 @@ function checkDoctype(node) {
32
32
  return /^!doctype\s+html\b/i.test(data);
33
33
  }
34
34
  function validarButton(node, line, relPath, ocorrencias) {
35
- const text = node.children.some(elem => elem.type === ElementType.Text && ((elem).data ?? '').trim().length > 0);
35
+ const text = node.children.some(elem => elem.type === ElementType.Text && (elem).data.trim().length > 0);
36
36
  if (!text && !getAttr(node, 'aria-label') && !getAttr(node, 'title')) {
37
37
  ocorrencias.push(warn(messages.HtmlMensagens.buttonWithoutText, relPath, line));
38
38
  }
@@ -53,7 +53,7 @@ function validarLink(node, line, relPath, ocorrencias) {
53
53
  if (target === '_blank' && !/(noopener|noreferrer)/i.test(getAttr(node, 'rel'))) {
54
54
  ocorrencias.push(warn(messages.HtmlMensagens.linkTargetBlank, relPath, line));
55
55
  }
56
- const attrs = node.attribs || {};
56
+ const attrs = node.attribs;
57
57
  const hasHref = Object.prototype.hasOwnProperty.call(attrs, 'href');
58
58
  const href = getAttr(node, 'href');
59
59
  if (hasHref && href !== '' && href !== '#') {
@@ -71,7 +71,7 @@ function validarImg(node, line, relPath, ocorrencias, isTemplate) {
71
71
  const ariaHidden = getAttr(node, 'aria-hidden').toLowerCase() === 'true';
72
72
  const role = getAttr(node, 'role').toLowerCase();
73
73
  const decorative = ariaHidden || ariaLabel || role === 'presentation' || role === 'none';
74
- const attrs = node.attribs || {};
74
+ const attrs = node.attribs;
75
75
  const dataAttr = Object.keys(attrs).some(chave => /^(data-)?(decorative|icon|symbol)$/i.test(chave));
76
76
  if (!alt && !decorative && !dataAttr && !/\.svg(\?|#|$)/i.test(getAttr(node, 'src'))) {
77
77
  ocorrencias.push(warn(messages.HtmlMensagens.imgWithoutAlt, relPath, line));
@@ -87,7 +87,7 @@ function validarForm(node, line, relPath, ocorrencias) {
87
87
  if (!getAttr(node, 'method')) {
88
88
  ocorrencias.push(warn(messages.HtmlMensagens.formWithoutMethod, relPath, line));
89
89
  }
90
- const attrs = node.attribs || {};
90
+ const attrs = node.attribs;
91
91
  if (!getAttr(node, 'action') && !Object.keys(attrs).some(chave => chave.toLowerCase().startsWith('data-'))) {
92
92
  ocorrencias.push(warn(messages.HtmlMensagens.formWithoutAction, relPath, line));
93
93
  }
@@ -108,7 +108,7 @@ function validarInput(node, line, relPath, ocorrencias) {
108
108
  }
109
109
  function validarScript(node, line, relPath, ocorrencias, isTemplate) {
110
110
  const srcAttr = getAttr(node, 'src');
111
- const children = node.children || [];
111
+ const children = node.children;
112
112
  const text = children.filter((elem) => elem.type === ElementType.Text).map(elem => ((elem).data || '')).join('');
113
113
  if (!srcAttr && text.trim().length > 0) {
114
114
  ocorrencias.push(warn(messages.HtmlMensagens.inlineScript, relPath, line));
@@ -121,7 +121,7 @@ function validarScript(node, line, relPath, ocorrencias, isTemplate) {
121
121
  }
122
122
  }
123
123
  function validarStyle(node, line, relPath, ocorrencias) {
124
- const children = node.children || [];
124
+ const children = node.children;
125
125
  const text = children.filter((elem) => elem.type === ElementType.Text).map(elem => ((elem).data || '')).join('');
126
126
  if (text.trim().length > 0) {
127
127
  ocorrencias.push(warn(messages.HtmlMensagens.inlineStyle, relPath, line));
@@ -140,10 +140,8 @@ const validadores = {
140
140
  };
141
141
  function validateNode(node, tag, line, relPath, ocorrencias, isTemplate) {
142
142
  const validador = validadores[tag];
143
- if (validador) {
144
- validador(node, line, relPath, ocorrencias, isTemplate);
145
- }
146
- const attrs = node.attribs || {};
143
+ validador(node, line, relPath, ocorrencias, isTemplate);
144
+ const attrs = node.attribs;
147
145
  if (Object.keys(attrs).some(attr => INLINE_EVENTS.has(attr.toLowerCase()))) {
148
146
  ocorrencias.push(warn(messages.HtmlMensagens.inlineHandler, relPath, line));
149
147
  }
@@ -171,7 +171,7 @@ function detectSeo(src, relPath) {
171
171
  const targetId = m[1].slice(1);
172
172
  if (!ids.has(targetId)) {
173
173
  const _lineLookup = splitLines(src);
174
- const idx = m.index ?? 0;
174
+ const idx = m.index;
175
175
  const lineNum = src.slice(0, idx).split('\n').length;
176
176
  results.push({ type: 'html-broken-anchor', message: M.brokenAnchor, line: lineNum });
177
177
  }
@@ -182,7 +182,7 @@ function detectSeo(src, relPath) {
182
182
  for (const m of headingMatches) {
183
183
  const level = parseInt(m[1], 10);
184
184
  if (level > lastLevel + 1 && lastLevel > 0) {
185
- const lineNum = src.slice(0, m.index ?? 0).split('\n').length;
185
+ const lineNum = src.slice(0, m.index).split('\n').length;
186
186
  results.push({ type: 'html-heading-hierarchy-skip', message: M.headingHierarchySkip, line: lineNum });
187
187
  }
188
188
  lastLevel = level;
@@ -310,7 +310,7 @@ function detectSemanticHtml(src, relPath) {
310
310
  const prev = ids.get(idValue) ?? 0;
311
311
  ids.set(idValue, prev + 1);
312
312
  if (prev > 0) {
313
- const lineNum = src.slice(0, m.index ?? 0).split('\n').length;
313
+ const lineNum = src.slice(0, m.index).split('\n').length;
314
314
  results.push({ type: 'html-duplicate-id-semantic', message: M.duplicateId, line: lineNum });
315
315
  }
316
316
  }