@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.
- package/README.md +0 -34
- package/dist/analysts/architects/analyst-structure.js +20 -20
- package/dist/analysts/architects/archetypes-custom.js +16 -19
- package/dist/analysts/architects/detector-archetypes.js +43 -36
- package/dist/analysts/architects/orchestrator-archetypes.js +3 -3
- package/dist/analysts/architects/signals-project-advanced.js +26 -28
- package/dist/analysts/architects/signals-project.js +2 -2
- package/dist/analysts/architects/strategist-structure.js +47 -66
- package/dist/analysts/azure-pipelines/analysts/analyst-azure.js +41 -35
- package/dist/analysts/azure-pipelines/corrections/correction-azure.js +22 -19
- package/dist/analysts/azure-pipelines/detectors/detector-azure-performance.js +21 -18
- package/dist/analysts/azure-pipelines/detectors/detector-azure-security.js +25 -20
- package/dist/analysts/azure-pipelines/detectors/detector-azure-structure.js +39 -40
- package/dist/analysts/azure-pipelines/scorers/scorer-azure.js +10 -7
- package/dist/analysts/circleci/analysts/analyst-circleci.js +33 -27
- package/dist/analysts/circleci/corrections/correction-circleci.js +22 -20
- package/dist/analysts/circleci/detectors/detector-circleci-performance.js +23 -19
- package/dist/analysts/circleci/detectors/detector-circleci-security.js +78 -82
- package/dist/analysts/circleci/detectors/detector-circleci-structure.js +22 -22
- package/dist/analysts/converters/convert-registry.js +1 -1
- package/dist/analysts/converters/engines/converter-gha-to-gitlab.js +17 -15
- package/dist/analysts/converters/index.js +1 -1
- package/dist/analysts/corrections/analyst-quick-fixes.js +25 -28
- package/dist/analysts/corrections/analyst-scoring.js +24 -21
- package/dist/analysts/corrections/auto-fix-engine.js +1 -1
- package/dist/analysts/corrections/corrector-structure.js +43 -42
- package/dist/analysts/corrections/fix-alias-imports.js +10 -6
- package/dist/analysts/corrections/fix-md-fences.js +23 -23
- package/dist/analysts/corrections/map-reversion.js +56 -53
- package/dist/analysts/corrections/pruning.js +19 -16
- package/dist/analysts/corrections/quick-fixes/fix-any-to-proper-type.js +57 -61
- package/dist/analysts/corrections/quick-fixes/fix-unknown-to-specific-type.js +30 -30
- package/dist/analysts/corrections/reorganize-barrels.js +13 -13
- package/dist/analysts/corrections/rewrite-testes-aliases.js +23 -22
- package/dist/analysts/corrections/scoring-shared.js +19 -18
- package/dist/analysts/corrections/type-safety/context-analyzer.js +15 -10
- package/dist/analysts/corrections/type-safety/type-analyzer.js +3 -3
- package/dist/analysts/corrections/type-safety/type-validator.js +4 -3
- package/dist/analysts/corrections/type-safety/usage-analyzer.js +39 -42
- package/dist/analysts/css/analysts/analyst-css.js +42 -42
- package/dist/analysts/css/corrections/correction-css.js +19 -11
- package/dist/analysts/css/detectors/detector-css-best-practices.js +129 -118
- package/dist/analysts/css/scorers/scorer-css.js +23 -18
- package/dist/analysts/css-in-js/analysts/analyst-css-in-js.js +24 -17
- package/dist/analysts/css-in-js/corrections/correction-css-in-js.js +31 -16
- package/dist/analysts/css-in-js/detectors/detector-css-in-js-best-practices.js +28 -30
- package/dist/analysts/css-in-js/scorers/scorer-css-in-js.js +79 -54
- package/dist/analysts/css-in-js/shared.js +7 -0
- package/dist/analysts/detectors/detector-architecture.js +91 -85
- package/dist/analysts/detectors/detector-bugs-ml.js +29 -27
- package/dist/analysts/detectors/detector-code-fragile.js +41 -36
- package/dist/analysts/detectors/detector-dependencies.js +5 -5
- package/dist/analysts/detectors/detector-duplications.js +26 -26
- package/dist/analysts/detectors/detector-monorepo.js +51 -45
- package/dist/analysts/detectors/detector-performance.js +24 -17
- package/dist/analysts/detectors/detector-recommendation-architecture.js +40 -36
- package/dist/analysts/detectors/detector-security.js +43 -42
- package/dist/analysts/detectors/detector-structure.js +31 -28
- package/dist/analysts/github-actions/analysts/analyst-github-actions.js +5 -8
- package/dist/analysts/github-actions/detectors/detector-workflow-accessibility.js +1 -9
- package/dist/analysts/github-actions/detectors/detector-workflow-structure.js +1 -4
- package/dist/analysts/github-actions/detectors/detector-workflow-trigger-unsafe.js +6 -5
- package/dist/analysts/gitlab-ci/analysts/analyst-gitlab-ci.js +2 -2
- package/dist/analysts/gitlab-ci/detectors/detector-gitlab-ci-structure.js +0 -3
- package/dist/analysts/go/analysts/analyst-best-practices.js +2 -2
- package/dist/analysts/go/analysts/analyst-concurrency.js +1 -1
- package/dist/analysts/go/analysts/analyst-security.js +1 -1
- package/dist/analysts/go/detectors/detector-conventions.js +1 -1
- package/dist/analysts/html/analysts/analyst-html.js +10 -12
- package/dist/analysts/html/detectors/detector-html.js +3 -3
- package/dist/analysts/js-ts/analysts/analyst-commands-cli.js +22 -22
- package/dist/analysts/js-ts/analysts/analyst-functions-long.js +5 -5
- package/dist/analysts/js-ts/analysts/analyst-patterns-usage.js +6 -2
- package/dist/analysts/js-ts/detectors/detector-anti-patterns-async.js +84 -9
- package/dist/analysts/js-ts/detectors/detector-constructions-syntactic.js +33 -10
- package/dist/analysts/js-ts/detectors/detector-context-smart.js +6 -6
- package/dist/analysts/js-ts/detectors/detector-leaks-memory.js +1 -1
- package/dist/analysts/js-ts/detectors/detector-types-unsafe.js +33 -2
- package/dist/analysts/php/analysts/analyst-php.js +3 -3
- package/dist/analysts/php/detectors/detector-php-best-practices.js +5 -5
- package/dist/analysts/php/detectors/detector-php-security.js +5 -5
- package/dist/analysts/php/scorers/scorer-php.js +2 -2
- package/dist/analysts/plugins/detector-documentation.js +6 -6
- package/dist/analysts/plugins/detector-markdown.js +7 -7
- package/dist/analysts/python/analysts/analyst-python.js +2 -5
- package/dist/analysts/react/analysts/analyst-react-hooks.js +66 -9
- package/dist/analysts/react/analysts/analyst-react.js +46 -2
- package/dist/analysts/react/corrections/correction-react.js +41 -1
- package/dist/analysts/react/detectors/detector-react-best-practices.js +5 -5
- package/dist/analysts/react/scorers/scorer-react.js +36 -1
- package/dist/analysts/registry/autodiscovery.js +2 -2
- package/dist/analysts/rust/analysts/analyst-best-practices.js +42 -3
- package/dist/analysts/rust/analysts/analyst-memory.js +2 -2
- package/dist/analysts/rust/analysts/analyst-rust.js +52 -5
- package/dist/analysts/rust/analysts/analyst-security.js +29 -1
- package/dist/analysts/scorers/scorer.js +5 -5
- package/dist/analysts/shell/analysts/analyst-shell.js +81 -5
- package/dist/analysts/shell/corrections/correction-shell.js +34 -1
- package/dist/analysts/shell/detectors/detector-shell-security.js +88 -0
- package/dist/analysts/shell/scorers/scorer-shell.js +58 -1
- package/dist/analysts/strategists/operator-structure.js +5 -7
- package/dist/analysts/strategists/suggestions-contextuais.js +5 -2
- package/dist/analysts/svg/analysts/analyst-svg.js +1 -0
- package/dist/analysts/tailwind/analysts/analyst-tailwind.js +79 -55
- package/dist/analysts/tailwind/corrections/correction-tailwind.js +108 -9
- package/dist/analysts/tailwind/detectors/detector-tailwind-best-practices.js +122 -7
- package/dist/analysts/tailwind/scorers/scorer-tailwind.js +62 -11
- package/dist/analysts/xml/analysts/analyst-xml.js +2 -2
- package/dist/app/index.js +1 -0
- package/dist/bin/cli-bootstrap.js +6 -4
- package/dist/bin/index.js +6 -4
- package/dist/caretakers/scoring.js +1 -0
- package/dist/cli/commands/command-analysts.js +4 -3
- package/dist/cli/commands/command-azure.js +1 -1
- package/dist/cli/commands/command-circleci.js +1 -1
- package/dist/cli/commands/command-compliance.js +1 -1
- package/dist/cli/commands/command-diagnose.js +10 -13
- package/dist/cli/commands/command-fix-types.js +9 -32
- package/dist/cli/commands/command-formatters.js +2 -2
- package/dist/cli/commands/command-github-actions.js +1 -1
- package/dist/cli/commands/command-gitlab-ci.js +1 -1
- package/dist/cli/commands/command-guardian.js +1 -1
- package/dist/cli/commands/command-imports.js +6 -6
- package/dist/cli/commands/command-jenkins.js +1 -1
- package/dist/cli/commands/command-licenses.js +1 -1
- package/dist/cli/commands/command-marketplace.js +7 -7
- package/dist/cli/commands/command-names.js +3 -8
- package/dist/cli/commands/command-perf.js +7 -9
- package/dist/cli/commands/command-plugins.js +4 -4
- package/dist/cli/diagnostic/auto-fix.js +2 -2
- package/dist/cli/diagnostic/exporters/json-exporter.js +1 -1
- package/dist/cli/diagnostic/exporters/sharded-exporter.js +0 -3
- package/dist/cli/diagnostic/exporters/svg-optimization-exporter.js +1 -1
- package/dist/cli/diagnostic/filters.js +9 -9
- package/dist/cli/diagnostic/handlers/archetype-handler.js +3 -6
- package/dist/cli/diagnostic/handlers/auto-fix-handler.js +4 -4
- package/dist/cli/diagnostic/handlers/guardian-handler.js +1 -1
- package/dist/cli/diagnostic/processing-diagnostic.js +31 -35
- package/dist/cli/diagnostic/processing-helpers.js +2 -2
- package/dist/cli/handlers/fix-types-exporter.js +1 -4
- package/dist/cli/helpers/display-frame.js +5 -5
- package/dist/core/config/auto/auto-fix-config.js +0 -6
- package/dist/core/config/chalk-safe.js +6 -6
- package/dist/core/config/config.js +11 -13
- package/dist/core/config/conventions.js +1 -1
- package/dist/core/config/security.js +2 -2
- package/dist/core/execution/analysis-cache.js +5 -8
- package/dist/core/execution/ast-cache.js +1 -3
- package/dist/core/execution/executor.js +8 -21
- package/dist/core/execution/inquisitor.js +24 -21
- package/dist/core/execution/results.js +1 -0
- package/dist/core/execution/scanner.js +4 -4
- package/dist/core/messages/en/analysts/analyst-github-actions-messages.js +1 -1
- package/dist/core/messages/en/analysts/analyst-patterns-usage-messages.js +1 -0
- package/dist/core/messages/en/analysts/analyst-shell-messages.js +15 -0
- package/dist/core/messages/en/analysts/detector-constructions-syntactic-messages.js +6 -0
- package/dist/core/messages/en/analysts/detector-js-ts-messages.js +27 -0
- package/dist/core/messages/en/analysts/detector-react-messages.js +8 -0
- package/dist/core/messages/en/analysts/detector-shell-messages.js +17 -0
- package/dist/core/messages/en/analysts/detector-tailwind-messages.js +3 -3
- package/dist/core/messages/en/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/en/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/en/core/plugin-messages.js +31 -3
- package/dist/core/messages/en/log/log.js +4 -4
- package/dist/core/messages/en/ui/filter-config.js +1 -5
- package/dist/core/messages/i18n-system.js +3 -3
- package/dist/core/messages/index.js +3 -3
- package/dist/core/messages/ja/analysts/analyst-github-actions-messages.js +1 -1
- package/dist/core/messages/ja/analysts/analyst-patterns-usage-messages.js +1 -0
- package/dist/core/messages/ja/analysts/analyst-shell-messages.js +15 -0
- package/dist/core/messages/ja/analysts/detector-constructions-syntactic-messages.js +6 -0
- package/dist/core/messages/ja/analysts/detector-js-ts-messages.js +27 -0
- package/dist/core/messages/ja/analysts/detector-react-messages.js +8 -0
- package/dist/core/messages/ja/analysts/detector-shell-messages.js +17 -0
- package/dist/core/messages/ja/analysts/detector-tailwind-messages.js +3 -3
- package/dist/core/messages/ja/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/ja/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/ja/core/plugin-messages.js +31 -3
- package/dist/core/messages/ja/log/log.js +4 -4
- package/dist/core/messages/ja/ui/filter-config.js +1 -1
- package/dist/core/messages/pt/analysts/analyst-github-actions-messages.js +1 -1
- package/dist/core/messages/pt/analysts/analyst-patterns-usage-messages.js +1 -0
- package/dist/core/messages/pt/analysts/analyst-shell-messages.js +15 -0
- package/dist/core/messages/pt/analysts/detector-constructions-syntactic-messages.js +6 -0
- package/dist/core/messages/pt/analysts/detector-js-ts-messages.js +27 -0
- package/dist/core/messages/pt/analysts/detector-react-messages.js +8 -0
- package/dist/core/messages/pt/analysts/detector-shell-messages.js +17 -0
- package/dist/core/messages/pt/analysts/detector-tailwind-messages.js +3 -3
- package/dist/core/messages/pt/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/pt/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/pt/core/plugin-messages.js +31 -3
- package/dist/core/messages/pt/log/log-engine.js +6 -6
- package/dist/core/messages/pt/log/log.js +3 -3
- package/dist/core/messages/pt/ui/filter-config.js +1 -1
- package/dist/core/messages/shared/icons.js +3 -3
- package/dist/core/messages/zh/analysts/analyst-github-actions-messages.js +1 -1
- package/dist/core/messages/zh/analysts/analyst-patterns-usage-messages.js +1 -0
- package/dist/core/messages/zh/analysts/analyst-shell-messages.js +15 -0
- package/dist/core/messages/zh/analysts/detector-constructions-syntactic-messages.js +6 -0
- package/dist/core/messages/zh/analysts/detector-js-ts-messages.js +27 -0
- package/dist/core/messages/zh/analysts/detector-react-messages.js +8 -0
- package/dist/core/messages/zh/analysts/detector-shell-messages.js +17 -0
- package/dist/core/messages/zh/analysts/detector-tailwind-messages.js +3 -3
- package/dist/core/messages/zh/analysts/report-circleci-messages.js +7 -7
- package/dist/core/messages/zh/caretakers/caretaker-messages.js +1 -7
- package/dist/core/messages/zh/core/plugin-messages.js +31 -3
- package/dist/core/messages/zh/log/log.js +3 -3
- package/dist/core/messages/zh/ui/filter-config.js +1 -5
- package/dist/core/parsing/filters.js +3 -3
- package/dist/core/parsing/langs/json.js +1 -1
- package/dist/core/parsing/langs/python.js +1 -1
- package/dist/core/parsing/langs/typescript.js +1 -1
- package/dist/core/parsing/parser.js +3 -4
- package/dist/core/parsing/utils.js +1 -0
- package/dist/core/registry/file-registry.js +3 -2
- package/dist/core/registry/paths.js +3 -3
- package/dist/core/reporting/default-reporter.js +2 -2
- package/dist/core/schema/version.js +6 -6
- package/dist/core/workers/worker-executor.js +3 -3
- package/dist/core/workers/worker-pool.js +0 -0
- package/dist/guardian/baseline.js +1 -1
- package/dist/guardian/gpg.js +3 -1
- package/dist/guardian/integrity.js +2 -7
- package/dist/guardian/records.js +7 -1
- package/dist/guardian/result.js +1 -1
- package/dist/guardian/sentinel.js +7 -1
- package/dist/guardian/watcher-hidden.js +6 -1
- package/dist/licenses/fs-utils.js +5 -1
- package/dist/licenses/generate-notices.js +1 -1
- package/dist/licenses/index.js +1 -0
- package/dist/licenses/normalizer.js +10 -9
- package/dist/node.loader.js +224 -4
- package/dist/reports/analise-async-patterns.js +1 -1
- package/dist/reports/filter-smart.js +2 -5
- package/dist/reports/generator-report.js +7 -7
- package/dist/reports/report-archetypes.js +10 -10
- package/dist/reports/report-caretaker-health.js +2 -1
- package/dist/reports/report-patterns-usage.js +1 -1
- package/dist/sdk/analyzer.js +1 -1
- package/dist/shared/data-processing/fragment-report.js +11 -11
- package/dist/shared/data-processing/json.js +1 -1
- package/dist/shared/data-processing/occurrences.js +3 -2
- package/dist/shared/formatters/code-min-formatter.js +1 -1
- package/dist/shared/formatters/engines/prettier.js +1 -1
- package/dist/shared/formatters/engines/stylelint.js +43 -40
- package/dist/shared/formatters/formatter.js +8 -8
- package/dist/shared/formatters/formatters/code.js +3 -3
- package/dist/shared/formatters/formatters/css.js +2 -10
- package/dist/shared/formatters/formatters/dotfiles.js +1 -1
- package/dist/shared/formatters/formatters/html.js +1 -5
- package/dist/shared/formatters/formatters/json.js +0 -3
- package/dist/shared/formatters/formatters/markdown.js +19 -24
- package/dist/shared/formatters/formatters/properties.js +2 -2
- package/dist/shared/formatters/formatters/shell.js +1 -4
- package/dist/shared/formatters/formatters/sql.js +0 -3
- package/dist/shared/formatters/formatters/xml.js +5 -7
- package/dist/shared/formatters/formatters/yaml.js +2 -7
- package/dist/shared/formatters/index.js +1 -1
- package/dist/shared/helpers/framework-detector.js +6 -2
- package/dist/shared/helpers/json.js +1 -1
- package/dist/shared/helpers/magic-constants-whitelist.js +1 -1
- package/dist/shared/helpers/masking.js +17 -17
- package/dist/shared/helpers/reader-report.js +0 -12
- package/dist/shared/helpers/structural-hash.js +3 -2
- package/dist/shared/helpers/structure.js +1 -1
- package/dist/shared/marketplace/registry.js +1 -1
- package/dist/shared/marketplace/remote.js +4 -4
- package/dist/shared/persistence/persistence.js +13 -6
- package/dist/shared/plugins/core-plugin.js +5 -1
- package/dist/shared/plugins/registry.js +3 -2
- package/dist/types/analysts/tailwind-correction.js +2 -0
- package/dist/types/caretakers/imports-barrel.js +1 -0
- package/dist/types/caretakers/index.js +4 -0
- package/dist/types/caretakers/map-reversion.js +1 -0
- package/dist/types/caretakers/pruning.js +1 -0
- package/dist/types/caretakers/scoring.js +1 -0
- package/dist/types/common/analysts.js +1 -1
- package/dist/types/core/config/filters.js +1 -0
- package/dist/types/core/config/index.js +2 -0
- package/dist/types/core/execution/ambiente.js +1 -0
- package/dist/types/core/execution/linguagens.js +1 -0
- package/dist/types/core/execution/parse-errors.js +1 -0
- package/dist/types/core/execution/results.js +1 -0
- package/dist/types/core/execution/structure-json.js +1 -0
- package/dist/types/core/index.js +1 -0
- package/dist/types/core/messages/index.js +1 -0
- package/dist/types/core/messages/log.js +1 -0
- package/dist/types/core/parsing/babel-narrow.js +1 -0
- package/dist/types/core/parsing/index.js +1 -0
- package/dist/types/core/runtime.js +1 -0
- package/dist/types/guardian/index.js +2 -0
- package/dist/types/guardian/integrity.js +7 -0
- package/dist/types/guardian/snapshot.js +1 -0
- package/dist/types/index.js +4 -4
- package/dist/types/licenses/index.js +2 -0
- package/dist/types/processing/display.js +16 -13
- package/dist/types/processing/filters.js +8 -11
- package/dist/types/reports/compliance.js +1 -0
- package/dist/types/reports/streaming.js +1 -0
- package/dist/types/scripts/index.js +1 -0
- package/dist/types/scripts/migrar-aliases.js +1 -0
- package/dist/types/sdk/index.js +1 -0
- package/dist/types/shared/index.js +2 -0
- package/dist/types/vulnerabilities/index.js +2 -0
- package/dist/vulnerabilities/scanner.js +3 -2
- 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 (!
|
|
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:
|
|
14
|
+
return { func: fn, bodyBlock, isAnonymous, params, totalParams: fn.params.length };
|
|
15
15
|
};
|
|
16
|
-
if (textoTitulo.isFunctionDeclaration(node) &&
|
|
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)) &&
|
|
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 (
|
|
62
|
-
nome =
|
|
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' &&
|
|
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 (
|
|
145
|
-
comandoNome =
|
|
144
|
+
if (textoTitulo.isStringLiteral(primeiroArg)) {
|
|
145
|
+
comandoNome = primeiroArg.value;
|
|
146
146
|
}
|
|
147
|
-
const handler = call.arguments
|
|
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
|
|
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 (
|
|
184
|
-
nome =
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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
|
|
9
|
-
const LIMITE_PARAMETROS = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_PARAMETROS
|
|
10
|
-
const LIMITE_ANINHAMENTO = config.ANALISE_LIMITES.FUNCOES_LONGAS.MAX_ANINHAMENTO
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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' &&
|
|
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
|
-
|
|
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 (
|
|
42
|
+
if (textoTitulo.isObjectPattern(declarator.id)) {
|
|
43
43
|
for (const prop of declarator.id.properties) {
|
|
44
|
-
if (textoTitulo.isObjectProperty(prop) &&
|
|
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 (
|
|
149
|
+
if (textoTitulo.isMemberExpression(left) || textoTitulo.isIdentifier(left)) {
|
|
150
150
|
const right = path.node.right;
|
|
151
|
-
if (
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (
|
|
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
|
|
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 (
|
|
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]
|
|
64
|
-
sugestao = messages.DetectorJsTsMensagens.tipoAnyComUtilidadeSugestao(anyMatch[1]
|
|
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 =
|
|
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
|
|
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,
|
|
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
|
|
66
|
-
const bodyStart = funcStart +
|
|
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,
|
|
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,
|
|
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,
|