@mocoto/mahoraga 0.15.0 → 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.
Files changed (61) hide show
  1. package/Docs/.obsidian/app.json +7 -0
  2. package/Docs/.obsidian/appearance.json +8 -0
  3. package/Docs/.obsidian/community-plugins.json +28 -0
  4. package/Docs/.obsidian/core-plugins-migration.json +18 -0
  5. package/Docs/.obsidian/core-plugins.json +73 -0
  6. package/Docs/.obsidian/graph.json +22 -0
  7. package/Docs/.obsidian/workspace.json +196 -0
  8. package/Docs/01-arquitetura/ADR-001-estrutura-testes.md +31 -0
  9. package/Docs/01-arquitetura/_index.md +152 -0
  10. package/Docs/02-componentes/_index.md +294 -0
  11. package/Docs/02-componentes/configuracao.md +110 -0
  12. package/Docs/02-componentes/supressao-inline.md +88 -0
  13. package/Docs/03-guias/_index.md +173 -0
  14. package/Docs/03-guias/contribuindo.md +71 -0
  15. package/Docs/03-guias/testes.md +133 -0
  16. package/Docs/04-glossario/_index.md +29 -0
  17. package/Docs/04-glossario/termos.md +247 -0
  18. package/Docs/05-referencias/_index.md +88 -0
  19. package/Docs/06-feedbacks/feedback.md +74 -0
  20. package/Docs/Sem t/303/255tulo.base" +3 -0
  21. package/Docs/Sem t/303/255tulo.md +0 -0
  22. package/Docs/_home.md +140 -0
  23. package/Docs/partials/AVISO-PROVENIENCIA.md +3 -0
  24. package/Docs/templates/ADR.md +24 -0
  25. package/Docs/templates/componente.md +34 -0
  26. package/Docs/templates/guia.md +28 -0
  27. package/README.md +269 -26
  28. package/dist/analysts/detectors/detector-bugs-ml.js +5 -0
  29. package/dist/analysts/js-ts/registrar.js +1 -1
  30. package/dist/analysts/plugins/detector-markdown.js +2 -2
  31. package/dist/analysts/react/analysts/analyst-react-hooks.js +30 -15
  32. package/dist/analysts/react/analysts/analyst-react.js +11 -2
  33. package/dist/analysts/react/detectors/detector-react-best-practices.js +7 -4
  34. package/dist/caretakers/caretaker-imports.js +0 -9
  35. package/dist/cli/commands/command-github-actions.js +0 -27
  36. package/dist/cli/diagnostic/filters.js +1 -4
  37. package/dist/core/config/config.js +2 -3
  38. package/dist/core/config/excludes-padrao.js +3 -2
  39. package/dist/core/messages/en/cli/cli-command-github-actions-messages.js +0 -5
  40. package/dist/core/messages/en/github/index.js +0 -1
  41. package/dist/core/messages/ja/cli/cli-command-github-actions-messages.js +0 -5
  42. package/dist/core/messages/ja/github/index.js +0 -1
  43. package/dist/core/messages/pt/cli/cli-command-github-actions-messages.js +0 -5
  44. package/dist/core/messages/pt/github/index.js +0 -1
  45. package/dist/core/messages/zh/cli/cli-command-github-actions-messages.js +0 -5
  46. package/dist/core/messages/zh/github/index.js +0 -1
  47. package/dist/core/registry/file-registry.js +1 -1
  48. package/dist/node.loader.js +0 -2
  49. package/dist/reports/report-structure.js +2 -8
  50. package/dist/shared/formatters/formatters/commons.js +36 -10
  51. package/dist/shared/formatters/formatters/shell.js +6 -3
  52. package/dist/shared/helpers/magic-constants-whitelist.js +14 -1
  53. package/dist/types/analysts/index.js +1 -1
  54. package/dist/types/processing/filters.js +1 -4
  55. package/package.json +31 -32
  56. package/dist/app/github.js +0 -14
  57. package/dist/app/index.js +0 -1
  58. package/dist/core/messages/en/github/github-app-messages.js +0 -9
  59. package/dist/core/messages/ja/github/github-app-messages.js +0 -9
  60. package/dist/core/messages/pt/github/github-app-messages.js +0 -9
  61. package/dist/core/messages/zh/github/github-app-messages.js +0 -9
@@ -40,53 +40,64 @@ function extractHookCallContent(src, startIndex) {
40
40
  const char = src[i];
41
41
  if (escaped) {
42
42
  escaped = false;
43
- if (started)
43
+ if (started) {
44
44
  content += char;
45
+ }
45
46
  continue;
46
47
  }
47
48
  if (char === '\\' && (inSingle || inDouble || inBacktick)) {
48
49
  escaped = true;
49
- if (started)
50
+ if (started) {
50
51
  content += char;
52
+ }
51
53
  continue;
52
54
  }
53
55
  if (inSingle) {
54
- if (char === "'")
56
+ if (char === "'") {
55
57
  inSingle = false;
56
- if (started)
58
+ }
59
+ if (started) {
57
60
  content += char;
61
+ }
58
62
  continue;
59
63
  }
60
64
  if (inDouble) {
61
- if (char === '"')
65
+ if (char === '"') {
62
66
  inDouble = false;
63
- if (started)
67
+ }
68
+ if (started) {
64
69
  content += char;
70
+ }
65
71
  continue;
66
72
  }
67
73
  if (inBacktick) {
68
- if (char === '`')
74
+ if (char === '`') {
69
75
  inBacktick = false;
70
- if (started)
76
+ }
77
+ if (started) {
71
78
  content += char;
79
+ }
72
80
  continue;
73
81
  }
74
82
  if (char === "'") {
75
83
  inSingle = true;
76
- if (started)
84
+ if (started) {
77
85
  content += char;
86
+ }
78
87
  continue;
79
88
  }
80
89
  if (char === '"') {
81
90
  inDouble = true;
82
- if (started)
91
+ if (started) {
83
92
  content += char;
93
+ }
84
94
  continue;
85
95
  }
86
96
  if (char === '`') {
87
97
  inBacktick = true;
88
- if (started)
98
+ if (started) {
89
99
  content += char;
100
+ }
90
101
  continue;
91
102
  }
92
103
  if (char === '(') {
@@ -116,15 +127,18 @@ function collectHookIssues(src, relPath, opts = {}) {
116
127
  const fullCall = extractHookCallContent(src, hookInicio + m[0].length - 1);
117
128
  const hasDepsArg = (() => {
118
129
  const lastClosing = fullCall.lastIndexOf(')');
119
- if (lastClosing === -1)
130
+ if (lastClosing === -1) {
120
131
  return false;
132
+ }
121
133
  const beforeClosing = fullCall.slice(0, lastClosing);
122
134
  const arrayMatch = beforeClosing.match(/,\s*(\[[\s\S]*?\])\s*$/);
123
- if (arrayMatch)
135
+ if (arrayMatch) {
124
136
  return true;
137
+ }
125
138
  const identMatch = beforeClosing.match(/,\s*(\w+)\s*$/);
126
- if (identMatch)
139
+ if (identMatch) {
127
140
  return true;
141
+ }
128
142
  return false;
129
143
  })();
130
144
  const skip = /no-deps-ok|eslint-disable-next-line\s+react-hooks\/exhaustive-deps/i.test(fullCall);
@@ -159,8 +173,9 @@ function collectHookIssues(src, relPath, opts = {}) {
159
173
  conditionalHooks.forEach(m => {
160
174
  const line = lineOf(m.index || 0);
161
175
  const pre = src.slice(Math.max(0, (m.index ?? 0) - 80), m.index ?? 0);
162
- if (/=>\s*$|\)\s*=>\s*$|\)\s*\{[\s\S]{0,40}$/.test(pre))
176
+ if (/=>\s*$|\)\s*=>\s*$|\)\s*\{[\s\S]{0,40}$/.test(pre)) {
163
177
  return;
178
+ }
164
179
  ocorrencias.push(warn(messages.ReactHooksMensagens.hookInConditional, relPath, line));
165
180
  });
166
181
  }
@@ -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);
@@ -34,8 +35,12 @@ function collectReactIssues(src, relPath) {
34
35
  for (const match of src.matchAll(/dangerouslySetInnerHTML/gi)) {
35
36
  const line = lineOf(match.index);
36
37
  const lineContent = src.split('\n')[line - 1] ?? '';
37
- if (/speculationrules/.test(lineContent))
38
+ if (/speculationrules/.test(lineContent)) {
38
39
  continue;
40
+ }
41
+ if (ALLOWLIST_DANGEROUSLY_SET_INNER_HTML.test(relPath)) {
42
+ continue;
43
+ }
39
44
  ocorrencias.push(warn(messages.ReactMensagens.dangerouslySetInnerHTML, relPath, line));
40
45
  }
41
46
  for (const match of src.matchAll(/<img[^>]*>/gi)) {
@@ -214,8 +219,12 @@ function parseReactWithBabel(scan, relPath) {
214
219
  if (findAttr(attrs, 'dangerouslySetInnerHTML')) {
215
220
  if (tag.toLowerCase() === 'script') {
216
221
  const typeAttr = findAttr(attrs, 'type');
217
- if (typeAttr && /speculationrules/i.test(normalizeStringValue(typeAttr.value)))
222
+ if (typeAttr && /speculationrules/i.test(normalizeStringValue(typeAttr.value))) {
218
223
  return;
224
+ }
225
+ }
226
+ if (ALLOWLIST_DANGEROUSLY_SET_INNER_HTML.test(tag)) {
227
+ return;
219
228
  }
220
229
  pushOnce(warn(messages.ReactMensagens.dangerouslySetInnerHTML, relPath, locLine));
221
230
  }
@@ -156,17 +156,20 @@ function detectWithBabel(src, relPath) {
156
156
  const locLine = path.node.loc?.start.line;
157
157
  if (isHookName(name)) {
158
158
  const parent = (() => {
159
- let currentPath = path;
159
+ const currentPath = path;
160
160
  while (currentPath) {
161
161
  const found = currentPath.findParent(p => p.isIfStatement() || p.isConditionalExpression() || p.isLogicalExpression() || p.isSwitchStatement() || p.isSwitchCase() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isLoop());
162
- if (found)
162
+ if (found) {
163
163
  return found;
164
+ }
164
165
  const fnBoundary = currentPath.findParent(p => p.isFunction());
165
- if (!fnBoundary)
166
+ if (!fnBoundary) {
166
167
  return null;
168
+ }
167
169
  const aboveFn = fnBoundary.findParent(p => p.isIfStatement() || p.isConditionalExpression() || p.isLogicalExpression() || p.isSwitchStatement() || p.isSwitchCase() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isLoop());
168
- if (aboveFn)
170
+ if (aboveFn) {
169
171
  return aboveFn;
172
+ }
170
173
  return null;
171
174
  }
172
175
  return null;
@@ -111,15 +111,6 @@ const PADRAO_ALIAS_CONFIGURACAO = {
111
111
  "@api/routes": "./src/api/routes/index.ts",
112
112
  "@api/server": "./src/api/server.ts",
113
113
  "@api/services": "./src/api/services/index.ts",
114
- "@app": "./src/app/index.ts",
115
- "@app/changelog": "./src/app/changelog/index.ts",
116
- "@app/github": "./src/app/github/app/index.ts",
117
- "@app/github/app": "./src/app/github/app/index.ts",
118
- "@app/github/dashboard": "./src/app/github/dashboard/index.ts",
119
- "@app/github/jobs": "./src/app/github/jobs/index.ts",
120
- "@app/github/push-analysis": "./src/app/github/push-analysis/index.ts",
121
- "@app/privacy-policy": "./src/app/privacy-policy/index.ts",
122
- "@app/terms-of-use": "./src/app/terms-of-use/index.ts",
123
114
  "@caretakers": "./src/caretakers/index.ts",
124
115
  "@cli": "./src/cli/index.ts",
125
116
  "@cli/commands": "./src/cli/commands/index.ts",
@@ -7,7 +7,6 @@ import { aplicarCorrecoes, salvarArquivoCorrigido } from '../../core/execution/i
7
7
  import { CliComandoGithubActionsMensagens, messages } from '../../core/messages/index.js';
8
8
  import { analistaGithubActions, analistaGithubActionsGlobal, autofixEngine, gerarRelatorio, obterDetectoresGithubActions, pontuarWorkflow, prepararDadosRelatorio } from '../../analysts/github-actions/index.js';
9
9
  import { ExitCode, sair } from '../helpers/index.js';
10
- import { iniciarServidorApp } from '../../app/github.js';
11
10
  const SCORE_MAX = 100;
12
11
  const SCORE_MIN = 0;
13
12
  const PENALTY_PER_OCCURRENCE = 5;
@@ -348,31 +347,5 @@ export function comandoGithubActions() {
348
347
  sair(ExitCode.Failure);
349
348
  }
350
349
  });
351
- cmd.command('app').description(CliComandoGithubActionsMensagens.descricaoApp)
352
- .option('-p, --port <number>', 'Porta do servidor', (process.env.MAHORAGA_API_PORT ?? process.env.PORT) ?? '3000')
353
- .action(async (opts) => {
354
- const appId = process.env.GITHUB_APP_ID;
355
- const privateKey = process.env.GITHUB_PRIVATE_KEY;
356
- const webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
357
- if (!appId || !privateKey || !webhookSecret) {
358
- log.erro(CliComandoGithubActionsMensagens.appSetupRequired);
359
- log.erro(CliComandoGithubActionsMensagens.appSetupEnvList);
360
- log.info(CliComandoGithubActionsMensagens.appDicaEnv);
361
- sair(ExitCode.Failure);
362
- return;
363
- }
364
- try {
365
- await iniciarServidorApp({
366
- appId,
367
- privateKey: privateKey.replace(/\\n/g, '\n'),
368
- webhookSecret,
369
- port: parseInt(opts.port, 10),
370
- });
371
- }
372
- catch (err) {
373
- log.erro(CliComandoGithubActionsMensagens.erroIniciarServidor(err instanceof Error ? err.message : String(err)));
374
- sair(ExitCode.Failure);
375
- }
376
- });
377
350
  return cmd;
378
351
  }
@@ -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
  }
@@ -3,7 +3,6 @@ export const CliComandoGithubActionsMensagens = {
3
3
  descricaoScan: 'Analyzes GitHub Actions workflows',
4
4
  descricaoReport: 'Generates workflow analysis report',
5
5
  descricaoGate: 'Quality gate for CI/CD - fails if score below threshold',
6
- descricaoApp: 'Starts the server to act as a GitHub App',
7
6
  optPath: 'Path to repository',
8
7
  optWorkflow: 'Analyze specific workflow',
9
8
  optFix: 'Automatically applies fixes when possible',
@@ -35,8 +34,4 @@ export const CliComandoGithubActionsMensagens = {
35
34
  gatePassou: (score, threshold) => `[OK] Gate passed! Score: ${score}/100 (threshold: ${threshold})`,
36
35
  gateFalhou: (score, threshold) => `[ERR] Gate failed! Score: ${score}/100 (threshold: ${threshold})`,
37
36
  gateFalhaMotivo: (motivo) => ` - ${motivo}`,
38
- appSetupRequired: 'To start the GitHub App, you need to configure the environment variables:',
39
- appSetupEnvList: ' - GITHUB_APP_ID\n - GITHUB_PRIVATE_KEY\n - GITHUB_WEBHOOK_SECRET',
40
- appDicaEnv: '\nTip: Create a .env file in the root with these variables.',
41
- erroIniciarServidor: (msg) => `Failed to start server: ${msg}`,
42
37
  };
@@ -1,4 +1,3 @@
1
- export * from './github-app-messages.js';
2
1
  export * from './github-push-report-messages.js';
3
2
  export * from './github-repo-downloader-messages.js';
4
3
  export * from './github-webhook-messages.js';
@@ -3,7 +3,6 @@ export const CliComandoGithubActionsMensagens = {
3
3
  descricaoScan: 'GitHub Actions ワークフローを分析',
4
4
  descricaoReport: 'ワークフロー分析レポートを生成',
5
5
  descricaoGate: 'CI/CD 品質ゲート - スコアがしきい値を下回ると失敗',
6
- descricaoApp: 'GitHub Appとして動作するサーバーを起動',
7
6
  optPath: 'リポジトリへのパス',
8
7
  optWorkflow: '特定のワークフローを分析',
9
8
  optFix: '可能な場合に自動的に修正を適用',
@@ -35,8 +34,4 @@ export const CliComandoGithubActionsMensagens = {
35
34
  gatePassou: (score, threshold) => `[OK] 品質ゲート通過! スコア: ${score}/100 (しきい値: ${threshold})`,
36
35
  gateFalhou: (score, threshold) => `[エラー] 品質ゲート失敗! スコア: ${score}/100 (しきい値: ${threshold})`,
37
36
  gateFalhaMotivo: (motivo) => ` - ${motivo}`,
38
- appSetupRequired: 'GitHub Appを起動するには、環境変数を設定する必要があります:',
39
- appSetupEnvList: ' - GITHUB_APP_ID\n - GITHUB_PRIVATE_KEY\n - GITHUB_WEBHOOK_SECRET',
40
- appDicaEnv: '\nヒント: ルートに .env ファイルを作成し、これらの変数を設定してください。',
41
- erroIniciarServidor: (msg) => `サーバー起動エラー: ${msg}`,
42
37
  };
@@ -1,4 +1,3 @@
1
- export * from './github-app-messages.js';
2
1
  export * from './github-push-report-messages.js';
3
2
  export * from './github-repo-downloader-messages.js';
4
3
  export * from './github-webhook-messages.js';
@@ -3,7 +3,6 @@ export const CliComandoGithubActionsMensagens = {
3
3
  descricaoScan: 'Analisa workflows do GitHub Actions',
4
4
  descricaoReport: 'Gera relatório de análise de workflows',
5
5
  descricaoGate: 'Gate de qualidade para CI/CD - falha se score abaixo do threshold',
6
- descricaoApp: 'Inicia o servidor para atuar como GitHub App',
7
6
  optPath: 'Caminho para o repositório',
8
7
  optWorkflow: 'Analisar workflow específico',
9
8
  optFix: 'Aplica correções automaticamente quando possível',
@@ -35,8 +34,4 @@ export const CliComandoGithubActionsMensagens = {
35
34
  gatePassou: (score, threshold) => `[OK] Gate passou! Score: ${score}/100 (threshold: ${threshold})`,
36
35
  gateFalhou: (score, threshold) => `[ERRO] Gate falhou! Score: ${score}/100 (threshold: ${threshold})`,
37
36
  gateFalhaMotivo: (motivo) => ` - ${motivo}`,
38
- appSetupRequired: 'Para iniciar o GitHub App, você precisa configurar as variáveis de ambiente:',
39
- appSetupEnvList: ' - GITHUB_APP_ID\n - GITHUB_PRIVATE_KEY\n - GITHUB_WEBHOOK_SECRET',
40
- appDicaEnv: '\nDica: Crie um arquivo .env na raiz com essas variáveis.',
41
- erroIniciarServidor: (msg) => `Erro ao iniciar servidor: ${msg}`,
42
37
  };
@@ -1,4 +1,3 @@
1
- export * from './github-app-messages.js';
2
1
  export * from './github-push-report-messages.js';
3
2
  export * from './github-repo-downloader-messages.js';
4
3
  export * from './github-webhook-messages.js';
@@ -3,7 +3,6 @@ export const CliComandoGithubActionsMensagens = {
3
3
  descricaoScan: '分析 GitHub Actions 工作流',
4
4
  descricaoReport: '生成工作流分析报告',
5
5
  descricaoGate: 'CI/CD 质量门 - 分数低于阈值则失败',
6
- descricaoApp: '启动服务器以作为 GitHub App 运行',
7
6
  optPath: '仓库路径',
8
7
  optWorkflow: '分析特定工作流',
9
8
  optFix: '自动应用修复(如可能)',
@@ -35,8 +34,4 @@ export const CliComandoGithubActionsMensagens = {
35
34
  gatePassou: (score, threshold) => `[OK] 质量门通过! 分数: ${score}/100 (阈值: ${threshold})`,
36
35
  gateFalhou: (score, threshold) => `[错误] 质量门失败! 分数: ${score}/100 (阈值: ${threshold})`,
37
36
  gateFalhaMotivo: (motivo) => ` - ${motivo}`,
38
- appSetupRequired: '要启动 GitHub App,您需要配置以下环境变量:',
39
- appSetupEnvList: ' - GITHUB_APP_ID\n - GITHUB_PRIVATE_KEY\n - GITHUB_WEBHOOK_SECRET',
40
- appDicaEnv: '\n提示: 在根目录创建一个 .env 文件并设置这些变量。',
41
- erroIniciarServidor: (msg) => `启动服务器错误: ${msg}`,
42
37
  };
@@ -1,4 +1,3 @@
1
- export * from './github-app-messages.js';
2
1
  export * from './github-push-report-messages.js';
3
2
  export * from './github-repo-downloader-messages.js';
4
3
  export * from './github-webhook-messages.js';
@@ -1,7 +1,7 @@
1
1
  import { promises as fs } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { messages } from '../messages/index.js';
4
- import { MIGRACAO_MAPA, MAHORAGA_ARQUIVOS, MAHORAGA_DIRS } from './paths.js';
4
+ import { MAHORAGA_ARQUIVOS, MAHORAGA_DIRS, MIGRACAO_MAPA } from './paths.js';
5
5
  async function fileExists(fileCaminho) {
6
6
  try {
7
7
  await fs.stat(fileCaminho);
@@ -109,8 +109,6 @@ const aliases = {
109
109
  "@analysts/xml/corrections": "./src/analysts/xml/corrections/index",
110
110
  "@analysts/xml/detectors": "./src/analysts/xml/detectors/index",
111
111
  "@analysts/xml/scorers": "./src/analysts/xml/scorers/index",
112
- "@app": "./src/app/index",
113
- "@app/github": "./src/app/github",
114
112
  "@caretakers": "./src/caretakers/index",
115
113
  "@cli": "./src/cli/index",
116
114
  "@cli/commands": "./src/cli/commands/index",
@@ -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
  '',
@@ -1,3 +1,20 @@
1
+ import { extrairSupressoes, isRegraSuprimida } from '../../helpers/index.js';
2
+ const REGRAS_SUPRESSAO_FORMATADOR = ['pontuacao-repetida', 'espacamento-incorreto', 'formatador', 'analista-formatador', '*'];
3
+ export function extrairLinhasProtegidasFormatador(src) {
4
+ const supressoes = extrairSupressoes(src);
5
+ const lines = src.split('\n');
6
+ const protegidas = new Set();
7
+ for (let indice = 0; indice < lines.length; indice++) {
8
+ const lineNo = indice + 1;
9
+ for (const regra of REGRAS_SUPRESSAO_FORMATADOR) {
10
+ if (isRegraSuprimida(regra, lineNo, supressoes)) {
11
+ protegidas.add(lineNo);
12
+ break;
13
+ }
14
+ }
15
+ }
16
+ return protegidas;
17
+ }
1
18
  export function normalizarFimDeLinha(code) {
2
19
  return code.replace(/\r\n?/g, '\n');
3
20
  }
@@ -88,7 +105,7 @@ export function corrigirEspacamentoBasicoCodigo(code) {
88
105
  count
89
106
  };
90
107
  }
91
- const REPEATABLE_TO_SINGLE = new Set([',', '.', '!', '?', ';']);
108
+ const REPEATABLE_TO_SINGLE = new Set([',', '.', '!', '?']);
92
109
  const REPEATABLE_KEEP_UP_TO_3 = new Set(['.', '!', '?']);
93
110
  const MULTI_PUNCT_RE = /([,\.!?:;_\-])\1+/g;
94
111
  const SPACE_BEFORE_PUNCT_RE = /\s+([,.:;!?])/g;
@@ -214,11 +231,14 @@ function shouldSkipLineForPunctuation(line, lineIndex, lines) {
214
231
  }
215
232
  return false;
216
233
  }
217
- function collapseRepeatedPunct(code) {
234
+ function collapseRepeatedPunct(code, protectedLines) {
218
235
  const lines = code.split('\n');
219
236
  let totalCount = 0;
220
237
  let changed = false;
221
238
  const out = lines.map((line, idx) => {
239
+ if (protectedLines?.has(idx + 1)) {
240
+ return line;
241
+ }
222
242
  if (shouldSkipLineForPunctuation(line, idx, lines)) {
223
243
  return line;
224
244
  }
@@ -280,12 +300,15 @@ function fixDotPunct(match, offset, fullLine) {
280
300
  }
281
301
  return '. ';
282
302
  }
283
- function fixSpacingAroundPunct(code) {
303
+ function fixSpacingAroundPunct(code, protectedLines) {
284
304
  const { text: protected_code, placeholders } = protectSequences(code);
285
305
  const lines = protected_code.split('\n');
286
306
  let totalChanges = 0;
287
307
  let changed = false;
288
308
  const out = lines.map((line, idx) => {
309
+ if (protectedLines?.has(idx + 1)) {
310
+ return line;
311
+ }
289
312
  if (shouldSkipLineForPunctuation(line, idx, lines)) {
290
313
  return line;
291
314
  }
@@ -329,11 +352,14 @@ const RELATIONAL_OPS = [{
329
352
  pattern: /->/g,
330
353
  replacement: '→'
331
354
  }];
332
- function normalizeRelationalOperators(code) {
355
+ function normalizeRelationalOperators(code, protectedLines) {
333
356
  const lines = code.split('\n');
334
357
  let totalCount = 0;
335
358
  let changed = false;
336
359
  const out = lines.map((line, idx) => {
360
+ if (protectedLines?.has(idx + 1)) {
361
+ return line;
362
+ }
337
363
  if (shouldSkipLineForPunctuation(line, idx, lines)) {
338
364
  return line;
339
365
  }
@@ -377,24 +403,24 @@ function restoreHtmlComments(code, placeholders) {
377
403
  function skipJsonYamlResult(code) {
378
404
  return { text: code, changed: false, stats: { pontuacaoRepetida: 0, espacamentoIncorreto: 0, operadoresRelacionais: 0 } };
379
405
  }
380
- export function corrigirPontuacaoECodigo(code) {
406
+ export function corrigirPontuacaoECodigo(code, protectedLines) {
381
407
  if (isJsonOrYaml(code)) {
382
408
  return skipJsonYamlResult(code);
383
409
  }
384
410
  const { text: semHtml, placeholders } = extractHtmlComments(code);
385
- const { text: collapsed, count: pontuacaoRepetida } = collapseRepeatedPunct(semHtml);
386
- const { text: spaced, count: espacamentoIncorreto } = fixSpacingAroundPunct(collapsed);
387
- const { text: normalized, count: operadoresRelacionais } = normalizeRelationalOperators(spaced);
411
+ const { text: collapsed, count: pontuacaoRepetida } = collapseRepeatedPunct(semHtml, protectedLines);
412
+ const { text: spaced, count: espacamentoIncorreto } = fixSpacingAroundPunct(collapsed, protectedLines);
413
+ const { text: normalized, count: operadoresRelacionais } = normalizeRelationalOperators(spaced, protectedLines);
388
414
  const restored = restoreHtmlComments(normalized, placeholders);
389
415
  const changed = pontuacaoRepetida > 0 || espacamentoIncorreto > 0 || operadoresRelacionais > 0;
390
416
  return { text: restored, changed, stats: { pontuacaoRepetida, espacamentoIncorreto, operadoresRelacionais } };
391
417
  }
392
- export function corrigirPontuacaoECodigoConservador(code) {
418
+ export function corrigirPontuacaoECodigoConservador(code, protectedLines) {
393
419
  if (isJsonOrYaml(code)) {
394
420
  return skipJsonYamlResult(code);
395
421
  }
396
422
  const { text: semHtml, placeholders } = extractHtmlComments(code);
397
- const { text: collapsed, count: pontuacaoRepetida } = collapseRepeatedPunct(semHtml);
423
+ const { text: collapsed, count: pontuacaoRepetida } = collapseRepeatedPunct(semHtml, protectedLines);
398
424
  const { text: spaced, count: espacamentoIncorreto } = corrigirEspacamentoBasicoCodigo(collapsed);
399
425
  const restored = restoreHtmlComments(spaced, placeholders);
400
426
  const changed = pontuacaoRepetida > 0 || espacamentoIncorreto > 0;
@@ -136,13 +136,15 @@ function isIndexInQuotes(line, index) {
136
136
  continue;
137
137
  }
138
138
  if (inSingle) {
139
- if (ch === "'")
139
+ if (ch === "'") {
140
140
  inSingle = false;
141
+ }
141
142
  continue;
142
143
  }
143
144
  if (inDouble) {
144
- if (ch === '"')
145
+ if (ch === '"') {
145
146
  inDouble = false;
147
+ }
146
148
  continue;
147
149
  }
148
150
  if (ch === "'") {
@@ -157,8 +159,9 @@ function isIndexInQuotes(line, index) {
157
159
  return inSingle || inDouble;
158
160
  }
159
161
  function isRealShellPipe(line, index) {
160
- if (isIndexInQuotes(line, index))
162
+ if (isIndexInQuotes(line, index)) {
161
163
  return false;
164
+ }
162
165
  const before = line.slice(0, index);
163
166
  return true;
164
167
  }
@@ -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
  }
@@ -5,6 +5,7 @@ export * from './strategists.js';
5
5
  export * from './azure-pipelines.js';
6
6
  export {} from './circleci.js';
7
7
  export * from './corrections.js';
8
+ export * from './css-in-js.js';
8
9
  export * from './dynamic-modules.js';
9
10
  export * from './github-actions-plugins.js';
10
11
  export {} from './github-actions-reports.js';
@@ -14,5 +15,4 @@ export {} from './jenkins.js';
14
15
  export * from './metrics.js';
15
16
  export * from './plugins.js';
16
17
  export * from './scoring.js';
17
- export * from './css-in-js.js';
18
18
  export * from './svg-plugins.js';
@@ -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 {