@mocoto/mahoraga 0.15.1 → 0.15.2
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 +12 -12
- 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/Sem t/303/255tulo.base" +3 -0
- package/Docs/Sem t/303/255tulo.md +0 -0
- package/{docs → Docs}/_home.md +4 -4
- package/README.md +8 -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,17 @@
|
|
|
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
|
-
"type": "
|
|
15
|
-
"state": {
|
|
16
|
-
"file": "02-componentes/_index.md",
|
|
17
|
-
"mode": "source",
|
|
18
|
-
"source": false
|
|
19
|
-
},
|
|
14
|
+
"type": "empty",
|
|
15
|
+
"state": {},
|
|
20
16
|
"icon": "lucide-file",
|
|
21
|
-
"title": "
|
|
17
|
+
"title": "Nova aba"
|
|
22
18
|
}
|
|
23
19
|
}
|
|
24
20
|
]
|
|
@@ -94,6 +90,7 @@
|
|
|
94
90
|
"state": {
|
|
95
91
|
"type": "backlink",
|
|
96
92
|
"state": {
|
|
93
|
+
"file": "06-feedbacks/feedback.md",
|
|
97
94
|
"collapseAll": false,
|
|
98
95
|
"extraContext": false,
|
|
99
96
|
"sortOrder": "alphabetical",
|
|
@@ -103,7 +100,7 @@
|
|
|
103
100
|
"unlinkedCollapsed": true
|
|
104
101
|
},
|
|
105
102
|
"icon": "links-coming-in",
|
|
106
|
-
"title": "Links inversos"
|
|
103
|
+
"title": "Links inversos para feedback"
|
|
107
104
|
}
|
|
108
105
|
},
|
|
109
106
|
{
|
|
@@ -180,15 +177,18 @@
|
|
|
180
177
|
"bases:Criar nova base": false
|
|
181
178
|
}
|
|
182
179
|
},
|
|
183
|
-
"active": "
|
|
180
|
+
"active": "eec9025824b684fa",
|
|
184
181
|
"lastOpenFiles": [
|
|
182
|
+
"Sem título.md",
|
|
183
|
+
"Sem título",
|
|
184
|
+
"Sem título.base",
|
|
185
|
+
"02-componentes/_index.md",
|
|
185
186
|
"templates/guia.md",
|
|
186
187
|
"templates/componente.md",
|
|
187
188
|
"templates/ADR.md",
|
|
188
189
|
"04-glossario/termos.md",
|
|
189
190
|
"03-guias/testes.md",
|
|
190
191
|
"03-guias/contribuindo.md",
|
|
191
|
-
"02-componentes/_index.md",
|
|
192
192
|
"01-arquitetura/ADR-001-estrutura-testes.md",
|
|
193
193
|
"01-arquitetura/_index.md",
|
|
194
194
|
"_home.md"
|
|
@@ -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`.*
|
|
File without changes
|
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,6 @@ 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
|
-
ja que temos aqui esses 60 bastiões, vou manter o projeto no ar e em evolução pra ajuda-los, no momento esta passando por ajustes, mas ja ja fica no jeito. (obrigado por usar o mahoraga).
|
|
11
10
|
|
|
12
11
|
Caso queira ajudar com relatórios de bugs e erros ou com sugestões, entre em contato pelo e-mail abaixo.
|
|
13
12
|
|
|
@@ -230,6 +229,13 @@ O Mahoraga lê um arquivo `mahoraga.config.json` na raiz do seu projeto. A confi
|
|
|
230
229
|
2. `mahoraga.config.json` (ou `src/config.json` como fallback)
|
|
231
230
|
3. System defaults (hardcoded)
|
|
232
231
|
|
|
232
|
+
### Comportamento de Merge
|
|
233
|
+
|
|
234
|
+
- **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.
|
|
235
|
+
- **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/**"]`.
|
|
236
|
+
- **Primitivos** (`locale`, `verbose`, `LOG_LEVEL`, `GUARDIAN_ENABLED`, etc.): substituem o valor default quando definidos.
|
|
237
|
+
- **`suppress.paths` e `suppress.filePatterns`**: substituem a lista de supressão (não é merge).
|
|
238
|
+
|
|
233
239
|
### Exemplo Completo
|
|
234
240
|
|
|
235
241
|
```jsonc
|
|
@@ -507,7 +513,7 @@ npm run lint # ESLint
|
|
|
507
513
|
## Qualidade
|
|
508
514
|
|
|
509
515
|
- **TypeScript estrito**: `strict: true`, `verbatimModuleSyntax: true`
|
|
510
|
-
- **Testes com Vitest**: ~
|
|
516
|
+
- **Testes com Vitest**: ~3300 testes em ~240 arquivos
|
|
511
517
|
- **ESLint 10.x**: configuração strict
|
|
512
518
|
- **Worker pool**: processamento paralelo
|
|
513
519
|
- **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.2",
|
|
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.1",
|
|
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
|