@skip-ai/scanner 0.2.0 → 0.4.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/dist/cli.d.ts +12 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +32 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.js +150 -46
- package/dist/index.js.map +1 -1
- package/dist/reporter.d.ts +13 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +5 -2
- package/dist/reporter.js.map +1 -1
- package/dist/scanner/guided-flows.d.ts +23 -0
- package/dist/scanner/guided-flows.d.ts.map +1 -0
- package/dist/scanner/guided-flows.js +61 -0
- package/dist/scanner/guided-flows.js.map +1 -0
- package/dist/scanner/history.d.ts +22 -0
- package/dist/scanner/history.d.ts.map +1 -0
- package/dist/scanner/history.js +38 -0
- package/dist/scanner/history.js.map +1 -0
- package/dist/scanner/score.d.ts +19 -0
- package/dist/scanner/score.d.ts.map +1 -0
- package/dist/scanner/score.js +52 -0
- package/dist/scanner/score.js.map +1 -0
- package/dist/scanner/wcag.d.ts +58 -0
- package/dist/scanner/wcag.d.ts.map +1 -0
- package/dist/scanner/wcag.js +392 -0
- package/dist/scanner/wcag.js.map +1 -0
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface SendOptions {
|
|
2
|
+
file: string;
|
|
3
|
+
token: string;
|
|
4
|
+
url: string;
|
|
5
|
+
verbose: boolean;
|
|
6
|
+
noPolling: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ScanOptions {
|
|
2
9
|
token?: string;
|
|
3
10
|
url: string;
|
|
4
11
|
dir: string;
|
|
@@ -7,5 +14,8 @@ export interface CliOptions {
|
|
|
7
14
|
dryRun: boolean;
|
|
8
15
|
}
|
|
9
16
|
export declare const DEFAULT_BASE_URL = "https://app.goskip.dev";
|
|
10
|
-
export declare function parseCli(argv?: string[]):
|
|
17
|
+
export declare function parseCli(argv?: string[]): {
|
|
18
|
+
command: 'send' | 'scan';
|
|
19
|
+
opts: SendOptions | ScanOptions;
|
|
20
|
+
};
|
|
11
21
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,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;IAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAA;CAAE,CAgDrH"}
|
package/dist/cli.js
CHANGED
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { CLI_VERSION } from './reporter.js';
|
|
2
3
|
export const DEFAULT_BASE_URL = 'https://app.goskip.dev';
|
|
3
4
|
export function parseCli(argv = process.argv) {
|
|
4
5
|
const program = new Command()
|
|
5
6
|
.name('skip-scanner')
|
|
6
|
-
.description('Scanner
|
|
7
|
-
.
|
|
8
|
-
|
|
7
|
+
.description('Scanner CLI para a plataforma Skip AI Accessibility Layer')
|
|
8
|
+
.version(CLI_VERSION);
|
|
9
|
+
// Comando principal: send (transporta um mapa já montado pelo agente)
|
|
10
|
+
program
|
|
11
|
+
.command('send', { isDefault: true })
|
|
12
|
+
.description('Envia um payload já montado (pelo agente/skill) para o Skip Cloud. Este é o modo recomendado.')
|
|
13
|
+
.requiredOption('-f, --file <path>', 'Arquivo JSON com o payload (gerado pelo agente)')
|
|
14
|
+
.requiredOption('-t, --token <token>', 'Token do projeto (do .skip.json ou dashboard)')
|
|
15
|
+
.option('-u, --url <url>', 'URL do Skip Cloud', DEFAULT_BASE_URL)
|
|
16
|
+
.option('--no-polling', 'Enviar sem aguardar o enriquecimento', false)
|
|
17
|
+
.option('-v, --verbose', 'Exibir detalhes no terminal', false)
|
|
18
|
+
.action(() => { });
|
|
19
|
+
// Comando legado: scan (extração por regex — mantido como fallback)
|
|
20
|
+
program
|
|
21
|
+
.command('scan')
|
|
22
|
+
.description('Modo legado: extrai rotas/componentes via regex e envia. Menos inteligente que o agente.')
|
|
23
|
+
.option('-t, --token <token>', 'Token do projeto. Obrigatório salvo em --dry-run.')
|
|
24
|
+
.option('-u, --url <url>', 'URL do Skip Cloud', DEFAULT_BASE_URL)
|
|
9
25
|
.option('-d, --dir <dir>', 'Diretório raiz do projeto', process.cwd())
|
|
10
26
|
.option('-i, --ignore <patterns...>', 'Padrões a ignorar além do padrão', [])
|
|
11
27
|
.option('--dry-run', 'Executa o scan sem enviar para a plataforma', false)
|
|
12
28
|
.option('-v, --verbose', 'Exibir detalhes do scan no terminal', false)
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
29
|
+
.action(() => { });
|
|
30
|
+
program.parse(argv);
|
|
31
|
+
const [cmd] = program.commands.filter((c) => c.name() === program.args[0] || program.args.length === 0);
|
|
32
|
+
const commandName = program.args[0] === 'scan' ? 'scan' : 'send';
|
|
33
|
+
const command = program.commands.find((c) => c.name() === commandName);
|
|
34
|
+
const opts = (command?.opts() ?? {});
|
|
35
|
+
// Validação específica do modo scan: token obrigatório fora do dry-run
|
|
36
|
+
if (commandName === 'scan') {
|
|
37
|
+
const scanOpts = opts;
|
|
38
|
+
if (!scanOpts.dryRun && !scanOpts.token) {
|
|
39
|
+
program.error("erro: a opção '-t, --token <token>' é obrigatória (ou use --dry-run para testar sem enviar).", { exitCode: 1 });
|
|
40
|
+
}
|
|
18
41
|
}
|
|
19
|
-
return opts;
|
|
42
|
+
return { command: commandName, opts };
|
|
20
43
|
}
|
|
21
44
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAmB5C,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,2DAA2D,CAAC;SACxE,OAAO,CAAC,WAAW,CAAC,CAAC;IAExB,sEAAsE;IACtE,OAAO;SACJ,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACpC,WAAW,CAAC,+FAA+F,CAAC;SAC5G,cAAc,CAAC,mBAAmB,EAAE,iDAAiD,CAAC;SACtF,cAAc,CAAC,qBAAqB,EAAE,+CAA+C,CAAC;SACtF,MAAM,CAAC,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,CAAC;SAChE,MAAM,CAAC,cAAc,EAAE,sCAAsC,EAAE,KAAK,CAAC;SACrE,MAAM,CAAC,eAAe,EAAE,6BAA6B,EAAE,KAAK,CAAC;SAC7D,MAAM,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEpB,oEAAoE;IACpE,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,0FAA0F,CAAC;SACvG,MAAM,CAAC,qBAAqB,EAAE,mDAAmD,CAAC;SAClF,MAAM,CAAC,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,CAAC;SAChE,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,MAAM,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEpB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpB,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IACxG,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAA8B,CAAC;IAElE,uEAAuE;IACvE,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAmB,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACxC,OAAO,CAAC,KAAK,CACX,8FAA8F,EAC9F,EAAE,QAAQ,EAAE,CAAC,EAAE,CAChB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
import { parseCli } from './cli.js';
|
|
6
|
+
import { maskObject } from './scanner/secrets.js';
|
|
7
|
+
import { uploadReport, pollStatus } from './uploader.js';
|
|
8
|
+
import { banner, spinner, printSummary, fail } from './ui.js';
|
|
9
|
+
// Modo legado de extração
|
|
5
10
|
import { detectProject } from './detector.js';
|
|
6
11
|
import { extractRoutes } from './scanner/routes.js';
|
|
7
12
|
import { extractComponents } from './scanner/components.js';
|
|
@@ -9,34 +14,103 @@ import { extractApiCalls } from './scanner/api-calls.js';
|
|
|
9
14
|
import { extractNavigation } from './scanner/navigation.js';
|
|
10
15
|
import { buildBriefing } from './scanner/briefing.js';
|
|
11
16
|
import { buildWidgetSnippet } from './scanner/widget-snippet.js';
|
|
17
|
+
import { auditWcag, summarize, WCAG_RULES_VERSION } from './scanner/wcag.js';
|
|
18
|
+
import { calculateScore, scoreColor } from './scanner/score.js';
|
|
19
|
+
/** Aplica cor do chalk conforme o score (necessário porque chalk não é indexável por string). */
|
|
20
|
+
function colorScore(score) {
|
|
21
|
+
const c = scoreColor(score);
|
|
22
|
+
if (c === 'green')
|
|
23
|
+
return chalk.bold.green(`${score}/100`);
|
|
24
|
+
if (c === 'yellow')
|
|
25
|
+
return chalk.bold.yellow(`${score}/100`);
|
|
26
|
+
if (c === 'magenta')
|
|
27
|
+
return chalk.bold.magenta(`${score}/100`);
|
|
28
|
+
return chalk.bold.red(`${score}/100`);
|
|
29
|
+
}
|
|
30
|
+
import { detectGuidedFlows } from './scanner/guided-flows.js';
|
|
31
|
+
import { appendHistory } from './scanner/history.js';
|
|
12
32
|
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
33
|
import { DEFAULT_IGNORE_PATTERNS } from './scanner/ignore.js';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const rootDir = path.resolve(opts.dir);
|
|
34
|
+
// ============ MODO SEND (transportador puro) ============
|
|
35
|
+
async function sendMode(opts) {
|
|
19
36
|
console.log(banner(CLI_VERSION));
|
|
37
|
+
console.log(chalk.dim(` Modo: send (transportador)`));
|
|
38
|
+
console.log(chalk.dim(` Plataforma: ${opts.url}`));
|
|
39
|
+
console.log(chalk.dim(` Arquivo: ${opts.file}\n`));
|
|
40
|
+
// 1. Ler o payload do arquivo
|
|
41
|
+
if (!fs.existsSync(opts.file)) {
|
|
42
|
+
throw new Error(`Arquivo não encontrado: ${opts.file}`);
|
|
43
|
+
}
|
|
44
|
+
const readSpinner = spinner('Lendo payload...');
|
|
45
|
+
let payload;
|
|
46
|
+
try {
|
|
47
|
+
payload = JSON.parse(fs.readFileSync(opts.file, 'utf-8'));
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
readSpinner.fail();
|
|
51
|
+
throw new Error(`JSON inválido em ${opts.file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
52
|
+
}
|
|
53
|
+
readSpinner.succeed('Payload carregado.');
|
|
54
|
+
// 2. Checagem mínima de estrutura
|
|
55
|
+
if (!payload.navigationMap && !payload.routes) {
|
|
56
|
+
throw new Error('O payload não contém navigationMap nem routes. Use o validador da skill antes de enviar: node validate-report.js <arquivo>');
|
|
57
|
+
}
|
|
58
|
+
// 3. Preencher metadados se faltarem
|
|
59
|
+
if (!payload.metadata) {
|
|
60
|
+
payload.metadata = {
|
|
61
|
+
framework: payload.framework ?? 'unknown',
|
|
62
|
+
language: payload.language ?? 'TypeScript',
|
|
63
|
+
packageCount: 0,
|
|
64
|
+
typescript: payload.language === 'TypeScript',
|
|
65
|
+
scannedAt: new Date().toISOString(),
|
|
66
|
+
cliVersion: CLI_VERSION,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// 4. Mascara secrets
|
|
70
|
+
const { result: masked, count: secretsFound } = maskObject(payload);
|
|
71
|
+
const report = { ...masked, secretsFound };
|
|
72
|
+
if (secretsFound > 0) {
|
|
73
|
+
console.log(chalk.yellow(`⚠ ${secretsFound} possível(eis) secret(s) mascarado(s) antes do envio.`));
|
|
74
|
+
}
|
|
75
|
+
if (opts.verbose) {
|
|
76
|
+
console.log('\n' + chalk.dim('Payload a enviar:'));
|
|
77
|
+
console.log(chalk.dim(JSON.stringify(report, null, 2).slice(0, 2000) + (JSON.stringify(report).length > 2000 ? '...' : '')));
|
|
78
|
+
}
|
|
79
|
+
// 5. Enviar
|
|
80
|
+
const uploadSpinner = spinner('Enviando para o Skip Cloud...');
|
|
81
|
+
const scanId = await uploadReport(report, opts.token, opts.url);
|
|
82
|
+
uploadSpinner.succeed(`Scan enviado! ID: ${chalk.yellow(scanId)}`);
|
|
83
|
+
// 6. Polling (opcional)
|
|
84
|
+
if (opts.noPolling) {
|
|
85
|
+
console.log(chalk.dim('\n--no-polling: não aguardando enriquecimento.\n'));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const status = await pollStatus(scanId, opts.token, opts.url);
|
|
89
|
+
printSummary({ scanId, entitiesCount: status.entitiesCount, baseUrl: opts.url, status: status.status });
|
|
90
|
+
if (status.status !== 'COMPLETED')
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
}
|
|
93
|
+
// ============ MODO SCAN (legado, extração por regex) ============
|
|
94
|
+
async function scanMode(opts) {
|
|
95
|
+
console.log(banner(CLI_VERSION));
|
|
96
|
+
console.log(chalk.dim(` Modo: scan (legado, regex)`));
|
|
97
|
+
const rootDir = path.resolve(opts.dir);
|
|
20
98
|
console.log(chalk.dim(` Diretório: ${rootDir}`));
|
|
21
99
|
console.log(chalk.dim(` Plataforma: ${opts.url}\n`));
|
|
100
|
+
console.log(chalk.yellow(' ⚠ Modo scan usa extração por regex (menos inteligente que o agente).\n'));
|
|
22
101
|
const ignorePatterns = [...DEFAULT_IGNORE_PATTERNS, ...opts.ignore];
|
|
23
|
-
// 1. Detectar framework
|
|
24
102
|
const detectSpinner = spinner('Detectando projeto...');
|
|
25
103
|
const signature = detectProject(rootDir);
|
|
26
104
|
detectSpinner.succeed(`Framework detectado: ${chalk.cyan(signature.framework)} (${signature.language})`);
|
|
27
|
-
// 2. Extrair rotas (necessárias para mapear page.tsx -> rota lógica)
|
|
28
105
|
const routeSpinner = spinner('Extraindo rotas...');
|
|
29
106
|
const routes = await extractRoutes(rootDir, signature.srcDir, ignorePatterns);
|
|
30
107
|
routeSpinner.succeed(`${routes.length} rotas encontradas`);
|
|
31
|
-
// 3. Extrair componentes e eventos (inventário)
|
|
32
108
|
const compSpinner = spinner('Extraindo componentes e eventos...');
|
|
33
109
|
const { components, events } = await extractComponents(rootDir, opts.ignore);
|
|
34
110
|
compSpinner.succeed(`${components.length} componentes, ${events.length} eventos`);
|
|
35
|
-
// 4. Extrair chamadas de API
|
|
36
111
|
const apiSpinner = spinner('Extraindo chamadas de API...');
|
|
37
112
|
const apiCalls = await extractApiCalls(rootDir, opts.ignore);
|
|
38
113
|
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
114
|
const navSpinner = spinner('Construindo mapa de navegação...');
|
|
41
115
|
const navigationMap = await extractNavigation(rootDir, opts.ignore, {
|
|
42
116
|
pagesRoutes: routes.map((r) => ({ physicalPath: r.physicalPath, logicalRoute: r.logicalRoute })),
|
|
@@ -44,69 +118,99 @@ async function main() {
|
|
|
44
118
|
});
|
|
45
119
|
const totalActions = navigationMap.screens.reduce((acc, s) => acc + s.actions.length, 0);
|
|
46
120
|
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
121
|
const briefing = buildBriefing(navigationMap);
|
|
49
122
|
const widgetSnippet = buildWidgetSnippet();
|
|
50
|
-
//
|
|
123
|
+
// ---- Auditoria WCAG ----
|
|
124
|
+
// Lê os arquivos das telas LOCALMENTE (não envia o conteúdo ao servidor).
|
|
125
|
+
const auditSpinner = spinner('Auditando WCAG...');
|
|
126
|
+
const contentsByFile = {};
|
|
127
|
+
for (const s of navigationMap.screens) {
|
|
128
|
+
const abs = path.join(rootDir, s.filePath);
|
|
129
|
+
try {
|
|
130
|
+
contentsByFile[s.filePath] = fs.readFileSync(abs, 'utf-8');
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
contentsByFile[s.filePath] = '';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const violations = auditWcag(navigationMap.screens, contentsByFile);
|
|
137
|
+
const summary = summarize(violations);
|
|
138
|
+
const { score, level, total } = calculateScore(violations);
|
|
139
|
+
const wcag = {
|
|
140
|
+
score,
|
|
141
|
+
level,
|
|
142
|
+
violations,
|
|
143
|
+
summary,
|
|
144
|
+
auditedAt: new Date().toISOString(),
|
|
145
|
+
rulesVersion: WCAG_RULES_VERSION,
|
|
146
|
+
};
|
|
147
|
+
auditSpinner.succeed(`WCAG: score ${colorScore(score)} (${level}), ${total} violação(ões) [${summary.critical}c/${summary.serious}s/${summary.moderate}m/${summary.minor}i]`);
|
|
148
|
+
// ---- Fluxos guiados ----
|
|
149
|
+
const guidedFlows = detectGuidedFlows(navigationMap);
|
|
150
|
+
// ---- Histórico (local, enviado junto pra o dashboard) ----
|
|
151
|
+
const historyEntry = {
|
|
152
|
+
scannedAt: wcag.auditedAt,
|
|
153
|
+
score,
|
|
154
|
+
violations: total,
|
|
155
|
+
critical: summary.critical,
|
|
156
|
+
serious: summary.serious,
|
|
157
|
+
moderate: summary.moderate,
|
|
158
|
+
minor: summary.minor,
|
|
159
|
+
};
|
|
160
|
+
const history = appendHistory(rootDir, historyEntry);
|
|
51
161
|
const uniqueFiles = new Set([
|
|
52
162
|
...routes.map((r) => r.physicalPath),
|
|
53
163
|
...components.map((c) => c.filepath),
|
|
54
164
|
...apiCalls.map((a) => a.filepath),
|
|
55
165
|
...navigationMap.screens.map((s) => s.filePath),
|
|
56
166
|
]);
|
|
57
|
-
const filesScanned = uniqueFiles.size;
|
|
58
|
-
// 8. Montar payload e mascarar secrets
|
|
59
167
|
const projectName = path.basename(rootDir);
|
|
60
168
|
const rawReport = buildReport({
|
|
61
|
-
signature,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
events,
|
|
65
|
-
apiCalls,
|
|
66
|
-
navigationMap,
|
|
67
|
-
widgetSnippet,
|
|
68
|
-
briefing,
|
|
69
|
-
filesScanned,
|
|
70
|
-
projectName,
|
|
169
|
+
signature, routes, components, events, apiCalls,
|
|
170
|
+
navigationMap, widgetSnippet, briefing, wcag, guidedFlows, history,
|
|
171
|
+
filesScanned: uniqueFiles.size, projectName,
|
|
71
172
|
});
|
|
72
173
|
const { report, secretsFound } = maskReportSecrets(rawReport);
|
|
73
174
|
if (secretsFound > 0) {
|
|
74
175
|
console.log(chalk.yellow(`⚠ ${secretsFound} possível(eis) secret(s) mascarado(s) antes do envio.`));
|
|
75
176
|
}
|
|
76
177
|
if (opts.verbose) {
|
|
77
|
-
console.log('\n' + chalk.dim('Briefing
|
|
178
|
+
console.log('\n' + chalk.dim('Briefing:'));
|
|
78
179
|
console.log(chalk.dim(briefing));
|
|
79
|
-
console.log('\n' + chalk.dim('
|
|
80
|
-
|
|
180
|
+
console.log('\n' + chalk.dim('Top violações WCAG:'));
|
|
181
|
+
for (const v of violations.slice(0, 8)) {
|
|
182
|
+
console.log(chalk.dim(` [${v.severity}] ${v.title} — ${v.screen} (${v.selector})`));
|
|
183
|
+
}
|
|
81
184
|
}
|
|
82
185
|
if (opts.dryRun) {
|
|
83
|
-
console.log(chalk.bold.cyan('\n🏃 Modo dry-run: pulando envio
|
|
84
|
-
console.log(`
|
|
85
|
-
console.log(`
|
|
86
|
-
console.log(`
|
|
87
|
-
console.log(`
|
|
88
|
-
console.log(`
|
|
89
|
-
console.log(`
|
|
90
|
-
console.log(`
|
|
91
|
-
console.log(` Chamadas de API: ${chalk.bold(apiCalls.length)}`);
|
|
92
|
-
console.log(` Secrets mascarados: ${chalk.bold(secretsFound)}\n`);
|
|
186
|
+
console.log(chalk.bold.cyan('\n🏃 Modo dry-run: pulando envio.\n'));
|
|
187
|
+
console.log(` Telas mapeadas: ${chalk.bold(navigationMap.screens.length)}`);
|
|
188
|
+
console.log(` Ações: ${chalk.bold(totalActions)}`);
|
|
189
|
+
console.log(` Arestas: ${chalk.bold(navigationMap.navigationGraph.length)}`);
|
|
190
|
+
console.log(` Fluxos guiados: ${chalk.bold(guidedFlows.length)}`);
|
|
191
|
+
console.log(` Score WCAG: ${colorScore(score)} (${level})`);
|
|
192
|
+
console.log(` Violações WCAG: ${chalk.bold(String(total))} [${summary.critical} critical, ${summary.serious} serious, ${summary.moderate} moderate, ${summary.minor} minor]`);
|
|
193
|
+
console.log(` Histórico: ${chalk.bold(String(history.length))} scan(s)\n`);
|
|
93
194
|
return;
|
|
94
195
|
}
|
|
95
|
-
|
|
96
|
-
const uploadSpinner = spinner('Enviando para a plataforma Skip...');
|
|
196
|
+
const uploadSpinner = spinner('Enviando para o Skip Cloud...');
|
|
97
197
|
const scanId = await uploadReport(report, opts.token, opts.url);
|
|
98
198
|
uploadSpinner.succeed(`Scan enviado! ID: ${chalk.yellow(scanId)}`);
|
|
99
|
-
// 10. Aguardar enriquecimento com IA
|
|
100
199
|
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
|
-
});
|
|
200
|
+
printSummary({ scanId, entitiesCount: status.entitiesCount, baseUrl: opts.url, status: status.status });
|
|
107
201
|
if (status.status !== 'COMPLETED')
|
|
108
202
|
process.exitCode = 1;
|
|
109
203
|
}
|
|
204
|
+
// ============ Entry point ============
|
|
205
|
+
async function main() {
|
|
206
|
+
const { command, opts } = parseCli();
|
|
207
|
+
if (command === 'send') {
|
|
208
|
+
await sendMode(opts);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
await scanMode(opts);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
110
214
|
main().catch((err) => {
|
|
111
215
|
const msg = err instanceof Error ? err.message : String(err);
|
|
112
216
|
console.error(fail(`Erro: ${msg}\n`));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/reporter.d.ts
CHANGED
|
@@ -3,7 +3,10 @@ import type { RouteEntry } from './scanner/routes.js';
|
|
|
3
3
|
import type { ComponentEntry, EventEntry } from './scanner/components.js';
|
|
4
4
|
import type { ApiCallEntry } from './scanner/api-calls.js';
|
|
5
5
|
import type { NavigationMap } from './scanner/navigation.js';
|
|
6
|
-
|
|
6
|
+
import type { WcagReport } from './scanner/wcag.js';
|
|
7
|
+
import type { GuidedFlow } from './scanner/guided-flows.js';
|
|
8
|
+
import type { HistoryEntry } from './scanner/history.js';
|
|
9
|
+
export declare const CLI_VERSION = "0.4.0";
|
|
7
10
|
export interface ScanMetadata {
|
|
8
11
|
framework: string;
|
|
9
12
|
language: string;
|
|
@@ -25,6 +28,12 @@ export interface ScanReport {
|
|
|
25
28
|
widgetSnippet: string;
|
|
26
29
|
/** Resumo em linguagem natural das telas e ações (pronto para a IA ler). */
|
|
27
30
|
briefing: string;
|
|
31
|
+
/** Auditoria WCAG: violações, score (0-100) e nível alcançável. */
|
|
32
|
+
wcag: WcagReport;
|
|
33
|
+
/** Fluxos guiados detectados (ex.: login, preenchimento de form). */
|
|
34
|
+
guidedFlows: GuidedFlow[];
|
|
35
|
+
/** Histórico de scans neste projeto (score ao longo do tempo). */
|
|
36
|
+
history: HistoryEntry[];
|
|
28
37
|
secretsFound: number;
|
|
29
38
|
metadata: ScanMetadata;
|
|
30
39
|
}
|
|
@@ -37,6 +46,9 @@ export interface BuildReportInput {
|
|
|
37
46
|
navigationMap: NavigationMap;
|
|
38
47
|
widgetSnippet: string;
|
|
39
48
|
briefing: string;
|
|
49
|
+
wcag: WcagReport;
|
|
50
|
+
guidedFlows: GuidedFlow[];
|
|
51
|
+
history: HistoryEntry[];
|
|
40
52
|
filesScanned: number;
|
|
41
53
|
projectName: string;
|
|
42
54
|
}
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,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,mEAAmE;IACnE,IAAI,EAAE,UAAU,CAAC;IACjB,qEAAqE;IACrE,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,kEAAkE;IAClE,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,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,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,UAAU,CA2B/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
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { maskObject } from './scanner/secrets.js';
|
|
2
|
-
export const CLI_VERSION = '0.
|
|
2
|
+
export const CLI_VERSION = '0.4.0';
|
|
3
3
|
/**
|
|
4
4
|
* Monta o payload final (ScanReport) enviado para a API.
|
|
5
5
|
*/
|
|
6
6
|
export function buildReport(input) {
|
|
7
|
-
const { signature, routes, components, events, apiCalls, navigationMap, widgetSnippet, briefing, filesScanned, projectName } = input;
|
|
7
|
+
const { signature, routes, components, events, apiCalls, navigationMap, widgetSnippet, briefing, wcag, guidedFlows, history, filesScanned, projectName } = input;
|
|
8
8
|
const report = {
|
|
9
9
|
projectName,
|
|
10
10
|
filesScanned,
|
|
@@ -15,6 +15,9 @@ export function buildReport(input) {
|
|
|
15
15
|
navigationMap,
|
|
16
16
|
widgetSnippet,
|
|
17
17
|
briefing,
|
|
18
|
+
wcag,
|
|
19
|
+
guidedFlows,
|
|
20
|
+
history,
|
|
18
21
|
secretsFound: 0,
|
|
19
22
|
metadata: {
|
|
20
23
|
framework: signature.framework,
|
package/dist/reporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAkDnC;;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,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAEjK,MAAM,MAAM,GAAe;QACzB,WAAW;QACX,YAAY;QACZ,MAAM;QACN,UAAU;QACV,MAAM;QACN,QAAQ;QACR,aAAa;QACb,aAAa;QACb,QAAQ;QACR,IAAI;QACJ,WAAW;QACX,OAAO;QACP,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,23 @@
|
|
|
1
|
+
import type { NavigationMap } from './navigation.js';
|
|
2
|
+
export interface GuidedFlowStep {
|
|
3
|
+
screen: string;
|
|
4
|
+
action: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Rota destino, se a ação navegar. */
|
|
7
|
+
navigatesTo?: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface GuidedFlow {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
steps: GuidedFlowStep[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Detecta fluxos guiados a partir do navigationMap.
|
|
16
|
+
* Um fluxo é uma sequência de ações que leva o usuário a um objetivo
|
|
17
|
+
* (ex.: login, preencher formulário, finalizar compra).
|
|
18
|
+
*
|
|
19
|
+
* Heurística: para cada tela que tem um <form> (ações fill + submit),
|
|
20
|
+
* monta um fluxo "Preencher <tela>" com as ações em ordem.
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectGuidedFlows(map: NavigationMap): GuidedFlow[];
|
|
23
|
+
//# sourceMappingURL=guided-flows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guided-flows.d.ts","sourceRoot":"","sources":["../../src/scanner/guided-flows.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,iBAAiB,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,EAAE,CAwClE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detecta fluxos guiados a partir do navigationMap.
|
|
3
|
+
* Um fluxo é uma sequência de ações que leva o usuário a um objetivo
|
|
4
|
+
* (ex.: login, preencher formulário, finalizar compra).
|
|
5
|
+
*
|
|
6
|
+
* Heurística: para cada tela que tem um <form> (ações fill + submit),
|
|
7
|
+
* monta um fluxo "Preencher <tela>" com as ações em ordem.
|
|
8
|
+
*/
|
|
9
|
+
export function detectGuidedFlows(map) {
|
|
10
|
+
const flows = [];
|
|
11
|
+
for (const screen of map.screens) {
|
|
12
|
+
const fills = screen.actions.filter((a) => a.kind === 'fill');
|
|
13
|
+
const submits = screen.actions.filter((a) => a.kind === 'submit');
|
|
14
|
+
const navigations = screen.actions.filter((a) => a.kind === 'navigation');
|
|
15
|
+
// Fluxo 1: formulário (fill + submit)
|
|
16
|
+
if (fills.length > 0 && submits.length > 0) {
|
|
17
|
+
const steps = fills
|
|
18
|
+
.sort(byLabel)
|
|
19
|
+
.map((a) => ({ screen: screen.route, action: a.kind, label: a.label }));
|
|
20
|
+
for (const s of submits) {
|
|
21
|
+
steps.push({
|
|
22
|
+
screen: screen.route,
|
|
23
|
+
action: s.kind,
|
|
24
|
+
label: s.label,
|
|
25
|
+
navigatesTo: s.targetRoute,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
flows.push({
|
|
29
|
+
name: flowNameFor(screen.title, submits[0]?.intent),
|
|
30
|
+
description: `Preencher e enviar o formulário da tela ${screen.title}.`,
|
|
31
|
+
steps,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
// Fluxo 2: navegação primária (se há uma navegação clara da tela)
|
|
35
|
+
if (fills.length === 0 && navigations.length === 1) {
|
|
36
|
+
const nav = navigations[0];
|
|
37
|
+
flows.push({
|
|
38
|
+
name: `Ir para ${navLabel(nav)}`,
|
|
39
|
+
description: `Navegar de ${screen.title} para ${navLabel(nav)}.`,
|
|
40
|
+
steps: [{ screen: screen.route, action: nav.kind, label: nav.label, navigatesTo: nav.targetRoute }],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return flows;
|
|
45
|
+
}
|
|
46
|
+
function byLabel(a, b) {
|
|
47
|
+
return a.label.localeCompare(b.label);
|
|
48
|
+
}
|
|
49
|
+
function navLabel(nav) {
|
|
50
|
+
return nav.targetRoute ?? nav.label;
|
|
51
|
+
}
|
|
52
|
+
function flowNameFor(screenTitle, intent) {
|
|
53
|
+
if (intent === 'login')
|
|
54
|
+
return 'Login do usuário';
|
|
55
|
+
if (intent === 'save')
|
|
56
|
+
return `Salvar em ${screenTitle}`;
|
|
57
|
+
if (intent === 'search')
|
|
58
|
+
return `Buscar em ${screenTitle}`;
|
|
59
|
+
return `Preencher ${screenTitle}`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=guided-flows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guided-flows.js","sourceRoot":"","sources":["../../src/scanner/guided-flows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface HistoryEntry {
|
|
2
|
+
scannedAt: string;
|
|
3
|
+
score: number;
|
|
4
|
+
violations: number;
|
|
5
|
+
/** Contagem por severidade. */
|
|
6
|
+
critical: number;
|
|
7
|
+
serious: number;
|
|
8
|
+
moderate: number;
|
|
9
|
+
minor: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const HISTORY_FILE = ".skip-history.json";
|
|
12
|
+
/**
|
|
13
|
+
* Lê o histórico local do projeto (.skip-history.json).
|
|
14
|
+
* Retorna [] se não existir ou for inválido.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readHistory(rootDir: string): HistoryEntry[];
|
|
17
|
+
/**
|
|
18
|
+
* Adiciona uma entrada ao histórico local e retorna o histórico atualizado.
|
|
19
|
+
* Mantém apenas as últimas MAX_ENTRIES entradas.
|
|
20
|
+
*/
|
|
21
|
+
export declare function appendHistory(rootDir: string, entry: HistoryEntry): HistoryEntry[];
|
|
22
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/scanner/history.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,YAAY,uBAAuB,CAAC;AAGjD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAS3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,EAAE,CAalF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export const HISTORY_FILE = '.skip-history.json';
|
|
4
|
+
const MAX_ENTRIES = 100;
|
|
5
|
+
/**
|
|
6
|
+
* Lê o histórico local do projeto (.skip-history.json).
|
|
7
|
+
* Retorna [] se não existir ou for inválido.
|
|
8
|
+
*/
|
|
9
|
+
export function readHistory(rootDir) {
|
|
10
|
+
const file = path.join(rootDir, HISTORY_FILE);
|
|
11
|
+
if (!fs.existsSync(file))
|
|
12
|
+
return [];
|
|
13
|
+
try {
|
|
14
|
+
const data = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
15
|
+
return Array.isArray(data) ? data : [];
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Adiciona uma entrada ao histórico local e retorna o histórico atualizado.
|
|
23
|
+
* Mantém apenas as últimas MAX_ENTRIES entradas.
|
|
24
|
+
*/
|
|
25
|
+
export function appendHistory(rootDir, entry) {
|
|
26
|
+
const history = readHistory(rootDir);
|
|
27
|
+
history.push(entry);
|
|
28
|
+
const trimmed = history.slice(-MAX_ENTRIES);
|
|
29
|
+
const file = path.join(rootDir, HISTORY_FILE);
|
|
30
|
+
try {
|
|
31
|
+
fs.writeFileSync(file, JSON.stringify(trimmed, null, 2), 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Falha ao salvar histórico não deve quebrar o scan.
|
|
35
|
+
}
|
|
36
|
+
return trimmed;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/scanner/history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAaxB,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AACjD,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACxD,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,KAAmB;IAChE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC;IAE5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,qDAAqD;IACvD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Severity, WcagLevel, WcagViolation } from './wcag.js';
|
|
2
|
+
/** Penalização por severidade (multiplicada pela contagem). */
|
|
3
|
+
export declare const SEVERITY_WEIGHT: Record<Severity, number>;
|
|
4
|
+
export interface ScoreResult {
|
|
5
|
+
/** 0–100 */
|
|
6
|
+
score: number;
|
|
7
|
+
/** Nível WCAG alcançável: A, AA ou AAA. */
|
|
8
|
+
level: WcagLevel;
|
|
9
|
+
/** Total de violações consideradas. */
|
|
10
|
+
total: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Calcula o score de acessibilidade (0–100).
|
|
14
|
+
* Começa em 100 e desconta por severidade, com floor em 0.
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateScore(violations: WcagViolation[]): ScoreResult;
|
|
17
|
+
/** Cor sugerida para o score (pra usar no dashboard/terminal). */
|
|
18
|
+
export declare function scoreColor(score: number): string;
|
|
19
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/scanner/score.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEpE,+DAA+D;AAC/D,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAKpD,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,KAAK,EAAE,SAAS,CAAC;IACjB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,WAAW,CAcvE;AAsBD,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKhD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Penalização por severidade (multiplicada pela contagem). */
|
|
2
|
+
export const SEVERITY_WEIGHT = {
|
|
3
|
+
critical: 12,
|
|
4
|
+
serious: 6,
|
|
5
|
+
moderate: 3,
|
|
6
|
+
minor: 1,
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Calcula o score de acessibilidade (0–100).
|
|
10
|
+
* Começa em 100 e desconta por severidade, com floor em 0.
|
|
11
|
+
*/
|
|
12
|
+
export function calculateScore(violations) {
|
|
13
|
+
let penalty = 0;
|
|
14
|
+
let total = violations.length;
|
|
15
|
+
for (const v of violations) {
|
|
16
|
+
penalty += SEVERITY_WEIGHT[v.severity];
|
|
17
|
+
}
|
|
18
|
+
// Cada tela sem violações ameniza o desconto (evita score punitivo em projetos grandes)
|
|
19
|
+
const score = Math.max(0, Math.round(100 - penalty));
|
|
20
|
+
const level = determineLevel(violations);
|
|
21
|
+
return { score, level, total };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Determina o nível WCAG alcançável:
|
|
25
|
+
* - AAA: nenhuma violação
|
|
26
|
+
* - AA: nenhuma violação AA/AAA (pode ter A)
|
|
27
|
+
* - A: nenhuma violação A... na prática, se há A, fica A
|
|
28
|
+
*
|
|
29
|
+
* Observação: projetado como indicador de conformidade alcançável, não certificação.
|
|
30
|
+
*/
|
|
31
|
+
function determineLevel(violations) {
|
|
32
|
+
if (violations.length === 0)
|
|
33
|
+
return 'AAA';
|
|
34
|
+
const hasA = violations.some((v) => v.level === 'A');
|
|
35
|
+
if (hasA)
|
|
36
|
+
return 'A';
|
|
37
|
+
const hasAA = violations.some((v) => v.level === 'AA');
|
|
38
|
+
if (hasAA)
|
|
39
|
+
return 'AA';
|
|
40
|
+
return 'AA';
|
|
41
|
+
}
|
|
42
|
+
/** Cor sugerida para o score (pra usar no dashboard/terminal). */
|
|
43
|
+
export function scoreColor(score) {
|
|
44
|
+
if (score >= 90)
|
|
45
|
+
return 'green';
|
|
46
|
+
if (score >= 70)
|
|
47
|
+
return 'yellow';
|
|
48
|
+
if (score >= 50)
|
|
49
|
+
return 'magenta';
|
|
50
|
+
return 'red';
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/scanner/score.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;CACT,CAAC;AAWF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,UAA2B;IACxD,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC;IAE9B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,OAAO,IAAI,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,wFAAwF;IACxF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAErD,MAAM,KAAK,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAEzC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,UAA2B;IACjD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE1C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;IACrD,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC;IAErB,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;IACvD,IAAI,KAAK;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,OAAO,CAAC;IAChC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,QAAQ,CAAC;IACjC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ScreenMap } from './navigation.js';
|
|
2
|
+
export type Severity = 'critical' | 'serious' | 'moderate' | 'minor';
|
|
3
|
+
export type WcagLevel = 'A' | 'AA' | 'AAA';
|
|
4
|
+
export interface WcagViolation {
|
|
5
|
+
id: string;
|
|
6
|
+
rule: string;
|
|
7
|
+
level: WcagLevel;
|
|
8
|
+
severity: Severity;
|
|
9
|
+
impact: string;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
screen: string;
|
|
13
|
+
filePath: string;
|
|
14
|
+
selector: string;
|
|
15
|
+
fix: string;
|
|
16
|
+
wcagUrl: string;
|
|
17
|
+
}
|
|
18
|
+
export interface WcagSummary {
|
|
19
|
+
critical: number;
|
|
20
|
+
serious: number;
|
|
21
|
+
moderate: number;
|
|
22
|
+
minor: number;
|
|
23
|
+
}
|
|
24
|
+
export interface WcagReport {
|
|
25
|
+
score: number;
|
|
26
|
+
level: WcagLevel;
|
|
27
|
+
violations: WcagViolation[];
|
|
28
|
+
summary: WcagSummary;
|
|
29
|
+
auditedAt: string;
|
|
30
|
+
rulesVersion: string;
|
|
31
|
+
}
|
|
32
|
+
export declare const WCAG_RULES_VERSION = "1.0.0";
|
|
33
|
+
export interface AuditContext {
|
|
34
|
+
screen: ScreenMap;
|
|
35
|
+
/** Conteúdo do arquivo da tela (lido localmente; NUNCA enviado ao servidor). */
|
|
36
|
+
content: string;
|
|
37
|
+
}
|
|
38
|
+
export interface RuleDef {
|
|
39
|
+
id: string;
|
|
40
|
+
rule: string;
|
|
41
|
+
level: WcagLevel;
|
|
42
|
+
severity: Severity;
|
|
43
|
+
impact: string;
|
|
44
|
+
title: string;
|
|
45
|
+
wcagUrl: string;
|
|
46
|
+
defaultFix: string;
|
|
47
|
+
/** Extrai as violações desta regra no contexto. */
|
|
48
|
+
check: (ctx: AuditContext) => WcagViolation[];
|
|
49
|
+
}
|
|
50
|
+
export declare const RULES: RuleDef[];
|
|
51
|
+
/**
|
|
52
|
+
* Aplica todas as regras WCAG a um conjunto de telas.
|
|
53
|
+
* Os conteúdos dos arquivos são lidos localmente e NÃO são enviados ao servidor.
|
|
54
|
+
*/
|
|
55
|
+
export declare function auditWcag(screens: ScreenMap[], contentsByFile: Record<string, string>): WcagViolation[];
|
|
56
|
+
/** Conta violações por severidade. */
|
|
57
|
+
export declare function summarize(violations: WcagViolation[]): WcagSummary;
|
|
58
|
+
//# sourceMappingURL=wcag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wcag.d.ts","sourceRoot":"","sources":["../../src/scanner/wcag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AACrE,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAI1C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,aAAa,EAAE,CAAC;CAC/C;AA6FD,eAAO,MAAM,KAAK,EAAE,OAAO,EAuP1B,CAAC;AA4CF;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,SAAS,EAAE,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,aAAa,EAAE,CAwBjB;AAED,sCAAsC;AACtC,wBAAgB,SAAS,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,WAAW,CAIlE"}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
export const WCAG_RULES_VERSION = '1.0.0';
|
|
2
|
+
function findTags(content, tagNames) {
|
|
3
|
+
const out = [];
|
|
4
|
+
const re = new RegExp(`<(${tagNames.join('|')})\\b`, 'gi');
|
|
5
|
+
let m;
|
|
6
|
+
while ((m = re.exec(content)) !== null) {
|
|
7
|
+
const lt = m.index;
|
|
8
|
+
const tag = m[1];
|
|
9
|
+
let i = lt + 1 + tag.length;
|
|
10
|
+
let brace = 0;
|
|
11
|
+
let quote = null;
|
|
12
|
+
while (i < content.length) {
|
|
13
|
+
const ch = content[i];
|
|
14
|
+
if (quote) {
|
|
15
|
+
if (ch === quote)
|
|
16
|
+
quote = null;
|
|
17
|
+
i++;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (ch === '"' || ch === "'") {
|
|
21
|
+
quote = ch;
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (ch === '{') {
|
|
26
|
+
brace++;
|
|
27
|
+
i++;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (ch === '}') {
|
|
31
|
+
brace--;
|
|
32
|
+
i++;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (brace === 0 && ch === '>') {
|
|
36
|
+
out.push({
|
|
37
|
+
full: content.substring(lt, i + 1),
|
|
38
|
+
tag,
|
|
39
|
+
attrs: content.substring(lt + 1 + tag.length, i).trim(),
|
|
40
|
+
contentStart: i + 1,
|
|
41
|
+
});
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
i++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function attr(attrs, name) {
|
|
50
|
+
const m = attrs.match(new RegExp(`\\b${name}\\s*=\\s*["']([^"']*)["']`, 'i'));
|
|
51
|
+
return m ? m[1] : null;
|
|
52
|
+
}
|
|
53
|
+
function visibleText(content, from) {
|
|
54
|
+
if (from < 0)
|
|
55
|
+
return '';
|
|
56
|
+
const slice = content.substring(from, from + 120);
|
|
57
|
+
const m = slice.match(/^\s*([^<{]+)/);
|
|
58
|
+
return m ? m[1].trim() : '';
|
|
59
|
+
}
|
|
60
|
+
function buildSelectorFromTag(tag, attrs, inputName) {
|
|
61
|
+
const id = attr(attrs, 'id');
|
|
62
|
+
if (id)
|
|
63
|
+
return `#${id}`;
|
|
64
|
+
const anchor = attr(attrs, 'data-skip-anchor');
|
|
65
|
+
if (anchor)
|
|
66
|
+
return `[data-skip-anchor='${anchor}']`;
|
|
67
|
+
if (inputName)
|
|
68
|
+
return `${tag}[name='${inputName}']`;
|
|
69
|
+
const aria = attr(attrs, 'aria-label');
|
|
70
|
+
if (aria)
|
|
71
|
+
return `${tag}[aria-label='${aria}']`;
|
|
72
|
+
return tag;
|
|
73
|
+
}
|
|
74
|
+
// ---- Definição das regras WCAG ----
|
|
75
|
+
const VALID_ROLES = new Set([
|
|
76
|
+
'alert', 'alertdialog', 'banner', 'button', 'checkbox', 'complementary',
|
|
77
|
+
'contentinfo', 'dialog', 'document', 'form', 'grid', 'gridcell', 'heading',
|
|
78
|
+
'img', 'link', 'list', 'listbox', 'listitem', 'main', 'menu', 'menubar',
|
|
79
|
+
'menuitem', 'navigation', 'none', 'note', 'option', 'presentation', 'progressbar',
|
|
80
|
+
'radio', 'radiogroup', 'region', 'row', 'rowgroup', 'rowheader', 'scrollbar',
|
|
81
|
+
'search', 'separator', 'slider', 'spinbutton', 'status', 'tab', 'tablist',
|
|
82
|
+
'tabpanel', 'textbox', 'timer', 'toolbar', 'tooltip', 'tree', 'treegrid', 'treeitem',
|
|
83
|
+
]);
|
|
84
|
+
export const RULES = [
|
|
85
|
+
// 1.1.1 — Imagem sem alt
|
|
86
|
+
{
|
|
87
|
+
id: 'img-alt-missing',
|
|
88
|
+
rule: '1.1.1 Non-text Content',
|
|
89
|
+
level: 'A',
|
|
90
|
+
severity: 'critical',
|
|
91
|
+
impact: 'Leitores de tela não conseguem descrever a imagem para usuários cegos.',
|
|
92
|
+
title: 'Imagem sem texto alternativo',
|
|
93
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#non-text-content',
|
|
94
|
+
defaultFix: "Adicione alt='...' descrevendo a imagem, ou alt='' se for puramente decorativa.",
|
|
95
|
+
check: (ctx) => {
|
|
96
|
+
const out = [];
|
|
97
|
+
for (const t of findTags(ctx.content, ['img'])) {
|
|
98
|
+
if (!/\balt\s*=/.test(t.attrs)) {
|
|
99
|
+
out.push(violation(thisId(ctx, 'img-alt'), ctx, t, buildSelectorFromTag('img', t.attrs, null)));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
// 4.1.2 — Button sem nome acessível
|
|
106
|
+
{
|
|
107
|
+
id: 'button-no-name',
|
|
108
|
+
rule: '4.1.2 Name, Role, Value',
|
|
109
|
+
level: 'A',
|
|
110
|
+
severity: 'serious',
|
|
111
|
+
impact: 'Usuários de leitor de tela ouvem apenas "botão" sem saber sua função.',
|
|
112
|
+
title: 'Botão sem nome acessível',
|
|
113
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#name-role-value',
|
|
114
|
+
defaultFix: "Adicione texto visível, aria-label='...' ou aria-labelledby='...'.",
|
|
115
|
+
check: (ctx) => {
|
|
116
|
+
const out = [];
|
|
117
|
+
for (const t of findTags(ctx.content, ['button'])) {
|
|
118
|
+
const aria = attr(t.attrs, 'aria-label') || attr(t.attrs, 'aria-labelledby');
|
|
119
|
+
const text = visibleText(ctx.content, t.contentStart);
|
|
120
|
+
if (!aria && !text) {
|
|
121
|
+
out.push(violation(thisId(ctx, 'btn-name'), ctx, t, buildSelectorFromTag('button', t.attrs, null)));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
// 1.3.1 / 3.3.2 — Input sem label
|
|
128
|
+
{
|
|
129
|
+
id: 'input-no-label',
|
|
130
|
+
rule: '1.3.1 Info and Relationships / 3.3.2 Labels or Instructions',
|
|
131
|
+
level: 'A',
|
|
132
|
+
severity: 'serious',
|
|
133
|
+
impact: 'Usuários não sabem o que preencher; leitores de tela anunciam "campo de texto" sem contexto.',
|
|
134
|
+
title: 'Campo de formulário sem label associada',
|
|
135
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#labels-or-instructions',
|
|
136
|
+
defaultFix: "Associe um <label for='id'>, ou adicione aria-label='...' ou aria-labelledby='...'.",
|
|
137
|
+
check: (ctx) => {
|
|
138
|
+
const out = [];
|
|
139
|
+
const inputs = findTags(ctx.content, ['input', 'textarea', 'select']);
|
|
140
|
+
// Procura <label for="x"> no conteúdo pra ver se o input tem label
|
|
141
|
+
const labelFors = new Set();
|
|
142
|
+
const labelRe = /<label\b[^>]*\bfor\s*=\s*["']([^"']+)["']/gi;
|
|
143
|
+
let lm;
|
|
144
|
+
while ((lm = labelRe.exec(ctx.content)) !== null)
|
|
145
|
+
labelFors.add(lm[1]);
|
|
146
|
+
for (const t of inputs) {
|
|
147
|
+
if (t.attrs.includes('type="hidden"') || t.attrs.includes("type='hidden'"))
|
|
148
|
+
continue;
|
|
149
|
+
const id = attr(t.attrs, 'id');
|
|
150
|
+
const aria = attr(t.attrs, 'aria-label') || attr(t.attrs, 'aria-labelledby');
|
|
151
|
+
const labelled = (id && labelFors.has(id)) || aria;
|
|
152
|
+
if (!labelled) {
|
|
153
|
+
const name = attr(t.attrs, 'name');
|
|
154
|
+
out.push(violation(thisId(ctx, 'input-label'), ctx, t, buildSelectorFromTag(t.tag, t.attrs, name)));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
// 2.4.4 — Link com href vazio
|
|
161
|
+
{
|
|
162
|
+
id: 'link-href-empty',
|
|
163
|
+
rule: '2.4.4 Link Purpose (In Context)',
|
|
164
|
+
level: 'A',
|
|
165
|
+
severity: 'moderate',
|
|
166
|
+
impact: "Links com href='#' ou vazio não levam a lugar algum, confundindo navegação.",
|
|
167
|
+
title: 'Link sem destino válido',
|
|
168
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#link-purpose-in-context',
|
|
169
|
+
defaultFix: "Use um href válido apontando para a rota correta, ou transforme em <button> se for uma ação.",
|
|
170
|
+
check: (ctx) => {
|
|
171
|
+
const out = [];
|
|
172
|
+
for (const t of findTags(ctx.content, ['a'])) {
|
|
173
|
+
const href = attr(t.attrs, 'href');
|
|
174
|
+
if (href === '#' || href === '' || href == null) {
|
|
175
|
+
out.push(violation(thisId(ctx, 'link-href'), ctx, t, buildSelectorFromTag('a', t.attrs, null)));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
// 2.4.3 — tabindex positivo
|
|
182
|
+
{
|
|
183
|
+
id: 'tabindex-positive',
|
|
184
|
+
rule: '2.4.3 Focus Order',
|
|
185
|
+
level: 'A',
|
|
186
|
+
severity: 'moderate',
|
|
187
|
+
impact: 'tabindex positivo quebra a ordem natural de navegação por teclado.',
|
|
188
|
+
title: 'tabindex positivo quebra ordem de foco',
|
|
189
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#focus-order',
|
|
190
|
+
defaultFix: "Remova o tabindex positivo; use ordem natural do DOM. Use tabindex='0' se precisar tornar focável.",
|
|
191
|
+
check: (ctx) => {
|
|
192
|
+
const out = [];
|
|
193
|
+
const re = /<(\w+)\b([^>]*?)\btabindex\s*=\s*["']([1-9]\d*)["']/gi;
|
|
194
|
+
let m;
|
|
195
|
+
while ((m = re.exec(ctx.content)) !== null) {
|
|
196
|
+
out.push(violationRaw(thisId(ctx, 'tabindex'), ctx, `${m[1]}`, m[2], `${m[1]}[tabindex='${m[3]}']`));
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
// 1.3.1 — ordem de headings
|
|
202
|
+
{
|
|
203
|
+
id: 'heading-order',
|
|
204
|
+
rule: '1.3.1 Info and Relationships',
|
|
205
|
+
level: 'A',
|
|
206
|
+
severity: 'moderate',
|
|
207
|
+
impact: 'Pular níveis de heading (ex.: h1→h3) confunde a estrutura do documento para leitores de tela.',
|
|
208
|
+
title: 'Ordem de headings inconsistente',
|
|
209
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#info-and-relationships',
|
|
210
|
+
defaultFix: 'Não pule níveis: após h1 use h2, após h2 use h3, etc.',
|
|
211
|
+
check: (ctx) => {
|
|
212
|
+
const out = [];
|
|
213
|
+
const re = /<h([1-6])\b/gi;
|
|
214
|
+
let prev = 0;
|
|
215
|
+
let m;
|
|
216
|
+
while ((m = re.exec(ctx.content)) !== null) {
|
|
217
|
+
const lvl = parseInt(m[1], 10);
|
|
218
|
+
if (prev !== 0 && lvl > prev + 1) {
|
|
219
|
+
out.push(violationRaw(thisId(ctx, 'heading'), ctx, `h${lvl}`, '', `h${lvl}`));
|
|
220
|
+
}
|
|
221
|
+
prev = lvl;
|
|
222
|
+
}
|
|
223
|
+
return out;
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
// 4.1.2 — role inválida
|
|
227
|
+
{
|
|
228
|
+
id: 'aria-invalid-role',
|
|
229
|
+
rule: '4.1.2 Name, Role, Value',
|
|
230
|
+
level: 'A',
|
|
231
|
+
severity: 'serious',
|
|
232
|
+
impact: 'role inválida faz leitores de tela anunciarem o elemento incorretamente.',
|
|
233
|
+
title: 'atributo role inválido',
|
|
234
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#name-role-value',
|
|
235
|
+
defaultFix: 'Use um valor de role válido da especificação ARIA, ou remova o atributo.',
|
|
236
|
+
check: (ctx) => {
|
|
237
|
+
const out = [];
|
|
238
|
+
const re = /<(\w+)\b([^>]*?)\brole\s*=\s*["']([^"']+)["']/gi;
|
|
239
|
+
let m;
|
|
240
|
+
while ((m = re.exec(ctx.content)) !== null) {
|
|
241
|
+
if (!VALID_ROLES.has(m[3])) {
|
|
242
|
+
out.push(violationRaw(thisId(ctx, 'aria-role'), ctx, m[1], m[2], `${m[1]}[role='${m[3]}']`));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
// 3.1.1 — html sem lang
|
|
249
|
+
{
|
|
250
|
+
id: 'lang-missing',
|
|
251
|
+
rule: '3.1.1 Language of Page',
|
|
252
|
+
level: 'A',
|
|
253
|
+
severity: 'serious',
|
|
254
|
+
impact: 'Sem lang no <html>, leitores de tela usam idioma errado pra pronunciar.',
|
|
255
|
+
title: 'Documento sem idioma declarado',
|
|
256
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#language-of-page',
|
|
257
|
+
defaultFix: "Adicione lang='pt-BR' (ou o idioma correto) na tag <html>.",
|
|
258
|
+
check: (ctx) => {
|
|
259
|
+
const htmlMatch = ctx.content.match(/<html\b([^>]*)>/i);
|
|
260
|
+
if (htmlMatch && !/\blang\s*=/.test(htmlMatch[1])) {
|
|
261
|
+
return [
|
|
262
|
+
violationRaw(thisId(ctx, 'lang'), ctx, 'html', htmlMatch[1], 'html'),
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
return [];
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
// 2.4.1 — sem skip link
|
|
269
|
+
{
|
|
270
|
+
id: 'skip-link-missing',
|
|
271
|
+
rule: '2.4.1 Bypass Blocks',
|
|
272
|
+
level: 'A',
|
|
273
|
+
severity: 'moderate',
|
|
274
|
+
impact: 'Usuários de teclado precisam tabular por toda a navegação repetitiva a cada página.',
|
|
275
|
+
title: 'Sem link de pular para o conteúdo',
|
|
276
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#bypass-blocks',
|
|
277
|
+
defaultFix: "Adicione um <a href='#main' className='skip-link'>Pular para o conteúdo</a> como primeiro elemento focável.",
|
|
278
|
+
check: (ctx) => {
|
|
279
|
+
const hasSkip = /href\s*=\s*["']#(?:main|content)["']/i.test(ctx.content);
|
|
280
|
+
const hasMain = /id\s*=\s*["']main["']/i.test(ctx.content) || /<main\b/i.test(ctx.content);
|
|
281
|
+
if (!hasSkip && hasMain) {
|
|
282
|
+
return [violationRaw(thisId(ctx, 'skip'), ctx, 'body', '', 'body')];
|
|
283
|
+
}
|
|
284
|
+
return [];
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
// 1.4.3 — contraste (heurística estática)
|
|
288
|
+
{
|
|
289
|
+
id: 'low-contrast-hint',
|
|
290
|
+
rule: '1.4.3 Contrast (Minimum)',
|
|
291
|
+
level: 'AA',
|
|
292
|
+
severity: 'minor',
|
|
293
|
+
impact: 'Possível baixo contraste texto/fundo dificulta leitura para usuários com baixa visão.',
|
|
294
|
+
title: 'Possível baixo contraste de cor',
|
|
295
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#contrast-minimum',
|
|
296
|
+
defaultFix: 'Verifique a razão de contraste (mínimo 4.5:1 para texto normal). Evite classes como text-gray-300 em fundos brancos.',
|
|
297
|
+
check: (ctx) => {
|
|
298
|
+
const out = [];
|
|
299
|
+
const suspect = /(text-(?:gray|slate|zinc|neutral)-(?:200|300))|(text-white\/[1-4]\d)|(opacity-(?:[1-3]\d|40))/gi;
|
|
300
|
+
let m;
|
|
301
|
+
while ((m = suspect.exec(ctx.content)) !== null) {
|
|
302
|
+
out.push(violationRaw(thisId(ctx, 'contrast'), ctx, '*', m[0], m[0]));
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
// 3.3.2 — form sem instrução
|
|
308
|
+
{
|
|
309
|
+
id: 'form-no-instruction',
|
|
310
|
+
rule: '3.3.2 Labels or Instructions',
|
|
311
|
+
level: 'A',
|
|
312
|
+
severity: 'moderate',
|
|
313
|
+
impact: 'Formulários sem instruções aumentam chance de erro do usuário.',
|
|
314
|
+
title: 'Formulário sem instrução de preenchimento',
|
|
315
|
+
wcagUrl: 'https://www.w3.org/WAI/WCAG22/quickref/#labels-or-instructions',
|
|
316
|
+
defaultFix: 'Adicione uma instrução curta antes do formulário, ou aria-describedby nos campos.',
|
|
317
|
+
check: (ctx) => {
|
|
318
|
+
const forms = findTags(ctx.content, ['form']);
|
|
319
|
+
if (forms.length === 0)
|
|
320
|
+
return [];
|
|
321
|
+
// heurística: se há <form> mas nenhum <p>/<span> com texto de instrução antes
|
|
322
|
+
const hasInstruction = /(por favor|preencha|informe|digite|required|obrigat)/i.test(ctx.content);
|
|
323
|
+
if (!hasInstruction) {
|
|
324
|
+
return [violationRaw(thisId(ctx, 'form-instr'), ctx, 'form', '', 'form')];
|
|
325
|
+
}
|
|
326
|
+
return [];
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
];
|
|
330
|
+
// ---- Helpers de construção de violação ----
|
|
331
|
+
function thisId(ctx, slug) {
|
|
332
|
+
return `${slug}-${ctx.screen.id}`;
|
|
333
|
+
}
|
|
334
|
+
function violation(id, ctx, tag, selector) {
|
|
335
|
+
return violationRaw(id, ctx, tag.tag, tag.attrs, selector);
|
|
336
|
+
}
|
|
337
|
+
function violationRaw(id, ctx, tag, attrs, selector) {
|
|
338
|
+
void tag;
|
|
339
|
+
void attrs;
|
|
340
|
+
return {
|
|
341
|
+
id,
|
|
342
|
+
rule: '',
|
|
343
|
+
level: 'A',
|
|
344
|
+
severity: 'minor',
|
|
345
|
+
impact: '',
|
|
346
|
+
title: '',
|
|
347
|
+
description: '',
|
|
348
|
+
screen: ctx.screen.route,
|
|
349
|
+
filePath: ctx.screen.filePath,
|
|
350
|
+
selector,
|
|
351
|
+
fix: '',
|
|
352
|
+
wcagUrl: '',
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
// ---- Orquestrador da auditoria ----
|
|
356
|
+
/**
|
|
357
|
+
* Aplica todas as regras WCAG a um conjunto de telas.
|
|
358
|
+
* Os conteúdos dos arquivos são lidos localmente e NÃO são enviados ao servidor.
|
|
359
|
+
*/
|
|
360
|
+
export function auditWcag(screens, contentsByFile) {
|
|
361
|
+
const all = [];
|
|
362
|
+
for (const screen of screens) {
|
|
363
|
+
const content = contentsByFile[screen.filePath] ?? '';
|
|
364
|
+
const ctx = { screen, content };
|
|
365
|
+
for (const rule of RULES) {
|
|
366
|
+
const found = rule.check(ctx);
|
|
367
|
+
for (const v of found) {
|
|
368
|
+
all.push({
|
|
369
|
+
...v,
|
|
370
|
+
id: v.id,
|
|
371
|
+
rule: rule.rule,
|
|
372
|
+
level: rule.level,
|
|
373
|
+
severity: rule.severity,
|
|
374
|
+
impact: rule.impact,
|
|
375
|
+
title: rule.title,
|
|
376
|
+
fix: rule.defaultFix,
|
|
377
|
+
wcagUrl: rule.wcagUrl,
|
|
378
|
+
description: `${rule.title} em ${screen.route} (${screen.filePath}).`,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return all;
|
|
384
|
+
}
|
|
385
|
+
/** Conta violações por severidade. */
|
|
386
|
+
export function summarize(violations) {
|
|
387
|
+
const s = { critical: 0, serious: 0, moderate: 0, minor: 0 };
|
|
388
|
+
for (const v of violations)
|
|
389
|
+
s[v.severity]++;
|
|
390
|
+
return s;
|
|
391
|
+
}
|
|
392
|
+
//# sourceMappingURL=wcag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wcag.js","sourceRoot":"","sources":["../../src/scanner/wcag.ts"],"names":[],"mappings":"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"}
|