@mocoto/mahoraga 0.14.5 → 0.14.6

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/README.md CHANGED
@@ -8,15 +8,19 @@ Proveniência e Autoria: Este documento integra o projeto Mahoraga (licença MIT
8
8
 
9
9
  </div>
10
10
 
11
- <p> Estou ficando desanimado de continuar com esse projeto, caso goste do projeto e queira ajudar pra eu não desanimar entre em contato por esse E-mail: /p>
11
+ <p> Desisti de desistir do projeto, até parece que vou aceitar perder pra vocês ...</p>
12
+
13
+ <p> caso tenha interesse em ajudar no projeto o E-mail é esse ai em baixo o **lint que me aguarde 😜 </p>
12
14
 
13
15
  [Gmail](mailto:mocoto.persona@gmail.com)
14
16
 
17
+ <h5> Alias!! ignora o sugestoes-00*.json ainda esta em ajustes.</h5>
18
+
15
19
  ## Começar Rápido (30 segundos)
16
20
 
17
21
  ```bash
18
22
  # 1. Instalar
19
- npm install -g mahoraga
23
+ npm install -g @mocoto/mahoraga
20
24
 
21
25
  # 2. Analisar seu projeto
22
26
  cd meu-projeto
@@ -185,25 +189,16 @@ mahoraga metricas
185
189
 
186
190
  **Uso global:**
187
191
  ```bash
188
- npm install -g mahoraga
192
+ npm install -g @mocoto/mahoraga
189
193
  mahoraga --version
190
194
  ```
191
195
 
192
196
  **Uso local no projeto:**
193
197
  ```bash
194
- npm install --save-dev mahoraga
198
+ npm install --save-dev @mocoto/mahoraga
195
199
  npx mahoraga --help
196
200
  ```
197
201
 
198
- ### Do Repositório
199
-
200
- ```bash
201
- git clone https://github.com/o-atoa/mahoraga.git
202
- cd mahoraga
203
- npm install
204
- npm run build
205
- npm link
206
- ```
207
202
 
208
203
  ### Docker
209
204
 
@@ -612,19 +607,6 @@ mahoraga github-actions gate --threshold 80 --fail-on erro
612
607
 
613
608
  ---
614
609
 
615
- ## Desenvolvimento
616
-
617
- ### Setup
618
-
619
- ```bash
620
- git clone https://github.com/o-atoa/mahoraga.git
621
- cd mahoraga
622
- npm install
623
- npm run build
624
- npm link
625
- mahoraga --version
626
- ```
627
-
628
610
  ### Scripts
629
611
 
630
612
  ```bash
@@ -691,18 +673,6 @@ Dependências de terceiros listadas em [THIRD-PARTY-NOTICES.txt](./THIRD-PARTY-N
691
673
 
692
674
  ---
693
675
 
694
- <div align="center">
695
-
696
- [![npm](https://img.shields.io/badge/npm-mahoraga-CB3837)](https://www.npmjs.com/package/mahoraga)
697
- [![GitHub](https://img.shields.io/badge/github-blue--diaz/mahoraga-181717)](https://github.com/o-atoa/mahoraga)
698
- [![Issues](https://img.shields.io/badge/issues-report-FF4500)](https://github.com/o-atoa/mahoraga/issues)
699
- [![Releases](https://img.shields.io/badge/releases-latest-2ea44f)](https://github.com/o-atoa/mahoraga/releases)
700
-
701
- **Feito para os iniciantes** — [Voltar ao topo](#mahoraga)
676
+ **Feito para os iniciantes**
702
677
 
703
678
  </div>
704
- # mahoraga
705
-
706
- # mahoraga
707
- # mahoraga
708
- # mahoraga
@@ -51,7 +51,7 @@ export const detectorEstrutura = {
51
51
  const setCaminhos = new Set(caminhos);
52
52
  // Detecta contexto geral do projeto para análise inteligente
53
53
  const arquivoPrincipal = caminhos?.find(caminho => /package\.json$/.test(caminho)) ?? caminhos[0];
54
- const conteudoPrincipal = contexto.arquivos.find(arquivo => arquivo.relPath === arquivoPrincipal)?.content ?? '';
54
+ const conteudoPrincipal = contexto.arquivos?.find(arquivo => arquivo.relPath === arquivoPrincipal)?.content ?? '';
55
55
  const contextoProjeto = detectarContextoProjeto({
56
56
  arquivo: arquivoPrincipal,
57
57
  conteudo: conteudoPrincipal,
@@ -33,8 +33,63 @@ function extractHookCallContent(src, startIndex) {
33
33
  let depth = 0;
34
34
  let started = false;
35
35
  let content = '';
36
+ let inSingle = false;
37
+ let inDouble = false;
38
+ let inBacktick = false;
39
+ let escaped = false;
36
40
  for (let i = startIndex; i < src.length; i++) {
37
41
  const char = src[i];
42
+ if (escaped) {
43
+ escaped = false;
44
+ if (started)
45
+ content += char;
46
+ continue;
47
+ }
48
+ if (char === '\\' && (inSingle || inDouble || inBacktick)) {
49
+ escaped = true;
50
+ if (started)
51
+ content += char;
52
+ continue;
53
+ }
54
+ if (inSingle) {
55
+ if (char === "'")
56
+ inSingle = false;
57
+ if (started)
58
+ content += char;
59
+ continue;
60
+ }
61
+ if (inDouble) {
62
+ if (char === '"')
63
+ inDouble = false;
64
+ if (started)
65
+ content += char;
66
+ continue;
67
+ }
68
+ if (inBacktick) {
69
+ if (char === '`')
70
+ inBacktick = false;
71
+ if (started)
72
+ content += char;
73
+ continue;
74
+ }
75
+ if (char === "'") {
76
+ inSingle = true;
77
+ if (started)
78
+ content += char;
79
+ continue;
80
+ }
81
+ if (char === '"') {
82
+ inDouble = true;
83
+ if (started)
84
+ content += char;
85
+ continue;
86
+ }
87
+ if (char === '`') {
88
+ inBacktick = true;
89
+ if (started)
90
+ content += char;
91
+ continue;
92
+ }
38
93
  if (char === '(') {
39
94
  depth++;
40
95
  started = true;
@@ -59,7 +114,22 @@ function collectHookIssues(src, relPath) {
59
114
  effectMatches.forEach(m => {
60
115
  const hookInicio = m.index;
61
116
  const fullCall = extractHookCallContent(src, hookInicio + m[0].length - 1);
62
- const hasDepsArg = /,\s*(\[[\s\S]*?\]|\w+)\s*\)$/.test(fullCall);
117
+ // More robust deps detection: find the last comma followed by an array or identifier before the closing paren
118
+ const hasDepsArg = (() => {
119
+ // Find the last ')' (closing paren of the full call)
120
+ const lastClosing = fullCall.lastIndexOf(')');
121
+ if (lastClosing === -1)
122
+ return false;
123
+ const beforeClosing = fullCall.slice(0, lastClosing);
124
+ // Find the last '[' or identifier before the closing paren
125
+ const arrayMatch = beforeClosing.match(/,\s*(\[[\s\S]*?\])\s*$/);
126
+ if (arrayMatch)
127
+ return true;
128
+ const identMatch = beforeClosing.match(/,\s*(\w+)\s*$/);
129
+ if (identMatch)
130
+ return true;
131
+ return false;
132
+ })();
63
133
  const skip = /no-deps-ok|eslint-disable-next-line\s+react-hooks\/exhaustive-deps/i.test(fullCall);
64
134
  if (!hasDepsArg && !skip) {
65
135
  const line = lineOf(hookInicio);
@@ -89,10 +159,18 @@ function collectHookIssues(src, relPath) {
89
159
  ocorrencias.push(warn(messages.ReactHooksMensagens.memoCallbackNoDeps, relPath, line));
90
160
  }
91
161
  });
92
- // Conditional hooks
93
- const conditionalHooks = [...src.matchAll(/(if|for|while)\s*\([^)]*\)\s*\{[\s\S]{0,160}?use[A-Z][A-Za-z0-9_]*/g)];
162
+ // Conditional hooks — only flag when a hook call is directly inside a conditional block,
163
+ // not when the conditional is inside a hook callback (e.g. cleanup inside useEffect).
164
+ // The regex matches: if/for/while (...) { ... useXxx ... } but limits the match scope
165
+ // to avoid matching conditionals that appear inside hook callbacks.
166
+ const conditionalHooks = [...src.matchAll(/(?:^|(?<=[\n;]))\s*(if|for|while)\s*\([^)]*\)\s*\{[\s\S]{0,160}?use[A-Z][A-Za-z0-9_]*/g)];
94
167
  conditionalHooks.forEach(m => {
95
168
  const line = lineOf(m.index || 0);
169
+ // Heuristic: skip if the 'if' keyword is preceded by a closing paren or brace at the same indentation,
170
+ // which suggests it's inside a callback body rather than at the component top level.
171
+ const pre = src.slice(Math.max(0, (m.index ?? 0) - 80), m.index ?? 0);
172
+ if (/=>\s*$|\)\s*=>\s*$|\)\s*\{[\s\S]{0,40}$/.test(pre))
173
+ return;
96
174
  ocorrencias.push(warn(messages.ReactHooksMensagens.hookInConditional, relPath, line));
97
175
  });
98
176
  // React 19: useOptimistic detected
@@ -127,7 +205,7 @@ function collectHookIssues(src, relPath) {
127
205
  if (!ALL_BUILTIN_HOOKS.includes(hookName)) {
128
206
  if (/^use[A-Z]/.test(hookName)) {
129
207
  const line = lineOf(m.index || 0);
130
- ocorrencias.push(warn(`Custom hook '${hookName}' - verify naming follows useXxx convention`, relPath, line));
208
+ ocorrencias.push(warn(`Custom hook '${hookName}' - verify naming follows useXxx convention`, relPath, line, messages.SeverityNiveis.info));
131
209
  }
132
210
  }
133
211
  });
@@ -182,7 +260,26 @@ function parseHooksWithBabel(src, relPath) {
182
260
  const isMemoLike = (name) => name === 'useMemo' || name === 'useCallback';
183
261
  const isAnyHook = (name) => /^use[A-Z0-9_]/.test(name) || name === 'use';
184
262
  const inConditionalOrLoop = (path) => {
185
- return Boolean(path.findParent(p => p.isIfStatement() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isSwitchStatement() || p.isConditionalExpression()));
263
+ // Only consider conditionals/loops in the SAME function scope, not inside nested callbacks.
264
+ // Stop climbing at the nearest function boundary to avoid false positives when
265
+ // a hook is used inside a callback that happens to be in a conditional context.
266
+ let current = path;
267
+ while (current) {
268
+ const parent = current.findParent(p => p.isIfStatement() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isSwitchStatement() || p.isConditionalExpression());
269
+ if (parent)
270
+ return true;
271
+ // Climb to the nearest function boundary; stop if we hit one
272
+ const fnBoundary = current.findParent(p => p.isFunction());
273
+ if (!fnBoundary)
274
+ break;
275
+ // If the fnBoundary is the component function itself, we've exhausted this scope
276
+ // Check if there's a conditional ABOVE this function boundary
277
+ const aboveFn = fnBoundary.findParent(p => p.isIfStatement() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isSwitchStatement() || p.isConditionalExpression());
278
+ if (aboveFn)
279
+ return true;
280
+ break;
281
+ }
282
+ return false;
186
283
  };
187
284
  const getIdentifiersInNode = (node) => {
188
285
  const ids = new Set();
@@ -329,7 +426,7 @@ function parseHooksWithBabel(src, relPath) {
329
426
  }
330
427
  }
331
428
  if (isAnyHook(name) && !isEffectLike(name) && !isMemoLike(name) && name !== 'useState' && name !== 'useRef' && name !== 'useContext' && name !== 'useReducer' && name !== 'useDebugValue' && name !== 'useId' && name !== 'useOptimistic' && name !== 'useActionState' && name !== 'useFormStatus' && name !== 'use') {
332
- pushOnce(warn(`Custom hook '${name}' usage detected`, relPath, locLine));
429
+ pushOnce(warn(`Custom hook '${name}' usage detected`, relPath, locLine, messages.SeverityNiveis.info));
333
430
  }
334
431
  }
335
432
  catch {
@@ -38,6 +38,11 @@ function collectReactIssues(src, relPath) {
38
38
  // dangerouslySetInnerHTML
39
39
  for (const match of src.matchAll(/dangerouslySetInnerHTML/gi)) {
40
40
  const line = lineOf(match.index);
41
+ // Skip if this is a <script type="speculationrules"> element — dangerouslySetInnerHTML
42
+ // is required for Speculation Rules API (no children allowed, only innerHTML).
43
+ const lineContent = src.split('\n')[line - 1] ?? '';
44
+ if (/speculationrules/.test(lineContent))
45
+ continue;
41
46
  ocorrencias.push(warn(messages.ReactMensagens.dangerouslySetInnerHTML, relPath, line));
42
47
  }
43
48
  // <img> sem alt
@@ -233,6 +238,13 @@ function parseReactWithBabel(scan, relPath) {
233
238
  }
234
239
  }
235
240
  if (findAttr(attrs, 'dangerouslySetInnerHTML')) {
241
+ // Skip if this is a <script type="speculationrules"> — dangerouslySetInnerHTML
242
+ // is required for Speculation Rules API (no children, only innerHTML).
243
+ if (tag.toLowerCase() === 'script') {
244
+ const typeAttr = findAttr(attrs, 'type');
245
+ if (typeAttr && /speculationrules/i.test(normalizeStringValue(typeAttr.value)))
246
+ return;
247
+ }
236
248
  pushOnce(warn(messages.ReactMensagens.dangerouslySetInnerHTML, relPath, locLine));
237
249
  }
238
250
  // Inline Styles
@@ -23,6 +23,9 @@ export const detectorReactBestPractices = {
23
23
  linhas.forEach((linha, index) => {
24
24
  const numeroLinha = index + 1;
25
25
  if (/dangerouslySetInnerHTML/.test(linha)) {
26
+ // Skip <script type="speculationrules"> — dangerouslySetInnerHTML is required
27
+ if (/speculationrules/i.test(linha))
28
+ return;
26
29
  ocorrencias.push(warn('react-dangerous-html', D.dangerousHtml, relPath, numeroLinha, D.dangerousHtmlSugestao, 'erro'));
27
30
  }
28
31
  if (/onClick=|onSubmit=|onChange=|onMouseOver=/.test(linha) && /{[^}]*=>/.test(linha)) {
@@ -101,7 +104,27 @@ function detectWithBabel(src, relPath) {
101
104
  }
102
105
  const locLine = path.node.loc?.start.line;
103
106
  if (isHookName(name)) {
104
- const parent = path.findParent(p => p.isIfStatement() || p.isConditionalExpression() || p.isLogicalExpression() || p.isSwitchStatement() || p.isSwitchCase() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isLoop());
107
+ // Only flag hooks inside conditionals in the SAME function scope.
108
+ // Stop climbing at function boundaries (callbacks, event handlers, etc.)
109
+ // to avoid false positives when a conditional is inside a hook callback.
110
+ const parent = (() => {
111
+ let currentPath = path;
112
+ while (currentPath) {
113
+ const found = currentPath.findParent(p => p.isIfStatement() || p.isConditionalExpression() || p.isLogicalExpression() || p.isSwitchStatement() || p.isSwitchCase() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isLoop());
114
+ if (found)
115
+ return found;
116
+ // Stop at function boundaries
117
+ const fnBoundary = currentPath.findParent(p => p.isFunction());
118
+ if (!fnBoundary)
119
+ return null;
120
+ // Check above the function boundary
121
+ const aboveFn = fnBoundary.findParent(p => p.isIfStatement() || p.isConditionalExpression() || p.isLogicalExpression() || p.isSwitchStatement() || p.isSwitchCase() || p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement() || p.isLoop());
122
+ if (aboveFn)
123
+ return aboveFn;
124
+ return null;
125
+ }
126
+ return null;
127
+ })();
105
128
  if (parent) {
106
129
  pushOnce(warn('react-hook-conditional', D.hookConditionalCall, relPath, locLine, D.hookConditionalCallSugestao, 'erro'));
107
130
  }
@@ -311,8 +311,11 @@ function propertyKey(token) {
311
311
  re: /^max-h(?:-|\[)/,
312
312
  key: 'max-h'
313
313
  }, {
314
- re: /^(top|left|right|bottom)(?:-|\[)/,
315
- key: 'position'
314
+ re: /^(top|bottom)(?:-|\[)/,
315
+ key: 'position-y'
316
+ }, {
317
+ re: /^(left|right)(?:-|\[)/,
318
+ key: 'position-x'
316
319
  }, {
317
320
  re: /^field-sizing(?:-|\[)/,
318
321
  key: 'field-sizing'
@@ -2,19 +2,37 @@
2
2
  import { execSync } from 'node:child_process';
3
3
  import { config } from '../config/index.js';
4
4
  import { getMessages } from '../messages/index.js';
5
+ // Expressão regular para detectar shell metacharacters perigosos
6
+ // que permitiriam injeção de comandos adicionais.
7
+ // Bloqueia: ; | & ` $() ${} <> \n
8
+ const SHELL_INJECTION_RE = /[;|&`]|\$[({]|\${|>|<|\\n/;
9
+ /**
10
+ * Valida que o comando não contém caracteres de injeção shell.
11
+ * @param cmd - Comando a validar
12
+ * @throws Error se o comando contiver padrões perigosos
13
+ */
14
+ function validarComando(cmd) {
15
+ if (SHELL_INJECTION_RE.test(cmd)) {
16
+ throw new Error(`Comando rejeitado por segurança: contém caracteres de injeção shell.`);
17
+ }
18
+ }
19
+ function verificarSafeMode() {
20
+ if (config.SAFE_MODE && !config.ALLOW_EXEC) {
21
+ throw new Error(getMessages().ExecSafeMensagens.safeModeBloqueado);
22
+ }
23
+ }
5
24
  /**
6
25
  * Executa um comando shell de forma segura.
7
26
  * Bloqueia a execução quando SAFE_MODE está ativo e ALLOW_EXEC não está habilitado.
27
+ * Também valida o comando contra injeção shell mesmo quando a execução é permitida.
8
28
  * @param cmd - Comando shell a executar
9
29
  * @param opts - Opções do execSync do Node.js
10
30
  * @returns Buffer ou string com a saída do comando
11
- * @throws Error se SAFE_MODE estiver ativo sem ALLOW_EXEC
31
+ * @throws Error se SAFE_MODE estiver ativo sem ALLOW_EXEC ou se o comando for inválido
12
32
  */
13
33
  export function executarShellSeguro(cmd, opts = {}) {
14
- // only block if SAFE_MODE is explicitly true and ALLOW_EXEC is falsy
15
- if (config.SAFE_MODE && !config.ALLOW_EXEC) {
16
- throw new Error(getMessages().ExecSafeMensagens.safeModeBloqueado);
17
- }
34
+ validarComando(cmd);
35
+ verificarSafeMode();
18
36
  return execSync(cmd, opts);
19
37
  }
20
38
  /**
@@ -197,7 +197,6 @@ const aliases = {
197
197
  "@reports": "./src/reports/index",
198
198
  "@reports/compliance": "./src/reports/compliance/index",
199
199
  "@scripts": "./src/scripts/index",
200
- "@sdk": "./src/sdk/index",
201
200
  "@shared": "./src/shared/index",
202
201
  "@shared/data-processing": "./src/shared/data-processing/index",
203
202
  "@shared/formatters": "./src/shared/formatters/index",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mocoto/mahoraga",
3
- "version": "0.14.5",
3
+ "version": "0.14.6",
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": "rei macaco",
package/dist/index.js DELETED
@@ -1,2 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- export { analyzeFile, analyzeProject } from './sdk/analyzer.js';
@@ -1,88 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- import path from 'node:path';
3
- import { executarInquisicao, scanRepository } from '../core/execution/index.js';
4
- import { decifrarSintaxe } from '../core/parsing/index.js';
5
- import { asTecnicas } from '../types/index.js';
6
- const EXTENSOES_COM_AST = new Set([
7
- '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
8
- '.css', '.scss', '.html', '.xml', '.svg',
9
- '.py', '.go', '.rs', '.php', '.sh',
10
- '.yaml', '.yml', '.json',
11
- ]);
12
- function extensaoRelevante(relPath) {
13
- const ext = path.extname(relPath).toLowerCase();
14
- return EXTENSOES_COM_AST.has(ext);
15
- }
16
- async function carregarTecnicas() {
17
- const { registroAnalistas } = await import('../analysts/registry/index.js');
18
- return asTecnicas(registroAnalistas);
19
- }
20
- function tecnicasParaArquivo(tecnicas, relPath) {
21
- return tecnicas.filter(t => {
22
- if (t.global) {
23
- return false;
24
- }
25
- if (!t.test) {
26
- return extensaoRelevante(relPath);
27
- }
28
- return t.test(relPath);
29
- });
30
- }
31
- const AST_SENTINEL = {};
32
- export async function analyzeFile(filePath, content, baseDir) {
33
- const inicio = performance.now();
34
- const relPath = baseDir ? path.relative(baseDir, filePath) : path.basename(filePath);
35
- if (!extensaoRelevante(relPath)) {
36
- return { ocorrencias: [], arquivo: relPath, tempoMs: 0 };
37
- }
38
- const ext = path.extname(filePath).toLowerCase();
39
- const parsed = await decifrarSintaxe(content, ext, { relPath });
40
- const ast = parsed ? AST_SENTINEL : null;
41
- const tecnicas = await carregarTecnicas();
42
- const tecnicasFile = tecnicasParaArquivo(tecnicas, relPath);
43
- if (tecnicasFile.length === 0) {
44
- return { ocorrencias: [], arquivo: relPath, tempoMs: performance.now() - inicio };
45
- }
46
- const ocorrencias = [];
47
- for (const tecnica of tecnicasFile) {
48
- try {
49
- const resultado = await tecnica.aplicar(content, relPath, ast, filePath);
50
- if (Array.isArray(resultado)) {
51
- ocorrencias.push(...resultado);
52
- }
53
- else if (resultado) {
54
- ocorrencias.push(resultado);
55
- }
56
- }
57
- catch {
58
- // Silencia erros por analista
59
- }
60
- }
61
- return {
62
- ocorrencias,
63
- arquivo: relPath,
64
- tempoMs: performance.now() - inicio,
65
- };
66
- }
67
- export async function analyzeProject(projectDir, opts) {
68
- const inicio = performance.now();
69
- const fileEntries = await scanRepository(projectDir, {
70
- includeContent: true,
71
- });
72
- const entries = Object.values(fileEntries);
73
- const fileEntriesComAst = entries.map(f => ({ ...f, ast: undefined }));
74
- let filteredEntries = fileEntriesComAst;
75
- if (opts?.fast) {
76
- filteredEntries = fileEntriesComAst.filter(fe => {
77
- const rel = fe.relPath || '';
78
- return !rel.includes('node_modules') && !rel.includes('.test.') && !rel.includes('.spec.');
79
- });
80
- }
81
- const tecnicas = await carregarTecnicas();
82
- const resultadoExecucao = await executarInquisicao(filteredEntries, tecnicas, projectDir, null, { verbose: false, compact: true, fast: opts?.fast });
83
- return {
84
- ocorrencias: resultadoExecucao.ocorrencias,
85
- totalArquivos: entries.length,
86
- tempoMs: performance.now() - inicio,
87
- };
88
- }
package/dist/sdk/index.js DELETED
@@ -1,2 +0,0 @@
1
- export { analyzeFile, analyzeProject } from './analyzer.js';
2
- export { MahoragaSDK } from './sdk-legacy.js';
@@ -1,36 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- import { analistaGithubActions, analistaGithubActionsGlobal, registrarDetectorGithubActions } from '../analysts/github-actions/index.js';
3
- /**
4
- * Mahoraga SDK Principal
5
- * Fornece acesso programático aos analistas e sistema de plugins
6
- */
7
- export const MahoragaSDK = {
8
- /**
9
- * Analisa um conteúdo de workflow individual
10
- */
11
- async analisarGithubActions(conteudo, relPath = '.github/workflows/main.yml') {
12
- try {
13
- const res = await analistaGithubActions.aplicar(conteudo, relPath, null, undefined, undefined);
14
- return Array.isArray(res) ? res : [];
15
- }
16
- catch {
17
- return [];
18
- }
19
- },
20
- /**
21
- * Analisa um repositório completo (Contexto global)
22
- */
23
- async analisarRepositorio(contexto) {
24
- try {
25
- const res = await analistaGithubActionsGlobal.aplicar('', '', null, undefined, contexto);
26
- return Array.isArray(res) ? res : [];
27
- }
28
- catch {
29
- return [];
30
- }
31
- },
32
- /**
33
- * Registra um novo plugin de detector
34
- */
35
- registrarDetector: registrarDetectorGithubActions
36
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export * from './analyzer.js';