@mocoto/mahoraga 0.15.1 → 0.15.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/{docs → Docs}/.obsidian/graph.json +1 -1
- package/{docs → Docs}/.obsidian/workspace.json +18 -10
- package/{docs → Docs}/01-arquitetura/ADR-001-estrutura-testes.md +2 -2
- package/Docs/02-componentes/configuracao.md +110 -0
- package/{docs → Docs}/05-referencias/_index.md +1 -0
- package/Docs/06-feedbacks/feedback.md +74 -0
- package/{docs → Docs}/_home.md +4 -4
- package/README.md +12 -2
- package/dist/analysts/detectors/detector-bugs-ml.js +5 -0
- package/dist/analysts/plugins/detector-markdown.js +2 -2
- package/dist/analysts/react/analysts/analyst-react.js +7 -0
- package/dist/cli/diagnostic/filters.js +1 -4
- package/dist/core/config/config.js +2 -3
- package/dist/core/config/excludes-padrao.js +3 -2
- package/dist/reports/report-structure.js +2 -8
- package/dist/shared/helpers/magic-constants-whitelist.js +14 -1
- package/dist/types/processing/filters.js +1 -4
- package/package.json +10 -10
- /package/{docs → Docs}/.obsidian/app.json +0 -0
- /package/{docs → Docs}/.obsidian/appearance.json +0 -0
- /package/{docs → Docs}/.obsidian/community-plugins.json +0 -0
- /package/{docs → Docs}/.obsidian/core-plugins-migration.json +0 -0
- /package/{docs → Docs}/.obsidian/core-plugins.json +0 -0
- /package/{docs → Docs}/01-arquitetura/_index.md +0 -0
- /package/{docs → Docs}/02-componentes/_index.md +0 -0
- /package/{docs → Docs}/02-componentes/supressao-inline.md +0 -0
- /package/{docs → Docs}/03-guias/_index.md +0 -0
- /package/{docs → Docs}/03-guias/contribuindo.md +0 -0
- /package/{docs → Docs}/03-guias/testes.md +0 -0
- /package/{docs → Docs}/04-glossario/_index.md +0 -0
- /package/{docs → Docs}/04-glossario/termos.md +0 -0
- /package/{docs → Docs}/partials/AVISO-PROVENIENCIA.md +0 -0
- /package/{docs → Docs}/templates/ADR.md +0 -0
- /package/{docs → Docs}/templates/componente.md +0 -0
- /package/{docs → Docs}/templates/guia.md +0 -0
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
"type": "split",
|
|
5
5
|
"children": [
|
|
6
6
|
{
|
|
7
|
-
"id": "
|
|
7
|
+
"id": "f49eb26fe94f5853",
|
|
8
8
|
"type": "tabs",
|
|
9
9
|
"children": [
|
|
10
10
|
{
|
|
11
|
-
"id": "
|
|
11
|
+
"id": "8dedf7c146f5cebf",
|
|
12
12
|
"type": "leaf",
|
|
13
13
|
"state": {
|
|
14
14
|
"type": "markdown",
|
|
15
15
|
"state": {
|
|
16
|
-
"file": "
|
|
16
|
+
"file": "03-guias/testes.md",
|
|
17
17
|
"mode": "source",
|
|
18
18
|
"source": false
|
|
19
19
|
},
|
|
20
20
|
"icon": "lucide-file",
|
|
21
|
-
"title": "
|
|
21
|
+
"title": "testes"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
]
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"state": {
|
|
95
95
|
"type": "backlink",
|
|
96
96
|
"state": {
|
|
97
|
+
"file": "06-feedbacks/feedback.md",
|
|
97
98
|
"collapseAll": false,
|
|
98
99
|
"extraContext": false,
|
|
99
100
|
"sortOrder": "alphabetical",
|
|
@@ -103,7 +104,7 @@
|
|
|
103
104
|
"unlinkedCollapsed": true
|
|
104
105
|
},
|
|
105
106
|
"icon": "links-coming-in",
|
|
106
|
-
"title": "Links inversos"
|
|
107
|
+
"title": "Links inversos para feedback"
|
|
107
108
|
}
|
|
108
109
|
},
|
|
109
110
|
{
|
|
@@ -180,17 +181,24 @@
|
|
|
180
181
|
"bases:Criar nova base": false
|
|
181
182
|
}
|
|
182
183
|
},
|
|
183
|
-
"active": "
|
|
184
|
+
"active": "8dedf7c146f5cebf",
|
|
184
185
|
"lastOpenFiles": [
|
|
186
|
+
"03-guias/contribuindo.md",
|
|
187
|
+
"03-guias/_index.md",
|
|
188
|
+
"02-componentes/supressao-inline.md",
|
|
189
|
+
"02-componentes/configuracao.md",
|
|
190
|
+
"02-componentes/_index.md",
|
|
191
|
+
"01-arquitetura/_index.md",
|
|
192
|
+
"01-arquitetura/ADR-001-estrutura-testes.md",
|
|
193
|
+
"06-feedbacks/feedback.md",
|
|
194
|
+
"Sem título.md",
|
|
195
|
+
"Sem título",
|
|
196
|
+
"Sem título.base",
|
|
185
197
|
"templates/guia.md",
|
|
186
198
|
"templates/componente.md",
|
|
187
199
|
"templates/ADR.md",
|
|
188
200
|
"04-glossario/termos.md",
|
|
189
201
|
"03-guias/testes.md",
|
|
190
|
-
"03-guias/contribuindo.md",
|
|
191
|
-
"02-componentes/_index.md",
|
|
192
|
-
"01-arquitetura/ADR-001-estrutura-testes.md",
|
|
193
|
-
"01-arquitetura/_index.md",
|
|
194
202
|
"_home.md"
|
|
195
203
|
]
|
|
196
204
|
}
|
|
@@ -22,8 +22,8 @@ O projeto precisava de uma estrutura de testes que suportasse mocking de módulo
|
|
|
22
22
|
## Consequências
|
|
23
23
|
|
|
24
24
|
- Testes rodam em ~30s (full suite) e ~6s (parciais)
|
|
25
|
-
-
|
|
26
|
-
- Coverage total: ~
|
|
25
|
+
- 238 test files, 3276 testes
|
|
26
|
+
- Coverage total: ~48% (target: 56%+)
|
|
27
27
|
|
|
28
28
|
## Alternativas Consideradas
|
|
29
29
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
Proveniência e Autoria: Este documento integra o projeto @mocoto/mahoraga (licença MIT-0).
|
|
3
|
+
tags: [componente]
|
|
4
|
+
status: aceito
|
|
5
|
+
created: 2026-07-25
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Configuração (`mahoraga.config.json`)
|
|
9
|
+
|
|
10
|
+
## Fluxo de Carregamento
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
mahoraga.config.json
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
converterConfigSimplificada()
|
|
17
|
+
│ Transforma chaves amigáveis (ex: "exclude")
|
|
18
|
+
│ em chaves internas (ex: "INCLUDE_EXCLUDE_RULES")
|
|
19
|
+
▼
|
|
20
|
+
mesclarProfundo(config, resultado)
|
|
21
|
+
│ Deep merge com precedência:
|
|
22
|
+
│ 1. CLI flags / env vars
|
|
23
|
+
│ 2. mahoraga.config.json
|
|
24
|
+
│ 3. System defaults (configPadrao)
|
|
25
|
+
▼
|
|
26
|
+
config global (acessível via import { config } from '@core/config')
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Comportamento de Merge
|
|
30
|
+
|
|
31
|
+
O `mesclarProfundo` aplica regras diferentes por tipo:
|
|
32
|
+
|
|
33
|
+
| Tipo | Comportamento | Exemplo |
|
|
34
|
+
|------|--------------|---------|
|
|
35
|
+
| Objeto plano | Merge recursivo | `languages`, `rules`, `detectorMarkdown`, `autoFix` |
|
|
36
|
+
| Array (`exclude`) | **Aditivo**: mergeado com defaults do sistema | `["temp/**"]` adiciona aos defaults |
|
|
37
|
+
| Primitivo | Substitui o valor default | `locale: "en"` |
|
|
38
|
+
|
|
39
|
+
### Caso crítico: `exclude`
|
|
40
|
+
|
|
41
|
+
Diferentemente de outros sistemas, o campo `exclude` no `mahoraga.config.json` é **aditivo**:
|
|
42
|
+
|
|
43
|
+
```jsonc
|
|
44
|
+
{
|
|
45
|
+
"exclude": ["temp/**", "logs/**"]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
O resultado final será: `[...defaultsDoSistema, "temp/**", "logs/**"]` — os defaults nunca são perdidos.
|
|
50
|
+
|
|
51
|
+
Isso é implementado em `converterConfigSimplificada` (`src/core/config/config.ts`), que faz o merge com `configPadrao.INCLUDE_EXCLUDE_RULES.globalExcludeGlob` antes de armazenar.
|
|
52
|
+
|
|
53
|
+
## Hierarquia de Precedência
|
|
54
|
+
|
|
55
|
+
1. **CLI flags**: `--include`, `--exclude` (máxima prioridade)
|
|
56
|
+
2. **Environment variables**: `MAHORAGA_*`
|
|
57
|
+
3. **`mahoraga.config.json** (ou `src/config.json` como fallback)
|
|
58
|
+
4. **System defaults** (`configPadrao` em `src/core/config/config.ts`)
|
|
59
|
+
|
|
60
|
+
## Arquitetura
|
|
61
|
+
|
|
62
|
+
### `src/core/config/config.ts`
|
|
63
|
+
|
|
64
|
+
- `configPadrao` — objeto com todos os valores default do sistema
|
|
65
|
+
- `config` — clone profundo de `configPadrao`, exportado como singleton
|
|
66
|
+
- `converterConfigSimplificada(raw)` — transforma chaves do usuário para formato interno
|
|
67
|
+
- `mesclarProfundo(target, src)` — merge recursivo com proteção prototype pollution
|
|
68
|
+
- `inicializarConfigDinamica()` — carrega e mergeia config do arquivo + env + CLI
|
|
69
|
+
|
|
70
|
+
### `src/core/config/excludes-padrao.ts`
|
|
71
|
+
|
|
72
|
+
- `EXCLUDES_PADRAO` — categorias de exclusão por tipo de projeto
|
|
73
|
+
- `getExcludesRecomendados(tipo)` — obtém defaults baseados no tipo de projeto detectado
|
|
74
|
+
- `mesclarConfigExcludes(usuario, tipo)` — merge dos excludes do usuário com defaults
|
|
75
|
+
- `isPadraoExclusaoSeguro(padrao)` — evita padrões perigosos como `**/*`
|
|
76
|
+
|
|
77
|
+
## Componentes Relacionados
|
|
78
|
+
|
|
79
|
+
- `src/core/config/include-exclude.ts` — avaliação de include/exclude via micromatch
|
|
80
|
+
- `src/shared/helpers/suppressao.ts` — supressão inline via `@mahoraga-disable`
|
|
81
|
+
- `src/shared/helpers/rule-config.ts` — configuração por regra (`rules.nome-da-regra.exclude`)
|
|
82
|
+
|
|
83
|
+
## Exemplo Completo
|
|
84
|
+
|
|
85
|
+
```jsonc
|
|
86
|
+
{
|
|
87
|
+
"locale": "pt",
|
|
88
|
+
"languages": {
|
|
89
|
+
"typescript": true,
|
|
90
|
+
"javascript": true,
|
|
91
|
+
"shell": true
|
|
92
|
+
},
|
|
93
|
+
"exclude": ["temp/**"],
|
|
94
|
+
"suppress": {
|
|
95
|
+
"paths": ["**/tests/**"],
|
|
96
|
+
"severity": { "no-console": "warning" }
|
|
97
|
+
},
|
|
98
|
+
"rules": {
|
|
99
|
+
"ml-magic-numbers": {
|
|
100
|
+
"severity": "off"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"detectorMarkdown": {
|
|
104
|
+
"checkReferences": false,
|
|
105
|
+
"whitelist": {
|
|
106
|
+
"dirs": ["Docs"]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
@@ -50,6 +50,7 @@ updated: 2026-07-25
|
|
|
50
50
|
| `tsconfig.json` | Configuração TypeScript (paths, strict, ES2024) |
|
|
51
51
|
| `vitest.config.ts` | Configuração de testes e aliases |
|
|
52
52
|
| `eslint.config.js` | Configuração ESLint |
|
|
53
|
+
| `mahoraga.config.json` | Configuração do Mahoraga (merge aditivo com defaults) |
|
|
53
54
|
| `THIRD-PARTY-NOTICES.txt` | Atribuições de licenças |
|
|
54
55
|
| `.github/workflows/ci.yml` | CI pipeline |
|
|
55
56
|
| `.github/workflows/publish.yml` | Publicação no npm |
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Feedback — Análise de Relatórios do Linter
|
|
2
|
+
|
|
3
|
+
## Resumo
|
|
4
|
+
|
|
5
|
+
3 relatórios analisados (`erro-001.json`, `aviso-001.json`, `info-001.json`). Nenhum problema real encontrado — todos são falsos positivos ou itens puramente informativos.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Falsos Positivos
|
|
10
|
+
|
|
11
|
+
### 1. `markdown-falta-proveniencia` (erro-001.json, 9 ocorrências)
|
|
12
|
+
|
|
13
|
+
**Disparo em**: `Docs/*.md`, `README.md`
|
|
14
|
+
|
|
15
|
+
**Problema**: O linter exige aviso de "Proveniência e Autoria" nas primeiras linhas de todo `.md`. Esse disclaimer é pertinente para instruções de agente (`AGENTS.md`, skills), mas não para documentação de usuário (`Docs/`, `README.md`).
|
|
16
|
+
|
|
17
|
+
**Sugestão**: Ignorar a pasta `Docs/` e `README.md`, ou criar um allowlist/denylist de diretórios para essa regra.
|
|
18
|
+
|
|
19
|
+
### 2. `codigo-fragil` — shebang ausente (aviso-001.json, husky.sh)
|
|
20
|
+
|
|
21
|
+
**Disparo em**: `.husky/_/husky.sh`
|
|
22
|
+
|
|
23
|
+
**Problema**: O arquivo é gerado automaticamente pelo husky. Arquivos gerados por ferramentas externas não devem ser escaneados.
|
|
24
|
+
|
|
25
|
+
**Sugestão**: Adicionar `.husky/` ao ignore pattern, ou criar um arquivo de configuração `.linterignore`.
|
|
26
|
+
|
|
27
|
+
### 3. `tailwindcss/regra` — left-0 + right-0 (aviso-001.json, Header.tsx:47)
|
|
28
|
+
|
|
29
|
+
**Disparo em**: `src/app/components/Header.tsx:47`
|
|
30
|
+
|
|
31
|
+
**Problema**: `left-0` + `right-0` em elemento `absolute` é padrão legítimo do Tailwind para esticar o elemento horizontalmente. Não é conflito.
|
|
32
|
+
|
|
33
|
+
**Sugestão**: A regra deve entender que `left-0` + `right-0` em conjunto com `position: absolute/fixed` é intencional e válido. Ignorar quando detectar `absolute` ou `fixed` no mesmo elemento.
|
|
34
|
+
|
|
35
|
+
### 4. `react/regra` — dangerouslySetInnerHTML (aviso-001.json, json-ld.tsx:17 e 23)
|
|
36
|
+
|
|
37
|
+
**Disparo em**: `src/app/components/json-ld.tsx:17,23`
|
|
38
|
+
|
|
39
|
+
**Problema**: O componente json-ld intencionalmente usa `dangerouslySetInnerHTML` para injetar JSON-LD schema.org. É o padrão recomendado pela documentação do Next.js para SEO.
|
|
40
|
+
|
|
41
|
+
**Sugestão**: Permitir esse padrão quando o componente tiver nome sugestivo (ex: contendo "json-ld", "schema", "structured-data") ou via suppress comment.
|
|
42
|
+
|
|
43
|
+
### 5. `codigo-fragil` / `boa-pratica-ausente` — shell script boas práticas (info-001.json, husky.sh)
|
|
44
|
+
|
|
45
|
+
**Disparo em**: `.husky/_/husky.sh` — 6 ocorrências (`set -e`, `set -u`, `IFS`, `trap`, `main()`, `command -v`, debug mode, validação de argumentos)
|
|
46
|
+
|
|
47
|
+
**Problema**: Mesmo que o item 2 — arquivo gerado por ferramenta. Além disso, `husky.sh` é um script auxiliar que não é executado diretamente pelo usuário.
|
|
48
|
+
|
|
49
|
+
**Sugestão**: Ignorar `.husky/` completamente no escaneamento.
|
|
50
|
+
|
|
51
|
+
### 6. `problema-documentacao` — magic-constants (info-001.json, ~25 ocorrências)
|
|
52
|
+
|
|
53
|
+
**Disparo em**: Quase todos os arquivos `src/app/`, `src/lib/`, `vercel.ts`, `next.config.ts`, `src/proxy.ts`
|
|
54
|
+
|
|
55
|
+
**Problema**: Números como `86400` (segundos em 1 dia) ou valores de configuração são detectados como "magic constants". Muitos desses são valores de configuração autoexplicativos ou já estão próximos do uso.
|
|
56
|
+
|
|
57
|
+
**Sugestão**: A regra é muito barulhenta. Recomenda-se usar um limiar mais alto de confiança, ou filtrar valores que são amplamente conhecidos (ex: `60`, `3600`, `86400`, `1000`). Alternativamente, agrupar por arquivo em vez de listar cada ocorrência individualmente.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Sugestões Gerais para o Linter
|
|
62
|
+
|
|
63
|
+
| # | Sugestão |
|
|
64
|
+
|---|----------|
|
|
65
|
+
| 1 | Criar um mecanismo de `ignore` (arquivo `.linterignore` ou comentários `// linter-ignore`) |
|
|
66
|
+
| 2 | Ignorar diretórios de ferramentas: `.husky/`, `.next/`, `node_modules/` |
|
|
67
|
+
| 3 | Ignorar `Docs/` e `README.md` para regras de disclaimer de agente |
|
|
68
|
+
| 4 | Reduzir verbose de regras de "magic constants" — consolidar ocorrências por arquivo |
|
|
69
|
+
| 5 | Adicionar contexto de CSS: `left-0 + right-0` não é conflito quando `position` é `absolute/fixed` |
|
|
70
|
+
| 6 | Adicionar allowlist de padrões para `dangerouslySetInnerHTML` (json-ld, schema, analytics snippets) |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
*Gerado em 2026-07-25 com base na análise dos relatórios `erro-001.json`, `aviso-001.json` e `info-001.json`.*
|
package/{docs → Docs}/_home.md
RENAMED
|
@@ -42,10 +42,10 @@ Mahoraga é uma ferramenta CLI que funciona como "médico de projetos": analisa
|
|
|
42
42
|
|---------|-------|
|
|
43
43
|
| Versão | 0.15.1 |
|
|
44
44
|
| Comandos CLI | 27 |
|
|
45
|
-
| Arquivos de teste | ~
|
|
46
|
-
| Testes | ~
|
|
47
|
-
| Cobertura (statements) | ~
|
|
48
|
-
| Source lines | ~
|
|
45
|
+
| Arquivos de teste | ~240 |
|
|
46
|
+
| Testes | ~3300 |
|
|
47
|
+
| Cobertura (statements) | ~48% |
|
|
48
|
+
| Source lines | ~31k |
|
|
49
49
|
| Diretórios em `src/` | 15+ |
|
|
50
50
|
| Analisadores de linguagem | 11 |
|
|
51
51
|
| Analisadores de CI/CD | 5 |
|
package/README.md
CHANGED
|
@@ -7,7 +7,10 @@ Proveniência e Autoria: Este documento integra o projeto @mocoto/mahoraga (lice
|
|
|
7
7
|
<p><b>@mocoto/mahoraga</b>: CLI modular para análise, diagnóstico e manutenção de projetos JavaScript/TypeScript com suporte multi-linguagem<p>
|
|
8
8
|
|
|
9
9
|
</div>
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
Abre seu obsidian, se não tiver instalado instala. Vai em abrir cofre, vai no seu projeto onde o mahoraga esta instalado, vai em projeto/node_modules/@mocoto/mahoraga/Docs e clique em selecionar. A documentação vai estar como obsidian do jeito que voces gostam. Como eu ia usar o projeto só pra mim então eu exclui a documentão essa é nova e vai ser completada conforme o projeto avança, mas acho que ja serve pra voces iniciar.
|
|
12
|
+
|
|
13
|
+
o mahoraga deve ser instalado como devdependence npm install @mocoto/mahoraga --save-dev depois arrumo certinho. to ocupado agora.
|
|
11
14
|
|
|
12
15
|
Caso queira ajudar com relatórios de bugs e erros ou com sugestões, entre em contato pelo e-mail abaixo.
|
|
13
16
|
|
|
@@ -230,6 +233,13 @@ O Mahoraga lê um arquivo `mahoraga.config.json` na raiz do seu projeto. A confi
|
|
|
230
233
|
2. `mahoraga.config.json` (ou `src/config.json` como fallback)
|
|
231
234
|
3. System defaults (hardcoded)
|
|
232
235
|
|
|
236
|
+
### Comportamento de Merge
|
|
237
|
+
|
|
238
|
+
- **Objetos** (`languages`, `suppress`, `rules`, `detectorMarkdown`, `autoFix`, `ANALISE_LIMITES`, `nameConventions`): faz merge recursivo — você pode definir apenas os campos que deseja sobrescrever; os demais mantêm os defaults.
|
|
239
|
+
- **Arrays** (`exclude`): são **aditivos** — os padrões que você definir em `exclude` são adicionados aos defaults do sistema, não os substituem. Se você quer excluir `temp/**` além dos defaults, basta incluir `"exclude": ["temp/**"]`.
|
|
240
|
+
- **Primitivos** (`locale`, `verbose`, `LOG_LEVEL`, `GUARDIAN_ENABLED`, etc.): substituem o valor default quando definidos.
|
|
241
|
+
- **`suppress.paths` e `suppress.filePatterns`**: substituem a lista de supressão (não é merge).
|
|
242
|
+
|
|
233
243
|
### Exemplo Completo
|
|
234
244
|
|
|
235
245
|
```jsonc
|
|
@@ -507,7 +517,7 @@ npm run lint # ESLint
|
|
|
507
517
|
## Qualidade
|
|
508
518
|
|
|
509
519
|
- **TypeScript estrito**: `strict: true`, `verbatimModuleSyntax: true`
|
|
510
|
-
- **Testes com Vitest**: ~
|
|
520
|
+
- **Testes com Vitest**: ~3300 testes em ~240 arquivos
|
|
511
521
|
- **ESLint 10.x**: configuração strict
|
|
512
522
|
- **Worker pool**: processamento paralelo
|
|
513
523
|
- **i18n**: PT, EN, ZH, JA
|
|
@@ -2,6 +2,7 @@ import { parse as babelParse } from '@babel/parser';
|
|
|
2
2
|
import traverse from '@babel/traverse';
|
|
3
3
|
import * as t from '@babel/types';
|
|
4
4
|
import { getMessages } from '../../core/messages/index.js';
|
|
5
|
+
import { isWhitelistedConstant } from '../../shared/helpers/index.js';
|
|
5
6
|
const MAX_MESSAGE_PREVIEW_LENGTH = 60;
|
|
6
7
|
const BUG_PATTERNS = [
|
|
7
8
|
{
|
|
@@ -224,6 +225,10 @@ const BUG_PATTERNS = [
|
|
|
224
225
|
const matches = content.matchAll(magicNumPattern);
|
|
225
226
|
const results = [];
|
|
226
227
|
for (const m of matches) {
|
|
228
|
+
const value = parseInt(m[0], 10);
|
|
229
|
+
if (isWhitelistedConstant(value, [])) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
227
232
|
const line = contarLinhasAtePos(content, m.index);
|
|
228
233
|
const lineContent = content.split('\n')[line - 1] || '';
|
|
229
234
|
if (!lineContent.includes('const') && !lineContent.includes('let') && !lineContent.includes('var') && !lineContent.includes('//') && !lineContent.includes('/*')) {
|
|
@@ -8,9 +8,9 @@ const LICENCA_PADROES = {
|
|
|
8
8
|
referenciasRisco: [/Stack\s*Overflow/i, /(?:^|https?:\/\/|\/\/)(?:[^\/\s@]+\.)?stackoverflow\.com(?::\d+)?(?:[\/?#]|$)/i, /\bassign\b/i, /\bcession\b/i]
|
|
9
9
|
};
|
|
10
10
|
const PADRAO_LISTA_BRANCA = {
|
|
11
|
-
paths: ['.github/copilot-instructions.md', 'docs/POLICY-PROVENIENCIA.md', 'docs/partials/AVISO-PROVENIENCIA.md'],
|
|
11
|
+
paths: ['.github/copilot-instructions.md', 'docs/POLICY-PROVENIENCIA.md', 'docs/partials/AVISO-PROVENIENCIA.md', 'README.md'],
|
|
12
12
|
patterns: ['**/reports/**', 'docs/history/**', 'tests/**', 'tmp*.md'],
|
|
13
|
-
dirs: ['pre-public', 'preview-mahoraga', '.abandonados', '.deprecados', 'reports']
|
|
13
|
+
dirs: ['pre-public', 'preview-mahoraga', '.abandonados', '.deprecados', 'reports', 'docs']
|
|
14
14
|
};
|
|
15
15
|
function createRiskRegex() {
|
|
16
16
|
const allPadroes = [...LICENCA_PADROES.incompativeis, ...LICENCA_PADROES.cessaoDireitos, ...LICENCA_PADROES.referenciasRisco].map(raiz => raiz.source).join('|');
|
|
@@ -5,6 +5,7 @@ import { messages } from '../../../core/messages/index.js';
|
|
|
5
5
|
import { createLineLookup, maskJsComments } from '../../../shared/helpers/index.js';
|
|
6
6
|
import { criarAnalista, criarOcorrencia } from '../../../types/index.js';
|
|
7
7
|
const disableEnv = process.env.MAHORAGA_DISABLE_PLUGIN_REACT === '1';
|
|
8
|
+
const ALLOWLIST_DANGEROUSLY_SET_INNER_HTML = /json-ld|schema|structured-data/i;
|
|
8
9
|
function hasJSX(src) {
|
|
9
10
|
const hasTagLike = /(^|[^A-Za-z0-9_$])<([A-Za-z][A-Za-z0-9]*)\b/.test(src);
|
|
10
11
|
const hasFragment = /<>|<\/>|<\/\s*>|<\/\s*Fragment\s*>/i.test(src);
|
|
@@ -37,6 +38,9 @@ function collectReactIssues(src, relPath) {
|
|
|
37
38
|
if (/speculationrules/.test(lineContent)) {
|
|
38
39
|
continue;
|
|
39
40
|
}
|
|
41
|
+
if (ALLOWLIST_DANGEROUSLY_SET_INNER_HTML.test(relPath)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
40
44
|
ocorrencias.push(warn(messages.ReactMensagens.dangerouslySetInnerHTML, relPath, line));
|
|
41
45
|
}
|
|
42
46
|
for (const match of src.matchAll(/<img[^>]*>/gi)) {
|
|
@@ -219,6 +223,9 @@ function parseReactWithBabel(scan, relPath) {
|
|
|
219
223
|
return;
|
|
220
224
|
}
|
|
221
225
|
}
|
|
226
|
+
if (ALLOWLIST_DANGEROUSLY_SET_INNER_HTML.test(tag)) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
222
229
|
pushOnce(warn(messages.ReactMensagens.dangerouslySetInnerHTML, relPath, locLine));
|
|
223
230
|
}
|
|
224
231
|
const styleAttr = findAttr(attrs, 'style');
|
|
@@ -52,11 +52,8 @@ export function detectarTipoProjeto(baseDir = process.cwd()) {
|
|
|
52
52
|
export function getDefaultExcludes(tipoProjeto) {
|
|
53
53
|
const configIncluirExcluir = config.INCLUDE_EXCLUDE_RULES;
|
|
54
54
|
const globalExclude = configIncluirExcluir.globalExcludeGlob;
|
|
55
|
-
if (Array.isArray(globalExclude) && globalExclude.length > 0) {
|
|
56
|
-
return Array.from(new Set(globalExclude));
|
|
57
|
-
}
|
|
58
55
|
const tipo = tipoProjeto ?? detectarTipoProjeto();
|
|
59
|
-
return mesclarConfigExcludes(null, tipo);
|
|
56
|
+
return mesclarConfigExcludes(globalExclude ?? null, tipo);
|
|
60
57
|
}
|
|
61
58
|
export function processarFiltros(opcoes) {
|
|
62
59
|
const tipoProjeto = detectarTipoProjeto();
|
|
@@ -205,10 +205,9 @@ function converterConfigSimplificada(config) {
|
|
|
205
205
|
delete resultado.locales;
|
|
206
206
|
}
|
|
207
207
|
if (Array.isArray(config.exclude)) {
|
|
208
|
+
const defaults = configPadrao.INCLUDE_EXCLUDE_RULES.globalExcludeGlob;
|
|
208
209
|
resultado.INCLUDE_EXCLUDE_RULES = {
|
|
209
|
-
globalExcludeGlob: config.exclude,
|
|
210
|
-
dirRules: {},
|
|
211
|
-
defaultExcludes: null
|
|
210
|
+
globalExcludeGlob: Array.from(new Set([...defaults, ...config.exclude])),
|
|
212
211
|
};
|
|
213
212
|
delete resultado.exclude;
|
|
214
213
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getMessages } from '../messages/index.js';
|
|
2
2
|
export const EXCLUDES_PADRAO = {
|
|
3
|
-
padroesSistema: ['node_modules', '**/node_modules/**', 'dist', 'dist/**', '**/dist/**', 'out', 'out/**', '**/out/**', '.next', '.next/**', '**/.next/**', 'build/**', '**/build/**', '**/*.log', '**/*.lock', 'package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', '**/.git/**', '.pnpm/**', 'mahoraga/**', '**/.mahoraga/**', 'preview-mahoraga/**', 'mahoraga/PREVIEW*', 'PREVIEW*', 'tests/fixtures/**', 'THIRD-PARTY-NOTICES.txt', '**/THIRD-PARTY-NOTICES.txt', '**/*LICENSE*', '**/*NOTICE*', '**/*CHANGELOG*', '**/*.min.js', '**/*.min.css', '**/bundle.*', '**/*generated*', '**/*autogenerated*'],
|
|
3
|
+
padroesSistema: ['node_modules', '**/node_modules/**', 'dist', 'dist/**', '**/dist/**', 'out', 'out/**', '**/out/**', '.next', '.next/**', '**/.next/**', 'build/**', '**/build/**', '**/*.log', '**/*.lock', 'package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', '**/.git/**', '.pnpm/**', 'mahoraga/**', '**/.mahoraga/**', 'preview-mahoraga/**', 'mahoraga/PREVIEW*', 'PREVIEW*', 'tests/fixtures/**', 'THIRD-PARTY-NOTICES.txt', '**/THIRD-PARTY-NOTICES.txt', '**/*LICENSE*', '**/*NOTICE*', '**/*CHANGELOG*', '**/*.min.js', '**/*.min.css', '**/bundle.*', '**/*generated*', '**/*autogenerated*', '.husky/**', '**/.husky/**'],
|
|
4
4
|
nodeJs: ['node_modules/**', '**/node_modules/**', 'npm-debug.log*', 'yarn-debug.log*', 'yarn-error.log*', '.npm', '.yarn', 'coverage/**', '**/coverage/**', '.nyc_output', 'dist/**', '**/dist/**', 'build/**', '**/build/**'],
|
|
5
5
|
typeScript: ['dist/**', '**/dist/**', 'build/**', '**/build/**', '*.tsbuildinfo', '**/*.tsbuildinfo', '.tsbuildinfo', 'out/**', '**/out/**'],
|
|
6
6
|
python: ['__pycache__/**', '**/__pycache__/**', '*.pyc', '**/*.pyc', '*.pyo', '**/*.pyo', '*.pyd', '**/*.pyd', '.Python', 'env/**', 'venv/**', '.env/**', 'pip-log.txt', 'pip-delete-this-directory.txt', '.tox/**', '.coverage', 'htmlcov/**', '.pytest_cache/**', '.mypy_cache/**'],
|
|
@@ -50,12 +50,13 @@ export function isPadraoExclusaoSeguro(padrao) {
|
|
|
50
50
|
}
|
|
51
51
|
export function mesclarConfigExcludes(configUsuario, tipoProjeto = 'generico') {
|
|
52
52
|
if (configUsuario && Array.isArray(configUsuario) && configUsuario.length > 0) {
|
|
53
|
+
const defaults = getExcludesRecomendados(tipoProjeto);
|
|
53
54
|
const padroesValidos = configUsuario.filter(isPadraoExclusaoSeguro);
|
|
54
55
|
if (padroesValidos.length !== configUsuario.length) {
|
|
55
56
|
const { SharedCommonMensagens } = getMessages();
|
|
56
57
|
console.warn(SharedCommonMensagens.exclusaoInsegura(configUsuario.filter(caminho => !isPadraoExclusaoSeguro(caminho)).join(', ')));
|
|
57
58
|
}
|
|
58
|
-
return Array.from(new Set(padroesValidos));
|
|
59
|
+
return Array.from(new Set([...defaults, ...padroesValidos]));
|
|
59
60
|
}
|
|
60
61
|
return getExcludesRecomendados(tipoProjeto);
|
|
61
62
|
}
|
|
@@ -4,18 +4,12 @@ export function gerarRelatorioEstrutura(mapa) {
|
|
|
4
4
|
const desalinhados = mapa.filter((item) => item.ideal && item.atual !== item.ideal);
|
|
5
5
|
if (desalinhados.length === 0) {
|
|
6
6
|
return [
|
|
7
|
-
|
|
7
|
+
RelatorioMensagens.estrutura.tituloVerificada,
|
|
8
8
|
'',
|
|
9
|
-
|
|
9
|
+
RelatorioMensagens.estrutura.tudoIdeal,
|
|
10
10
|
'',
|
|
11
11
|
].join('\\n');
|
|
12
12
|
}
|
|
13
|
-
return [
|
|
14
|
-
RelatorioMensagens.estrutura.tituloVerificada,
|
|
15
|
-
'',
|
|
16
|
-
RelatorioMensagens.estrutura.tudoIdeal,
|
|
17
|
-
'',
|
|
18
|
-
].join('\\n');
|
|
19
13
|
return [
|
|
20
14
|
RelatorioMensagens.estrutura.tituloDiagnostico,
|
|
21
15
|
'',
|
|
@@ -92,6 +92,16 @@ export const MATH_CONSTANTES = [{
|
|
|
92
92
|
value: 1000,
|
|
93
93
|
description: 'Milhar/conversão ms→s'
|
|
94
94
|
}];
|
|
95
|
+
export const TIME_CONSTANTES = [{
|
|
96
|
+
value: 60,
|
|
97
|
+
description: 'Segundos em um minuto'
|
|
98
|
+
}, {
|
|
99
|
+
value: 3600,
|
|
100
|
+
description: 'Segundos em uma hora'
|
|
101
|
+
}, {
|
|
102
|
+
value: 86400,
|
|
103
|
+
description: 'Segundos em um dia'
|
|
104
|
+
}];
|
|
95
105
|
export const FRAMEWORK_WHITELISTS = {
|
|
96
106
|
'Discord.js': DISCORD_LIMITES,
|
|
97
107
|
Express: HTTP_STATUS_CODIGOS,
|
|
@@ -110,6 +120,9 @@ export function isWhitelistedConstant(value, frameworks, userWhitelist) {
|
|
|
110
120
|
if (MATH_CONSTANTES.some(rule => rule.value === value)) {
|
|
111
121
|
return true;
|
|
112
122
|
}
|
|
123
|
+
if (TIME_CONSTANTES.some(rule => rule.value === value)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
113
126
|
if (COMUM_LIMITES.some(rule => rule.value === value)) {
|
|
114
127
|
return true;
|
|
115
128
|
}
|
|
@@ -125,7 +138,7 @@ export function isWhitelistedConstant(value, frameworks, userWhitelist) {
|
|
|
125
138
|
return false;
|
|
126
139
|
}
|
|
127
140
|
export function getConstantDescription(value, frameworks) {
|
|
128
|
-
const allRules = [...MATH_CONSTANTES, ...COMUM_LIMITES, ...HTTP_STATUS_CODIGOS, ...frameworks.flatMap(arquivo => FRAMEWORK_WHITELISTS[arquivo] ?? [])];
|
|
141
|
+
const allRules = [...MATH_CONSTANTES, ...TIME_CONSTANTES, ...COMUM_LIMITES, ...HTTP_STATUS_CODIGOS, ...frameworks.flatMap(arquivo => FRAMEWORK_WHITELISTS[arquivo] ?? [])];
|
|
129
142
|
const rule = allRules.find(raiz => raiz.value === value);
|
|
130
143
|
return rule?.description;
|
|
131
144
|
}
|
|
@@ -29,11 +29,8 @@ export function expandIncludes(list) {
|
|
|
29
29
|
export function getDefaultExcludes() {
|
|
30
30
|
const configIncluirExcluir = config.INCLUDE_EXCLUDE_RULES;
|
|
31
31
|
const globalExclude = configIncluirExcluir.globalExcludeGlob;
|
|
32
|
-
if (Array.isArray(globalExclude) && globalExclude.length > 0) {
|
|
33
|
-
return Array.from(new Set(configIncluirExcluir.globalExcludeGlob));
|
|
34
|
-
}
|
|
35
32
|
const tipoProjeto = detectarTipoProjeto();
|
|
36
|
-
return mesclarConfigExcludes(null, tipoProjeto);
|
|
33
|
+
return mesclarConfigExcludes(globalExclude ?? null, tipoProjeto);
|
|
37
34
|
}
|
|
38
35
|
function detectarTipoProjeto() {
|
|
39
36
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mocoto/mahoraga",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "C.L.I modular para análise, diagnóstico e manutenção de projetos JavaScript/TypeScript e multi-stack leve",
|
|
6
6
|
"author": "Italo Lopes",
|
|
@@ -27,12 +27,11 @@
|
|
|
27
27
|
"security-check": "npm audit --production --audit-level=moderate",
|
|
28
28
|
"test": "vitest run --passWithNoTests",
|
|
29
29
|
"coverage": "vitest run --coverage",
|
|
30
|
-
|
|
31
30
|
"diagnosticar": "mahoraga diagnosticar",
|
|
31
|
+
"diag": "mahoraga diagnosticar",
|
|
32
32
|
"analistas": "mahoraga analistas",
|
|
33
33
|
"metricas": "mahoraga metricas",
|
|
34
34
|
"vulnerabilidades": "mahoraga vulnerabilidades scan",
|
|
35
|
-
|
|
36
35
|
"imports": "mahoraga imports",
|
|
37
36
|
"imports:scan": "mahoraga imports --scan",
|
|
38
37
|
"imports:apply": "mahoraga imports --apply",
|
|
@@ -40,7 +39,6 @@
|
|
|
40
39
|
"names:scan": "mahoraga names --scan",
|
|
41
40
|
"names:apply": "mahoraga names --apply",
|
|
42
41
|
"barrels": "mahoraga barrels",
|
|
43
|
-
|
|
44
42
|
"formatar": "mahoraga formatar --write",
|
|
45
43
|
"format:check": "mahoraga formatar --check",
|
|
46
44
|
"podar": "mahoraga podar",
|
|
@@ -48,18 +46,15 @@
|
|
|
48
46
|
"otimizar-svg": "mahoraga otimizar-svg --write",
|
|
49
47
|
"atualizar": "mahoraga atualizar",
|
|
50
48
|
"convert": "mahoraga convert",
|
|
51
|
-
|
|
52
49
|
"perf:baseline": "mahoraga perf snapshot --baseline || true",
|
|
53
50
|
"perf:compare": "mahoraga perf compare",
|
|
54
51
|
"perf:gate": "mahoraga perf compare --threshold 0",
|
|
55
|
-
|
|
56
52
|
"scan": "mahoraga licencas scan",
|
|
57
53
|
"scan:root": "mahoraga licencas scan --root .",
|
|
58
54
|
"licenses:json": "mahoraga licencas scan --json",
|
|
59
55
|
"notices": "mahoraga licencas notices generate",
|
|
60
56
|
"disclaimer:verify": "mahoraga licencas disclaimer verify",
|
|
61
57
|
"add": "mahoraga licencas disclaimer add",
|
|
62
|
-
|
|
63
58
|
"gha:scan": "mahoraga github-actions scan",
|
|
64
59
|
"gha:report": "mahoraga github-actions report",
|
|
65
60
|
"gha:gate": "mahoraga github-actions gate",
|
|
@@ -67,11 +62,9 @@
|
|
|
67
62
|
"circleci:scan": "mahoraga circleci scan",
|
|
68
63
|
"jenkins:scan": "mahoraga jenkins scan",
|
|
69
64
|
"azure:scan": "mahoraga azure scan",
|
|
70
|
-
|
|
71
65
|
"plugins:list": "mahoraga plugins list",
|
|
72
66
|
"marketplace:search": "mahoraga marketplace search",
|
|
73
67
|
"marketplace:list": "mahoraga marketplace list",
|
|
74
|
-
|
|
75
68
|
"guardian": "mahoraga guardian",
|
|
76
69
|
"reverter:listar": "mahoraga reverter listar",
|
|
77
70
|
"reverter:status": "mahoraga reverter status"
|
|
@@ -99,7 +92,7 @@
|
|
|
99
92
|
"access": "public"
|
|
100
93
|
},
|
|
101
94
|
"files": [
|
|
102
|
-
"
|
|
95
|
+
"Docs",
|
|
103
96
|
"dist",
|
|
104
97
|
"README.md",
|
|
105
98
|
"CHANGELOG.md",
|
|
@@ -128,11 +121,18 @@
|
|
|
128
121
|
"yaml": "^2.9.0"
|
|
129
122
|
},
|
|
130
123
|
"devDependencies": {
|
|
124
|
+
"@mocoto/mahoraga": "0.15.2",
|
|
131
125
|
"@types/micromatch": "^4.0.10",
|
|
132
126
|
"@types/node": "^26.1.1",
|
|
127
|
+
"@typescript-eslint/eslint-plugin": "8.65.0",
|
|
128
|
+
"@typescript-eslint/parser": "8.65.0",
|
|
133
129
|
"@vitest/coverage-istanbul": "^4.1.8",
|
|
134
130
|
"@vitest/coverage-v8": "^4.1.8",
|
|
135
131
|
"autoprefixer": "^10.5.4",
|
|
132
|
+
"eslint": "10.8.0",
|
|
133
|
+
"eslint-plugin-import-x": "4.17.1",
|
|
134
|
+
"eslint-plugin-simple-import-sort": "14.0.0",
|
|
135
|
+
"eslint-plugin-unused-imports": "4.4.1",
|
|
136
136
|
"husky": "^9.1.7",
|
|
137
137
|
"license-checker-rseidelsohn": "^5.0.1",
|
|
138
138
|
"lint-staged": "^17.2.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|