@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.
Files changed (35) hide show
  1. package/{docs → Docs}/.obsidian/graph.json +1 -1
  2. package/{docs → Docs}/.obsidian/workspace.json +18 -10
  3. package/{docs → Docs}/01-arquitetura/ADR-001-estrutura-testes.md +2 -2
  4. package/Docs/02-componentes/configuracao.md +110 -0
  5. package/{docs → Docs}/05-referencias/_index.md +1 -0
  6. package/Docs/06-feedbacks/feedback.md +74 -0
  7. package/{docs → Docs}/_home.md +4 -4
  8. package/README.md +12 -2
  9. package/dist/analysts/detectors/detector-bugs-ml.js +5 -0
  10. package/dist/analysts/plugins/detector-markdown.js +2 -2
  11. package/dist/analysts/react/analysts/analyst-react.js +7 -0
  12. package/dist/cli/diagnostic/filters.js +1 -4
  13. package/dist/core/config/config.js +2 -3
  14. package/dist/core/config/excludes-padrao.js +3 -2
  15. package/dist/reports/report-structure.js +2 -8
  16. package/dist/shared/helpers/magic-constants-whitelist.js +14 -1
  17. package/dist/types/processing/filters.js +1 -4
  18. package/package.json +10 -10
  19. /package/{docs → Docs}/.obsidian/app.json +0 -0
  20. /package/{docs → Docs}/.obsidian/appearance.json +0 -0
  21. /package/{docs → Docs}/.obsidian/community-plugins.json +0 -0
  22. /package/{docs → Docs}/.obsidian/core-plugins-migration.json +0 -0
  23. /package/{docs → Docs}/.obsidian/core-plugins.json +0 -0
  24. /package/{docs → Docs}/01-arquitetura/_index.md +0 -0
  25. /package/{docs → Docs}/02-componentes/_index.md +0 -0
  26. /package/{docs → Docs}/02-componentes/supressao-inline.md +0 -0
  27. /package/{docs → Docs}/03-guias/_index.md +0 -0
  28. /package/{docs → Docs}/03-guias/contribuindo.md +0 -0
  29. /package/{docs → Docs}/03-guias/testes.md +0 -0
  30. /package/{docs → Docs}/04-glossario/_index.md +0 -0
  31. /package/{docs → Docs}/04-glossario/termos.md +0 -0
  32. /package/{docs → Docs}/partials/AVISO-PROVENIENCIA.md +0 -0
  33. /package/{docs → Docs}/templates/ADR.md +0 -0
  34. /package/{docs → Docs}/templates/componente.md +0 -0
  35. /package/{docs → Docs}/templates/guia.md +0 -0
@@ -17,6 +17,6 @@
17
17
  "repelStrength": 10,
18
18
  "linkStrength": 1,
19
19
  "linkDistance": 250,
20
- "scale": 1,
20
+ "scale": 0.6666666666666666,
21
21
  "close": true
22
22
  }
@@ -4,21 +4,21 @@
4
4
  "type": "split",
5
5
  "children": [
6
6
  {
7
- "id": "2dae1c0919723f46",
7
+ "id": "f49eb26fe94f5853",
8
8
  "type": "tabs",
9
9
  "children": [
10
10
  {
11
- "id": "d13e1d2e479b3201",
11
+ "id": "8dedf7c146f5cebf",
12
12
  "type": "leaf",
13
13
  "state": {
14
14
  "type": "markdown",
15
15
  "state": {
16
- "file": "02-componentes/_index.md",
16
+ "file": "03-guias/testes.md",
17
17
  "mode": "source",
18
18
  "source": false
19
19
  },
20
20
  "icon": "lucide-file",
21
- "title": "_index"
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": "d13e1d2e479b3201",
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
- - 222 test files, 3116 testes
26
- - Coverage total: ~47% (target: 56%+)
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`.*
@@ -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 | ~230 |
46
- | Testes | ~3200 |
47
- | Cobertura (statements) | ~47% |
48
- | Source lines | ~22k |
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
- 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).
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**: ~3200 testes em ~230 arquivos
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
- '# ?? Estrutura verificada',
7
+ RelatorioMensagens.estrutura.tituloVerificada,
8
8
  '',
9
- '? Tudo está em sua camada ideal.',
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.1",
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
- "docs",
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