@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.
- package/Docs/.obsidian/app.json +7 -0
- package/Docs/.obsidian/appearance.json +8 -0
- package/Docs/.obsidian/community-plugins.json +28 -0
- package/Docs/.obsidian/core-plugins-migration.json +18 -0
- package/Docs/.obsidian/core-plugins.json +73 -0
- package/Docs/.obsidian/graph.json +22 -0
- package/Docs/.obsidian/workspace.json +196 -0
- package/Docs/01-arquitetura/ADR-001-estrutura-testes.md +31 -0
- package/Docs/01-arquitetura/_index.md +152 -0
- package/Docs/02-componentes/_index.md +294 -0
- package/Docs/02-componentes/configuracao.md +110 -0
- package/Docs/02-componentes/supressao-inline.md +88 -0
- package/Docs/03-guias/_index.md +173 -0
- package/Docs/03-guias/contribuindo.md +71 -0
- package/Docs/03-guias/testes.md +133 -0
- package/Docs/04-glossario/_index.md +29 -0
- package/Docs/04-glossario/termos.md +247 -0
- package/Docs/05-referencias/_index.md +88 -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/_home.md +140 -0
- package/Docs/partials/AVISO-PROVENIENCIA.md +3 -0
- package/Docs/templates/ADR.md +24 -0
- package/Docs/templates/componente.md +34 -0
- package/Docs/templates/guia.md +28 -0
- package/README.md +269 -26
- package/dist/analysts/detectors/detector-bugs-ml.js +5 -0
- package/dist/analysts/js-ts/registrar.js +1 -1
- package/dist/analysts/plugins/detector-markdown.js +2 -2
- package/dist/analysts/react/analysts/analyst-react-hooks.js +30 -15
- package/dist/analysts/react/analysts/analyst-react.js +11 -2
- package/dist/analysts/react/detectors/detector-react-best-practices.js +7 -4
- package/dist/caretakers/caretaker-imports.js +0 -9
- package/dist/cli/commands/command-github-actions.js +0 -27
- 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/core/messages/en/cli/cli-command-github-actions-messages.js +0 -5
- package/dist/core/messages/en/github/index.js +0 -1
- package/dist/core/messages/ja/cli/cli-command-github-actions-messages.js +0 -5
- package/dist/core/messages/ja/github/index.js +0 -1
- package/dist/core/messages/pt/cli/cli-command-github-actions-messages.js +0 -5
- package/dist/core/messages/pt/github/index.js +0 -1
- package/dist/core/messages/zh/cli/cli-command-github-actions-messages.js +0 -5
- package/dist/core/messages/zh/github/index.js +0 -1
- package/dist/core/registry/file-registry.js +1 -1
- package/dist/node.loader.js +0 -2
- package/dist/reports/report-structure.js +2 -8
- package/dist/shared/formatters/formatters/commons.js +36 -10
- package/dist/shared/formatters/formatters/shell.js +6 -3
- package/dist/shared/helpers/magic-constants-whitelist.js +14 -1
- package/dist/types/analysts/index.js +1 -1
- package/dist/types/processing/filters.js +1 -4
- package/package.json +31 -32
- package/dist/app/github.js +0 -14
- package/dist/app/index.js +0 -1
- package/dist/core/messages/en/github/github-app-messages.js +0 -9
- package/dist/core/messages/ja/github/github-app-messages.js +0 -9
- package/dist/core/messages/pt/github/github-app-messages.js +0 -9
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
};
|
|
@@ -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
|
};
|
|
@@ -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
|
};
|
|
@@ -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,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 {
|
|
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);
|
package/dist/node.loader.js
CHANGED
|
@@ -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
|
-
|
|
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
|
'',
|
|
@@ -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 {
|