@skip-ai/scanner 0.2.0
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 +81 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +21 -0
- package/dist/cli.js.map +1 -0
- package/dist/detector.d.ts +14 -0
- package/dist/detector.d.ts.map +1 -0
- package/dist/detector.js +72 -0
- package/dist/detector.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +55 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +38 -0
- package/dist/reporter.js.map +1 -0
- package/dist/scanner/api-calls.d.ts +11 -0
- package/dist/scanner/api-calls.d.ts.map +1 -0
- package/dist/scanner/api-calls.js +45 -0
- package/dist/scanner/api-calls.js.map +1 -0
- package/dist/scanner/briefing.d.ts +7 -0
- package/dist/scanner/briefing.d.ts.map +1 -0
- package/dist/scanner/briefing.js +50 -0
- package/dist/scanner/briefing.js.map +1 -0
- package/dist/scanner/components.d.ts +24 -0
- package/dist/scanner/components.d.ts.map +1 -0
- package/dist/scanner/components.js +71 -0
- package/dist/scanner/components.js.map +1 -0
- package/dist/scanner/ignore.d.ts +13 -0
- package/dist/scanner/ignore.d.ts.map +1 -0
- package/dist/scanner/ignore.js +50 -0
- package/dist/scanner/ignore.js.map +1 -0
- package/dist/scanner/navigation.d.ts +50 -0
- package/dist/scanner/navigation.d.ts.map +1 -0
- package/dist/scanner/navigation.js +478 -0
- package/dist/scanner/navigation.js.map +1 -0
- package/dist/scanner/routes.d.ts +12 -0
- package/dist/scanner/routes.d.ts.map +1 -0
- package/dist/scanner/routes.js +74 -0
- package/dist/scanner/routes.js.map +1 -0
- package/dist/scanner/secrets.d.ts +18 -0
- package/dist/scanner/secrets.d.ts.map +1 -0
- package/dist/scanner/secrets.js +36 -0
- package/dist/scanner/secrets.js.map +1 -0
- package/dist/scanner/widget-snippet.d.ts +14 -0
- package/dist/scanner/widget-snippet.d.ts.map +1 -0
- package/dist/scanner/widget-snippet.js +114 -0
- package/dist/scanner/widget-snippet.js.map +1 -0
- package/dist/ui.d.ts +15 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +32 -0
- package/dist/ui.js.map +1 -0
- package/dist/uploader.d.ts +27 -0
- package/dist/uploader.d.ts.map +1 -0
- package/dist/uploader.js +73 -0
- package/dist/uploader.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @skip-ai/scanner
|
|
2
|
+
|
|
3
|
+
Scanner CLI da plataforma **Skip AI Accessibility Layer**.
|
|
4
|
+
|
|
5
|
+
Em uma única linha, o scanner detecta o framework do projeto, extrai rotas,
|
|
6
|
+
componentes, eventos e chamadas de API, mascara secrets e envia o relatório
|
|
7
|
+
para a API web da Skip, aguardando o enriquecimento com IA.
|
|
8
|
+
|
|
9
|
+
## Uso (npx)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @skip-ai/scanner --token=SEU_TOKEN_AQUI
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Não requer instalação prévia — o `npx` baixa e executa na hora.
|
|
16
|
+
|
|
17
|
+
## Opções
|
|
18
|
+
|
|
19
|
+
| Flag | Descrição | Padrão |
|
|
20
|
+
|------|-----------|--------|
|
|
21
|
+
| `-t, --token <token>` | Token do projeto (obrigatório) | — |
|
|
22
|
+
| `-u, --url <url>` | URL da plataforma Skip | `https://app.goskip.dev` |
|
|
23
|
+
| `-d, --dir <dir>` | Diretório raiz do projeto | `process.cwd()` |
|
|
24
|
+
| `-i, --ignore <patterns...>` | Padrões extras a ignorar (glob) | `[]` |
|
|
25
|
+
| `--dry-run` | Apenas escaneia, sem enviar para a API | `false` |
|
|
26
|
+
| `-v, --verbose` | Exibe o payload JSON no terminal | `false` |
|
|
27
|
+
|
|
28
|
+
## Desenvolvimento
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install
|
|
32
|
+
npm run build # gera dist/
|
|
33
|
+
npm test # roda os testes com vitest
|
|
34
|
+
npm run dev # executa via tsx (sem build)
|
|
35
|
+
node dist/index.js --token=TEST --dir=./tests/fixtures/nextjs-app --dry-run --verbose
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Segurança
|
|
39
|
+
|
|
40
|
+
Antes do envio, o scanner mascara automaticamente possíveis secrets
|
|
41
|
+
(OpenAI/AWS/GitHub/Slack keys, JWTs, senhas em env). O payload é limitado
|
|
42
|
+
a 5 MB (HTTP 413 caso exceda).
|
|
43
|
+
|
|
44
|
+
## Mapa de navegação (núcleo do produto)
|
|
45
|
+
|
|
46
|
+
O scanner não envia apenas um JSON — ele constrói um **mapa de navegação agrupado por tela**, onde cada tela tem suas próprias ações (botões, links e inputs), com seletor CSS e `anchorId` para o widget **emular o clique** e **preencher campos** em runtime.
|
|
47
|
+
|
|
48
|
+
Além do mapa estruturado, o payload inclui:
|
|
49
|
+
|
|
50
|
+
- **`briefing`**: resumo em linguagem natural das telas e ações, pronto para a IA interpretar intenções de voz (ex.: "quero ir pra configurações").
|
|
51
|
+
- **`widgetSnippet`**: snippet JS que o widget carrega no site do cliente para auto-injetar `data-skip-anchor` nos elementos mapeados — funciona mesmo sem o desenvolvedor marcar nada.
|
|
52
|
+
- **`navigationGraph`**: arestas de navegação (de → para) para a IA planejar caminhos entre telas, incluindo navegação global de sidebar/navbar.
|
|
53
|
+
|
|
54
|
+
### Como o widget usa (exemplo)
|
|
55
|
+
|
|
56
|
+
```jsonc
|
|
57
|
+
// navigationMap.screens[rotaAtual].actions → só as ações da tela em que o usuário está
|
|
58
|
+
{
|
|
59
|
+
"label": "Entrar", "kind": "submit",
|
|
60
|
+
"selector": "#btn-entrar", "anchorId": "btn-entrar"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
O widget clica via `document.querySelector('[data-skip-anchor=btn-entrar]').click()`.
|
|
65
|
+
|
|
66
|
+
### Escape para navegação dinâmica
|
|
67
|
+
|
|
68
|
+
Botões cuja navegação depende de runtime não são resolúveis estaticamente. Nestes casos, o desenvolvedor pode marcar manualmente:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<button data-skip-action="navigate:/checkout">Finalizar</button>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
O scanner lê esse atributo com prioridade.
|
|
75
|
+
|
|
76
|
+
## Frameworks suportados
|
|
77
|
+
|
|
78
|
+
- Next.js App Router (`src/app/**/page.tsx`)
|
|
79
|
+
- Next.js Pages Router (`src/pages/**`)
|
|
80
|
+
- Vite + React/Vue (componentes)
|
|
81
|
+
- NestJS, Django, FastAPI (detecção)
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CliOptions {
|
|
2
|
+
token?: string;
|
|
3
|
+
url: string;
|
|
4
|
+
dir: string;
|
|
5
|
+
ignore: string[];
|
|
6
|
+
verbose: boolean;
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const DEFAULT_BASE_URL = "https://app.goskip.dev";
|
|
10
|
+
export declare function parseCli(argv?: string[]): CliOptions;
|
|
11
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,MAAM,gBAAgB,2BAA2B,CAAC;AAEzD,wBAAgB,QAAQ,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,UAAU,CAuBlE"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export const DEFAULT_BASE_URL = 'https://app.goskip.dev';
|
|
3
|
+
export function parseCli(argv = process.argv) {
|
|
4
|
+
const program = new Command()
|
|
5
|
+
.name('skip-scanner')
|
|
6
|
+
.description('Scanner de código para a plataforma Skip AI Accessibility Layer')
|
|
7
|
+
.option('-t, --token <token>', 'Token do projeto (obtido no Dashboard). Obrigatório salvo em --dry-run.')
|
|
8
|
+
.option('-u, --url <url>', 'URL da plataforma Skip', DEFAULT_BASE_URL)
|
|
9
|
+
.option('-d, --dir <dir>', 'Diretório raiz do projeto', process.cwd())
|
|
10
|
+
.option('-i, --ignore <patterns...>', 'Padrões a ignorar além do padrão', [])
|
|
11
|
+
.option('--dry-run', 'Executa o scan sem enviar para a plataforma', false)
|
|
12
|
+
.option('-v, --verbose', 'Exibir detalhes do scan no terminal', false)
|
|
13
|
+
.parse(argv);
|
|
14
|
+
const opts = program.opts();
|
|
15
|
+
// Token só é obrigatório fora do dry-run (no dry-run nada é enviado à API).
|
|
16
|
+
if (!opts.dryRun && !opts.token) {
|
|
17
|
+
program.error("erro: a opção '-t, --token <token>' é obrigatória (ou use --dry-run para testar sem enviar).", { exitCode: 1 });
|
|
18
|
+
}
|
|
19
|
+
return opts;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAEzD,MAAM,UAAU,QAAQ,CAAC,OAAiB,OAAO,CAAC,IAAI;IACpD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;SAC1B,IAAI,CAAC,cAAc,CAAC;SACpB,WAAW,CAAC,iEAAiE,CAAC;SAC9E,MAAM,CAAC,qBAAqB,EAAE,yEAAyE,CAAC;SACxG,MAAM,CAAC,iBAAiB,EAAE,wBAAwB,EAAE,gBAAgB,CAAC;SACrE,MAAM,CAAC,iBAAiB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;SACrE,MAAM,CAAC,4BAA4B,EAAE,kCAAkC,EAAE,EAAE,CAAC;SAC5E,MAAM,CAAC,WAAW,EAAE,6CAA6C,EAAE,KAAK,CAAC;SACzE,MAAM,CAAC,eAAe,EAAE,qCAAqC,EAAE,KAAK,CAAC;SACrE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEf,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAgB,CAAC;IAE1C,4EAA4E;IAC5E,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CACX,8FAA8F,EAC9F,EAAE,QAAQ,EAAE,CAAC,EAAE,CAChB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Framework = 'nextjs' | 'vite-react' | 'nestjs' | 'django' | 'fastapi' | 'unknown';
|
|
2
|
+
export interface ProjectSignature {
|
|
3
|
+
framework: Framework;
|
|
4
|
+
language: 'TypeScript' | 'JavaScript' | 'Python';
|
|
5
|
+
hasAppRouter: boolean;
|
|
6
|
+
srcDir: string;
|
|
7
|
+
packageCount: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Detecta o framework e a linguagem do projeto a partir da raiz informada.
|
|
11
|
+
* Lê package.json e pyproject.toml quando existentes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectProject(rootDir: string): ProjectSignature;
|
|
14
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;IACjD,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAsE/D"}
|
package/dist/detector.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Detecta o framework e a linguagem do projeto a partir da raiz informada.
|
|
5
|
+
* Lê package.json e pyproject.toml quando existentes.
|
|
6
|
+
*/
|
|
7
|
+
export function detectProject(rootDir) {
|
|
8
|
+
const pkgPath = path.join(rootDir, 'package.json');
|
|
9
|
+
const pyprojectPath = path.join(rootDir, 'pyproject.toml');
|
|
10
|
+
if (fs.existsSync(pkgPath)) {
|
|
11
|
+
let pkg = {};
|
|
12
|
+
try {
|
|
13
|
+
pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
pkg = {};
|
|
17
|
+
}
|
|
18
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
19
|
+
if (deps['next']) {
|
|
20
|
+
const hasAppDir = fs.existsSync(path.join(rootDir, 'src/app')) || fs.existsSync(path.join(rootDir, 'app'));
|
|
21
|
+
const srcDir = fs.existsSync(path.join(rootDir, 'src/app'))
|
|
22
|
+
? 'src/app'
|
|
23
|
+
: fs.existsSync(path.join(rootDir, 'app'))
|
|
24
|
+
? 'app'
|
|
25
|
+
: 'src/pages';
|
|
26
|
+
return {
|
|
27
|
+
framework: 'nextjs',
|
|
28
|
+
language: fs.existsSync(path.join(rootDir, 'tsconfig.json')) ? 'TypeScript' : 'JavaScript',
|
|
29
|
+
hasAppRouter: hasAppDir,
|
|
30
|
+
srcDir,
|
|
31
|
+
packageCount: Object.keys(deps).length,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (deps['vite'] && (deps['react'] || deps['vue'])) {
|
|
35
|
+
return {
|
|
36
|
+
framework: 'vite-react',
|
|
37
|
+
language: fs.existsSync(path.join(rootDir, 'tsconfig.json')) ? 'TypeScript' : 'JavaScript',
|
|
38
|
+
hasAppRouter: false,
|
|
39
|
+
srcDir: 'src',
|
|
40
|
+
packageCount: Object.keys(deps).length,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (deps['@nestjs/core']) {
|
|
44
|
+
return {
|
|
45
|
+
framework: 'nestjs',
|
|
46
|
+
language: fs.existsSync(path.join(rootDir, 'tsconfig.json')) ? 'TypeScript' : 'JavaScript',
|
|
47
|
+
hasAppRouter: false,
|
|
48
|
+
srcDir: 'src',
|
|
49
|
+
packageCount: Object.keys(deps).length,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (fs.existsSync(pyprojectPath)) {
|
|
54
|
+
const content = fs.readFileSync(pyprojectPath, 'utf-8');
|
|
55
|
+
const framework = content.includes('fastapi') ? 'fastapi' : 'django';
|
|
56
|
+
return {
|
|
57
|
+
framework,
|
|
58
|
+
language: 'Python',
|
|
59
|
+
hasAppRouter: false,
|
|
60
|
+
srcDir: '.',
|
|
61
|
+
packageCount: 0,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
framework: 'unknown',
|
|
66
|
+
language: fs.existsSync(path.join(rootDir, 'tsconfig.json')) ? 'TypeScript' : 'JavaScript',
|
|
67
|
+
hasAppRouter: false,
|
|
68
|
+
srcDir: 'src',
|
|
69
|
+
packageCount: 0,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { parseCli } from './cli.js';
|
|
5
|
+
import { detectProject } from './detector.js';
|
|
6
|
+
import { extractRoutes } from './scanner/routes.js';
|
|
7
|
+
import { extractComponents } from './scanner/components.js';
|
|
8
|
+
import { extractApiCalls } from './scanner/api-calls.js';
|
|
9
|
+
import { extractNavigation } from './scanner/navigation.js';
|
|
10
|
+
import { buildBriefing } from './scanner/briefing.js';
|
|
11
|
+
import { buildWidgetSnippet } from './scanner/widget-snippet.js';
|
|
12
|
+
import { buildReport, maskReportSecrets, CLI_VERSION } from './reporter.js';
|
|
13
|
+
import { uploadReport, pollStatus } from './uploader.js';
|
|
14
|
+
import { banner, spinner, printSummary, fail } from './ui.js';
|
|
15
|
+
import { DEFAULT_IGNORE_PATTERNS } from './scanner/ignore.js';
|
|
16
|
+
async function main() {
|
|
17
|
+
const opts = parseCli();
|
|
18
|
+
const rootDir = path.resolve(opts.dir);
|
|
19
|
+
console.log(banner(CLI_VERSION));
|
|
20
|
+
console.log(chalk.dim(` Diretório: ${rootDir}`));
|
|
21
|
+
console.log(chalk.dim(` Plataforma: ${opts.url}\n`));
|
|
22
|
+
const ignorePatterns = [...DEFAULT_IGNORE_PATTERNS, ...opts.ignore];
|
|
23
|
+
// 1. Detectar framework
|
|
24
|
+
const detectSpinner = spinner('Detectando projeto...');
|
|
25
|
+
const signature = detectProject(rootDir);
|
|
26
|
+
detectSpinner.succeed(`Framework detectado: ${chalk.cyan(signature.framework)} (${signature.language})`);
|
|
27
|
+
// 2. Extrair rotas (necessárias para mapear page.tsx -> rota lógica)
|
|
28
|
+
const routeSpinner = spinner('Extraindo rotas...');
|
|
29
|
+
const routes = await extractRoutes(rootDir, signature.srcDir, ignorePatterns);
|
|
30
|
+
routeSpinner.succeed(`${routes.length} rotas encontradas`);
|
|
31
|
+
// 3. Extrair componentes e eventos (inventário)
|
|
32
|
+
const compSpinner = spinner('Extraindo componentes e eventos...');
|
|
33
|
+
const { components, events } = await extractComponents(rootDir, opts.ignore);
|
|
34
|
+
compSpinner.succeed(`${components.length} componentes, ${events.length} eventos`);
|
|
35
|
+
// 4. Extrair chamadas de API
|
|
36
|
+
const apiSpinner = spinner('Extraindo chamadas de API...');
|
|
37
|
+
const apiCalls = await extractApiCalls(rootDir, opts.ignore);
|
|
38
|
+
apiSpinner.succeed(`${apiCalls.length} chamadas de API detectadas`);
|
|
39
|
+
// 5. Extrair mapa de navegação (telas, botões, links, inputs) — núcleo do produto
|
|
40
|
+
const navSpinner = spinner('Construindo mapa de navegação...');
|
|
41
|
+
const navigationMap = await extractNavigation(rootDir, opts.ignore, {
|
|
42
|
+
pagesRoutes: routes.map((r) => ({ physicalPath: r.physicalPath, logicalRoute: r.logicalRoute })),
|
|
43
|
+
srcDir: signature.srcDir,
|
|
44
|
+
});
|
|
45
|
+
const totalActions = navigationMap.screens.reduce((acc, s) => acc + s.actions.length, 0);
|
|
46
|
+
navSpinner.succeed(`${navigationMap.screens.length} telas mapeadas, ${totalActions} ações, ${navigationMap.navigationGraph.length} arestas de navegação`);
|
|
47
|
+
// 6. Gerar briefing em linguagem natural + snippet do widget
|
|
48
|
+
const briefing = buildBriefing(navigationMap);
|
|
49
|
+
const widgetSnippet = buildWidgetSnippet();
|
|
50
|
+
// 7. Contagem fiel de arquivos físicos lidos
|
|
51
|
+
const uniqueFiles = new Set([
|
|
52
|
+
...routes.map((r) => r.physicalPath),
|
|
53
|
+
...components.map((c) => c.filepath),
|
|
54
|
+
...apiCalls.map((a) => a.filepath),
|
|
55
|
+
...navigationMap.screens.map((s) => s.filePath),
|
|
56
|
+
]);
|
|
57
|
+
const filesScanned = uniqueFiles.size;
|
|
58
|
+
// 8. Montar payload e mascarar secrets
|
|
59
|
+
const projectName = path.basename(rootDir);
|
|
60
|
+
const rawReport = buildReport({
|
|
61
|
+
signature,
|
|
62
|
+
routes,
|
|
63
|
+
components,
|
|
64
|
+
events,
|
|
65
|
+
apiCalls,
|
|
66
|
+
navigationMap,
|
|
67
|
+
widgetSnippet,
|
|
68
|
+
briefing,
|
|
69
|
+
filesScanned,
|
|
70
|
+
projectName,
|
|
71
|
+
});
|
|
72
|
+
const { report, secretsFound } = maskReportSecrets(rawReport);
|
|
73
|
+
if (secretsFound > 0) {
|
|
74
|
+
console.log(chalk.yellow(`⚠ ${secretsFound} possível(eis) secret(s) mascarado(s) antes do envio.`));
|
|
75
|
+
}
|
|
76
|
+
if (opts.verbose) {
|
|
77
|
+
console.log('\n' + chalk.dim('Briefing (resumo para IA):'));
|
|
78
|
+
console.log(chalk.dim(briefing));
|
|
79
|
+
console.log('\n' + chalk.dim('Navigation Map:'));
|
|
80
|
+
console.log(chalk.dim(JSON.stringify(report.navigationMap, null, 2)));
|
|
81
|
+
}
|
|
82
|
+
if (opts.dryRun) {
|
|
83
|
+
console.log(chalk.bold.cyan('\n🏃 Modo dry-run: pulando envio para a plataforma.\n'));
|
|
84
|
+
console.log(` Arquivos escaneados: ${chalk.bold(filesScanned)}`);
|
|
85
|
+
console.log(` Telas mapeadas: ${chalk.bold(navigationMap.screens.length)}`);
|
|
86
|
+
console.log(` Ações (botões/inputs): ${chalk.bold(totalActions)}`);
|
|
87
|
+
console.log(` Arestas de navegação: ${chalk.bold(navigationMap.navigationGraph.length)}`);
|
|
88
|
+
console.log(` Rotas: ${chalk.bold(routes.length)}`);
|
|
89
|
+
console.log(` Componentes: ${chalk.bold(components.length)}`);
|
|
90
|
+
console.log(` Eventos: ${chalk.bold(events.length)}`);
|
|
91
|
+
console.log(` Chamadas de API: ${chalk.bold(apiCalls.length)}`);
|
|
92
|
+
console.log(` Secrets mascarados: ${chalk.bold(secretsFound)}\n`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// 9. Enviar para a plataforma
|
|
96
|
+
const uploadSpinner = spinner('Enviando para a plataforma Skip...');
|
|
97
|
+
const scanId = await uploadReport(report, opts.token, opts.url);
|
|
98
|
+
uploadSpinner.succeed(`Scan enviado! ID: ${chalk.yellow(scanId)}`);
|
|
99
|
+
// 10. Aguardar enriquecimento com IA
|
|
100
|
+
const status = await pollStatus(scanId, opts.token, opts.url);
|
|
101
|
+
printSummary({
|
|
102
|
+
scanId,
|
|
103
|
+
entitiesCount: status.entitiesCount,
|
|
104
|
+
baseUrl: opts.url,
|
|
105
|
+
status: status.status,
|
|
106
|
+
});
|
|
107
|
+
if (status.status !== 'COMPLETED')
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
}
|
|
110
|
+
main().catch((err) => {
|
|
111
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
112
|
+
console.error(fail(`Erro: ${msg}\n`));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ProjectSignature } from './detector.js';
|
|
2
|
+
import type { RouteEntry } from './scanner/routes.js';
|
|
3
|
+
import type { ComponentEntry, EventEntry } from './scanner/components.js';
|
|
4
|
+
import type { ApiCallEntry } from './scanner/api-calls.js';
|
|
5
|
+
import type { NavigationMap } from './scanner/navigation.js';
|
|
6
|
+
export declare const CLI_VERSION = "0.2.0";
|
|
7
|
+
export interface ScanMetadata {
|
|
8
|
+
framework: string;
|
|
9
|
+
language: string;
|
|
10
|
+
packageCount: number;
|
|
11
|
+
typescript: boolean;
|
|
12
|
+
scannedAt: string;
|
|
13
|
+
cliVersion: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ScanReport {
|
|
16
|
+
projectName: string;
|
|
17
|
+
filesScanned: number;
|
|
18
|
+
routes: RouteEntry[];
|
|
19
|
+
components: ComponentEntry[];
|
|
20
|
+
events: EventEntry[];
|
|
21
|
+
apiCalls: ApiCallEntry[];
|
|
22
|
+
/** Mapa de navegação agrupado por tela — principal insumo para a IA e o widget. */
|
|
23
|
+
navigationMap: NavigationMap;
|
|
24
|
+
/** Snippet JS que o widget carrega em runtime para auto-injetar data-skip-anchor. */
|
|
25
|
+
widgetSnippet: string;
|
|
26
|
+
/** Resumo em linguagem natural das telas e ações (pronto para a IA ler). */
|
|
27
|
+
briefing: string;
|
|
28
|
+
secretsFound: number;
|
|
29
|
+
metadata: ScanMetadata;
|
|
30
|
+
}
|
|
31
|
+
export interface BuildReportInput {
|
|
32
|
+
signature: ProjectSignature;
|
|
33
|
+
routes: RouteEntry[];
|
|
34
|
+
components: ComponentEntry[];
|
|
35
|
+
events: EventEntry[];
|
|
36
|
+
apiCalls: ApiCallEntry[];
|
|
37
|
+
navigationMap: NavigationMap;
|
|
38
|
+
widgetSnippet: string;
|
|
39
|
+
briefing: string;
|
|
40
|
+
filesScanned: number;
|
|
41
|
+
projectName: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Monta o payload final (ScanReport) enviado para a API.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildReport(input: BuildReportInput): ScanReport;
|
|
47
|
+
/**
|
|
48
|
+
* Aplica mascaramento de secrets ao relatório antes do envio.
|
|
49
|
+
* Retorna um novo relatório (com `secretsFound` preenchido) e a contagem.
|
|
50
|
+
*/
|
|
51
|
+
export declare function maskReportSecrets(report: ScanReport): {
|
|
52
|
+
report: ScanReport;
|
|
53
|
+
secretsFound: number;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,eAAO,MAAM,WAAW,UAAU,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,mFAAmF;IACnF,aAAa,EAAE,aAAa,CAAC;IAC7B,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,UAAU,CAwB/D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAGlG"}
|
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { maskObject } from './scanner/secrets.js';
|
|
2
|
+
export const CLI_VERSION = '0.2.0';
|
|
3
|
+
/**
|
|
4
|
+
* Monta o payload final (ScanReport) enviado para a API.
|
|
5
|
+
*/
|
|
6
|
+
export function buildReport(input) {
|
|
7
|
+
const { signature, routes, components, events, apiCalls, navigationMap, widgetSnippet, briefing, filesScanned, projectName } = input;
|
|
8
|
+
const report = {
|
|
9
|
+
projectName,
|
|
10
|
+
filesScanned,
|
|
11
|
+
routes,
|
|
12
|
+
components,
|
|
13
|
+
events,
|
|
14
|
+
apiCalls,
|
|
15
|
+
navigationMap,
|
|
16
|
+
widgetSnippet,
|
|
17
|
+
briefing,
|
|
18
|
+
secretsFound: 0,
|
|
19
|
+
metadata: {
|
|
20
|
+
framework: signature.framework,
|
|
21
|
+
language: signature.language,
|
|
22
|
+
packageCount: signature.packageCount,
|
|
23
|
+
typescript: signature.language === 'TypeScript',
|
|
24
|
+
scannedAt: new Date().toISOString(),
|
|
25
|
+
cliVersion: CLI_VERSION,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
return report;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Aplica mascaramento de secrets ao relatório antes do envio.
|
|
32
|
+
* Retorna um novo relatório (com `secretsFound` preenchido) e a contagem.
|
|
33
|
+
*/
|
|
34
|
+
export function maskReportSecrets(report) {
|
|
35
|
+
const { result, count } = maskObject(report);
|
|
36
|
+
return { report: { ...result, secretsFound: count }, secretsFound: count };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAyCnC;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAErI,MAAM,MAAM,GAAe;QACzB,WAAW;QACX,YAAY;QACZ,MAAM;QACN,UAAU;QACV,MAAM;QACN,QAAQ;QACR,aAAa;QACb,aAAa;QACb,QAAQ;QACR,YAAY,EAAE,CAAC;QACf,QAAQ,EAAE;YACR,SAAS,EAAE,SAAS,CAAC,SAAS;YAC9B,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,UAAU,EAAE,SAAS,CAAC,QAAQ,KAAK,YAAY;YAC/C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,UAAU,EAAE,WAAW;SACxB;KACF,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IAClD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ApiCallEntry {
|
|
2
|
+
method: string;
|
|
3
|
+
endpoint: string;
|
|
4
|
+
filepath: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Extrai chamadas de API (fetch / axios) dentro do projeto.
|
|
8
|
+
* Captura endpoints internos (/api/...) e externos (http/https).
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractApiCalls(rootDir: string, ignorePatterns?: string[]): Promise<ApiCallEntry[]>;
|
|
11
|
+
//# sourceMappingURL=api-calls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-calls.d.ts","sourceRoot":"","sources":["../../src/scanner/api-calls.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAAO,GAC5B,OAAO,CAAC,YAAY,EAAE,CAAC,CA0CzB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { DEFAULT_IGNORE_PATTERNS, toRelative } from './ignore.js';
|
|
4
|
+
/**
|
|
5
|
+
* Extrai chamadas de API (fetch / axios) dentro do projeto.
|
|
6
|
+
* Captura endpoints internos (/api/...) e externos (http/https).
|
|
7
|
+
*/
|
|
8
|
+
export async function extractApiCalls(rootDir, ignorePatterns = []) {
|
|
9
|
+
const files = await glob('src/**/*.{ts,tsx,js,jsx}', {
|
|
10
|
+
cwd: rootDir,
|
|
11
|
+
absolute: true,
|
|
12
|
+
ignore: [...DEFAULT_IGNORE_PATTERNS, ...ignorePatterns],
|
|
13
|
+
});
|
|
14
|
+
const calls = [];
|
|
15
|
+
for (const file of files) {
|
|
16
|
+
let content;
|
|
17
|
+
try {
|
|
18
|
+
content = fs.readFileSync(file, 'utf-8');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const relative = toRelative(rootDir, file);
|
|
24
|
+
// Padrão 1: fetch('/api/...', { method: 'POST' })
|
|
25
|
+
const fetchMatches = [
|
|
26
|
+
...content.matchAll(/fetch\s*\(\s*['"`]([^'"`]+)['"`]\s*(?:,\s*\{[^}]*?method\s*:\s*['"`](\w+)['"`][^}]*?\})?/gs),
|
|
27
|
+
];
|
|
28
|
+
for (const m of fetchMatches) {
|
|
29
|
+
const endpoint = m[1];
|
|
30
|
+
const method = m[2]?.toUpperCase() ?? 'GET';
|
|
31
|
+
if (endpoint.startsWith('/api') || endpoint.startsWith('http')) {
|
|
32
|
+
calls.push({ method, endpoint, filepath: relative });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Padrão 2: axios.post('/api/...') — também cobre instâncias nomeadas (api.get, http.post)
|
|
36
|
+
const axiosMatches = [
|
|
37
|
+
...content.matchAll(/(?:axios|(?:api|http|client|request))\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]/g),
|
|
38
|
+
];
|
|
39
|
+
for (const m of axiosMatches) {
|
|
40
|
+
calls.push({ method: m[1].toUpperCase(), endpoint: m[2], filepath: relative });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return calls;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=api-calls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-calls.js","sourceRoot":"","sources":["../../src/scanner/api-calls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQlE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAe,EACf,iBAA2B,EAAE;IAE7B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,0BAA0B,EAAE;QACnD,GAAG,EAAE,OAAO;QACZ,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,CAAC,GAAG,uBAAuB,EAAE,GAAG,cAAc,CAAC;KACxD,CAAC,CAAC;IAEH,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAE3C,kDAAkD;QAClD,MAAM,YAAY,GAAG;YACnB,GAAG,OAAO,CAAC,QAAQ,CACjB,4FAA4F,CAC7F;SACF,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,KAAK,CAAC;YAC5C,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAED,2FAA2F;QAC3F,MAAM,YAAY,GAAG;YACnB,GAAG,OAAO,CAAC,QAAQ,CAAC,gGAAgG,CAAC;SACtH,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NavigationMap } from './navigation.js';
|
|
2
|
+
/**
|
|
3
|
+
* Gera um briefing em linguagem natural do mapa de navegação,
|
|
4
|
+
* uma linha por tela. Pronto para a IA ler e entender sem parsing.
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildBriefing(map: NavigationMap): string;
|
|
7
|
+
//# sourceMappingURL=briefing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"briefing.d.ts","sourceRoot":"","sources":["../../src/scanner/briefing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,iBAAiB,CAAC;AAiBvE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAwCxD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Descreve uma ação em linguagem natural curta. */
|
|
2
|
+
function describeAction(a) {
|
|
3
|
+
switch (a.kind) {
|
|
4
|
+
case 'fill':
|
|
5
|
+
return `input '${a.label}' (${a.inputType ?? 'text'}${a.inputName ? `, name=${a.inputName}` : ''})`;
|
|
6
|
+
case 'navigation':
|
|
7
|
+
return `link '${a.label}' navega para ${a.targetRoute ?? '?'}`;
|
|
8
|
+
case 'submit':
|
|
9
|
+
return `botão '${a.label}' (submit)`;
|
|
10
|
+
case 'click':
|
|
11
|
+
default:
|
|
12
|
+
return `botão '${a.label}'`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Gera um briefing em linguagem natural do mapa de navegação,
|
|
17
|
+
* uma linha por tela. Pronto para a IA ler e entender sem parsing.
|
|
18
|
+
*/
|
|
19
|
+
export function buildBriefing(map) {
|
|
20
|
+
if (map.screens.length === 0) {
|
|
21
|
+
return 'Nenhuma tela foi mapeada neste projeto.';
|
|
22
|
+
}
|
|
23
|
+
const lines = [];
|
|
24
|
+
// Cabeçalho com a visão geral de telas
|
|
25
|
+
const rotaTitulos = map.screens.map((s) => `'${s.title}' (${s.route})`).join(', ');
|
|
26
|
+
lines.push(`Projeto com ${map.screens.length} tela(s): ${rotaTitulos}.`);
|
|
27
|
+
lines.push('');
|
|
28
|
+
// Uma linha por tela descrevendo suas ações
|
|
29
|
+
for (const screen of map.screens) {
|
|
30
|
+
const parts = [];
|
|
31
|
+
for (const a of screen.actions) {
|
|
32
|
+
parts.push(describeAction(a));
|
|
33
|
+
}
|
|
34
|
+
// Navegação global disponível nesta tela
|
|
35
|
+
for (const g of screen.globalActions) {
|
|
36
|
+
parts.push(`menu '${g.label}' navega para ${g.targetRoute}`);
|
|
37
|
+
}
|
|
38
|
+
const acoesTxt = parts.length > 0 ? parts.join('; ') : 'sem ações mapeadas';
|
|
39
|
+
lines.push(`Tela ${screen.title} (${screen.route}): ${acoesTxt}.`);
|
|
40
|
+
}
|
|
41
|
+
// Avisos de baixa confidence (úteis para o dev corrigir)
|
|
42
|
+
const warnings = map.screens.flatMap((s) => s.actions.filter((a) => a.confidence === 'low' && a.warning).map((a) => `- ${s.route}: ${a.warning}`));
|
|
43
|
+
if (warnings.length > 0) {
|
|
44
|
+
lines.push('');
|
|
45
|
+
lines.push('Avisos de confiabilidade:');
|
|
46
|
+
lines.push(...warnings);
|
|
47
|
+
}
|
|
48
|
+
return lines.join('\n');
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=briefing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"briefing.js","sourceRoot":"","sources":["../../src/scanner/briefing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ComponentEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
filepath: string;
|
|
4
|
+
props: string[];
|
|
5
|
+
events: string[];
|
|
6
|
+
hasForm: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface EventEntry {
|
|
9
|
+
type: string;
|
|
10
|
+
handler: string;
|
|
11
|
+
filepath: string;
|
|
12
|
+
elementTag: string;
|
|
13
|
+
elementId: string | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extrai componentes React (TSX/JSX) com suas props e eventos,
|
|
17
|
+
* além dos eventos DOM vinculados a handlers no código.
|
|
18
|
+
* Inclui também layouts e componentes compartilhados (sidebar, navbar...).
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractComponents(rootDir: string, ignorePatterns?: string[]): Promise<{
|
|
21
|
+
components: ComponentEntry[];
|
|
22
|
+
events: EventEntry[];
|
|
23
|
+
}>;
|
|
24
|
+
//# sourceMappingURL=components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/scanner/components.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAAO,GAC5B,OAAO,CAAC;IAAE,UAAU,EAAE,cAAc,EAAE,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC,CAuEjE"}
|