@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.
Files changed (58) hide show
  1. package/README.md +81 -0
  2. package/dist/cli.d.ts +11 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +21 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/detector.d.ts +14 -0
  7. package/dist/detector.d.ts.map +1 -0
  8. package/dist/detector.js +72 -0
  9. package/dist/detector.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +115 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/reporter.d.ts +55 -0
  15. package/dist/reporter.d.ts.map +1 -0
  16. package/dist/reporter.js +38 -0
  17. package/dist/reporter.js.map +1 -0
  18. package/dist/scanner/api-calls.d.ts +11 -0
  19. package/dist/scanner/api-calls.d.ts.map +1 -0
  20. package/dist/scanner/api-calls.js +45 -0
  21. package/dist/scanner/api-calls.js.map +1 -0
  22. package/dist/scanner/briefing.d.ts +7 -0
  23. package/dist/scanner/briefing.d.ts.map +1 -0
  24. package/dist/scanner/briefing.js +50 -0
  25. package/dist/scanner/briefing.js.map +1 -0
  26. package/dist/scanner/components.d.ts +24 -0
  27. package/dist/scanner/components.d.ts.map +1 -0
  28. package/dist/scanner/components.js +71 -0
  29. package/dist/scanner/components.js.map +1 -0
  30. package/dist/scanner/ignore.d.ts +13 -0
  31. package/dist/scanner/ignore.d.ts.map +1 -0
  32. package/dist/scanner/ignore.js +50 -0
  33. package/dist/scanner/ignore.js.map +1 -0
  34. package/dist/scanner/navigation.d.ts +50 -0
  35. package/dist/scanner/navigation.d.ts.map +1 -0
  36. package/dist/scanner/navigation.js +478 -0
  37. package/dist/scanner/navigation.js.map +1 -0
  38. package/dist/scanner/routes.d.ts +12 -0
  39. package/dist/scanner/routes.d.ts.map +1 -0
  40. package/dist/scanner/routes.js +74 -0
  41. package/dist/scanner/routes.js.map +1 -0
  42. package/dist/scanner/secrets.d.ts +18 -0
  43. package/dist/scanner/secrets.d.ts.map +1 -0
  44. package/dist/scanner/secrets.js +36 -0
  45. package/dist/scanner/secrets.js.map +1 -0
  46. package/dist/scanner/widget-snippet.d.ts +14 -0
  47. package/dist/scanner/widget-snippet.d.ts.map +1 -0
  48. package/dist/scanner/widget-snippet.js +114 -0
  49. package/dist/scanner/widget-snippet.js.map +1 -0
  50. package/dist/ui.d.ts +15 -0
  51. package/dist/ui.d.ts.map +1 -0
  52. package/dist/ui.js +32 -0
  53. package/dist/ui.js.map +1 -0
  54. package/dist/uploader.d.ts +27 -0
  55. package/dist/uploader.d.ts.map +1 -0
  56. package/dist/uploader.js +73 -0
  57. package/dist/uploader.js.map +1 -0
  58. package/package.json +51 -0
@@ -0,0 +1,71 @@
1
+ import { glob } from 'glob';
2
+ import fs from 'fs';
3
+ import { DEFAULT_IGNORE_PATTERNS, toRelative } from './ignore.js';
4
+ /**
5
+ * Extrai componentes React (TSX/JSX) com suas props e eventos,
6
+ * além dos eventos DOM vinculados a handlers no código.
7
+ * Inclui também layouts e componentes compartilhados (sidebar, navbar...).
8
+ */
9
+ export async function extractComponents(rootDir, ignorePatterns = []) {
10
+ const files = await glob('src/**/*.{tsx,jsx}', {
11
+ cwd: rootDir,
12
+ absolute: true,
13
+ ignore: [...DEFAULT_IGNORE_PATTERNS, ...ignorePatterns],
14
+ });
15
+ const components = [];
16
+ const events = [];
17
+ for (const file of files) {
18
+ let content;
19
+ try {
20
+ content = fs.readFileSync(file, 'utf-8');
21
+ }
22
+ catch {
23
+ continue;
24
+ }
25
+ const relative = toRelative(rootDir, file);
26
+ // Nome do componente (export default ou named)
27
+ const nameMatch = content.match(/export\s+(?:default\s+)?(?:function|const)\s+(\w+)/);
28
+ if (!nameMatch)
29
+ continue;
30
+ const name = nameMatch[1];
31
+ // Props: interface *Props { ... } ou PropsWithChildren
32
+ const propsMatch = content.match(/interface\s+\w*Props\s*\{([\s\S]*?)\}/) ||
33
+ content.match(/type\s+\w*Props\s*=\s*\{([\s\S]*?)\}/);
34
+ const props = propsMatch
35
+ ? (propsMatch[1].match(/(\w+)\??\s*:/g)?.map((p) => p.replace(/[?:]/g, '').trim()) ?? [])
36
+ : [];
37
+ // Eventos: onClick={fn}, onClick={() => ...}, onSubmit={e => ...}, etc.
38
+ // O handler pode ser um identificador, ou uma arrow/anônima inline.
39
+ const eventMatches = [
40
+ ...content.matchAll(/on(Click|Submit|Change|Focus|Blur|KeyDown|KeyUp|KeyPress|MouseEnter|MouseLeave|Input|Scroll|Load|Error)\s*=\s*\{?\s*([A-Za-z_$][\w$]*)?/g),
41
+ ];
42
+ const componentEvents = [];
43
+ for (const match of eventMatches) {
44
+ const evType = `on${match[1]}`;
45
+ const handler = match[2] || '(anonymous)';
46
+ const idx = match.index ?? 0;
47
+ // Tenta descobrir a tag e o id do elemento onde o evento está
48
+ const lineStart = content.lastIndexOf('\n', idx) + 1;
49
+ const line = content.substring(lineStart, idx + 60);
50
+ const tagMatch = line.match(/<(\w+)/);
51
+ const idMatch = line.match(/id=["']([^"']+)["']/);
52
+ componentEvents.push(evType);
53
+ events.push({
54
+ type: evType,
55
+ handler,
56
+ filepath: relative,
57
+ elementTag: tagMatch?.[1] ?? 'unknown',
58
+ elementId: idMatch?.[1] ?? null,
59
+ });
60
+ }
61
+ components.push({
62
+ name,
63
+ filepath: relative,
64
+ props,
65
+ events: [...new Set(componentEvents)],
66
+ hasForm: content.includes('<form') || content.includes('<Form'),
67
+ });
68
+ }
69
+ return { components, events };
70
+ }
71
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/scanner/components.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Padrões de diretórios/arquivos ignorados por padrão em todos os scanners.
3
+ * Evita ruído irrelevante e grandes volumes desnecessários.
4
+ */
5
+ export declare const DEFAULT_IGNORE_PATTERNS: string[];
6
+ /** Segmentos de rota especiais do Next.js App Router que não são páginas. */
7
+ export declare const IGNORED_ROUTE_SEGMENTS: string[];
8
+ /**
9
+ * Retorna o caminho relativo ao rootDir, normalizado com forward slashes e sem barra inicial.
10
+ */
11
+ export declare function toRelative(rootDir: string, absPath: string): string;
12
+ export declare function isIgnored(relPath: string, patterns: string[]): boolean;
13
+ //# sourceMappingURL=ignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.d.ts","sourceRoot":"","sources":["../../src/scanner/ignore.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,uBAAuB,UAYnC,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,sBAAsB,UAAqF,CAAC;AAEzH;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnE;AAID,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAMtE"}
@@ -0,0 +1,50 @@
1
+ import path from 'path';
2
+ /**
3
+ * Padrões de diretórios/arquivos ignorados por padrão em todos os scanners.
4
+ * Evita ruído irrelevante e grandes volumes desnecessários.
5
+ */
6
+ export const DEFAULT_IGNORE_PATTERNS = [
7
+ '**/node_modules/**',
8
+ '**/dist/**',
9
+ '**/build/**',
10
+ '**/.next/**',
11
+ '**/.nuxt/**',
12
+ '**/.git/**',
13
+ '**/.cache/**',
14
+ '**/coverage/**',
15
+ '**/*.test.{ts,tsx,js,jsx}',
16
+ '**/*.spec.{ts,tsx,js,jsx}',
17
+ '**/*.stories.{ts,tsx,js,jsx}',
18
+ ];
19
+ /** Segmentos de rota especiais do Next.js App Router que não são páginas. */
20
+ export const IGNORED_ROUTE_SEGMENTS = ['layout', 'loading', 'error', 'not-found', 'template', 'global-error', 'default'];
21
+ /**
22
+ * Retorna o caminho relativo ao rootDir, normalizado com forward slashes e sem barra inicial.
23
+ */
24
+ export function toRelative(rootDir, absPath) {
25
+ const rel = path.relative(rootDir, absPath);
26
+ return rel.split(path.sep).join('/').replace(/^\//, '');
27
+ }
28
+ // Verifica se um caminho relativo deve ser ignorado com base nos padrões informados.
29
+ // Implementação simples de glob (suporta padrões com '**', '*' e sufixos).
30
+ export function isIgnored(relPath, patterns) {
31
+ const normalized = relPath.split(path.sep).join('/');
32
+ for (const p of patterns) {
33
+ if (matchGlob(normalized, p))
34
+ return true;
35
+ }
36
+ return false;
37
+ }
38
+ function matchGlob(filePath, pattern) {
39
+ // Converte o padrão glob em RegExp de forma simples
40
+ const re = '^' +
41
+ pattern
42
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
43
+ .replace(/\*\*/g, '::DS::')
44
+ .replace(/\*/g, '[^/]*')
45
+ .replace(/::DS::/g, '.*')
46
+ .replace(/\?/g, '.') +
47
+ '$';
48
+ return new RegExp(re).test(filePath);
49
+ }
50
+ //# sourceMappingURL=ignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.js","sourceRoot":"","sources":["../../src/scanner/ignore.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,oBAAoB;IACpB,YAAY;IACZ,aAAa;IACb,aAAa;IACb,aAAa;IACb,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,2BAA2B;IAC3B,2BAA2B;IAC3B,8BAA8B;CAC/B,CAAC;AAEF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;AAEzH;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,OAAe;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,qFAAqF;AACrF,2EAA2E;AAC3E,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,QAAkB;IAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAC5C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB,EAAE,OAAe;IAClD,oDAAoD;IACpD,MAAM,EAAE,GACN,GAAG;QACH,OAAO;aACJ,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;aACpC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC;aAC1B,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;aACvB,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;aACxB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;QACtB,GAAG,CAAC;IACN,OAAO,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,50 @@
1
+ export type ActionKind = 'navigation' | 'click' | 'submit' | 'fill';
2
+ export type Confidence = 'high' | 'medium' | 'low';
3
+ export type Intent = 'login' | 'logout' | 'save' | 'back' | 'cancel' | 'delete' | 'search' | 'submit' | 'navigate' | 'fill' | 'click';
4
+ export interface NavigationAction {
5
+ id: string;
6
+ label: string;
7
+ kind: ActionKind;
8
+ intent: Intent;
9
+ targetRoute: string | null;
10
+ selector: string;
11
+ anchorId: string | null;
12
+ inputType: string | null;
13
+ inputName: string | null;
14
+ confidence: Confidence;
15
+ warning: string | null;
16
+ }
17
+ export interface GlobalAction {
18
+ label: string;
19
+ targetRoute: string;
20
+ source: string;
21
+ }
22
+ export interface ScreenMap {
23
+ id: string;
24
+ title: string;
25
+ route: string;
26
+ filePath: string;
27
+ description: string | null;
28
+ actions: NavigationAction[];
29
+ globalActions: GlobalAction[];
30
+ }
31
+ export interface NavEdge {
32
+ from: string;
33
+ to: string;
34
+ label: string;
35
+ }
36
+ export interface NavigationMap {
37
+ screens: ScreenMap[];
38
+ navigationGraph: NavEdge[];
39
+ }
40
+ /**
41
+ * Extrai o mapa de navegação completo do projeto.
42
+ */
43
+ export declare function extractNavigation(rootDir: string, ignorePatterns?: string[], options?: {
44
+ pagesRoutes?: Array<{
45
+ physicalPath: string;
46
+ logicalRoute: string;
47
+ }>;
48
+ srcDir?: string;
49
+ }): Promise<NavigationMap>;
50
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/scanner/navigation.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEnD,MAAM,MAAM,MAAM,GACd,OAAO,GACP,QAAQ,GACR,MAAM,GACN,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,eAAe,EAAE,OAAO,EAAE,CAAC;CAC5B;AAqaD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAAO,EAC7B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACrG,OAAO,CAAC,aAAa,CAAC,CAiFxB"}