@wtdlee/repomap 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/analyzers/index.d.ts +69 -5
  2. package/dist/analyzers/index.js +1 -5
  3. package/dist/{server/doc-server.js → chunk-4K4MGTPV.js} +41 -329
  4. package/dist/chunk-6F4PWJZI.js +0 -0
  5. package/dist/chunk-J2CM7T7U.js +1 -0
  6. package/dist/{generators/page-map-generator.js → chunk-MOEA75XK.js} +278 -503
  7. package/dist/{generators/rails-map-generator.js → chunk-SL2GMDBN.js} +48 -129
  8. package/dist/chunk-UJT5KTVK.js +36 -0
  9. package/dist/chunk-VV3A3UE3.js +1 -0
  10. package/dist/chunk-XWZH2RDG.js +19 -0
  11. package/dist/cli.d.ts +0 -1
  12. package/dist/cli.js +29 -499
  13. package/dist/dataflow-analyzer-BfAiqVUp.d.ts +180 -0
  14. package/dist/env-detector-BIWJ7OYF.js +1 -0
  15. package/dist/generators/assets/common.css +564 -23
  16. package/dist/generators/index.d.ts +431 -3
  17. package/dist/generators/index.js +1 -3
  18. package/dist/index.d.ts +53 -10
  19. package/dist/index.js +1 -11
  20. package/dist/page-map-generator-XNZ4TDJT.js +1 -0
  21. package/dist/rails-TJCDGBBF.js +1 -0
  22. package/dist/rails-map-generator-JL5PKHYP.js +1 -0
  23. package/dist/server/index.d.ts +33 -1
  24. package/dist/server/index.js +1 -1
  25. package/dist/types.d.ts +39 -37
  26. package/dist/types.js +1 -5
  27. package/package.json +4 -2
  28. package/dist/analyzers/base-analyzer.d.ts +0 -45
  29. package/dist/analyzers/base-analyzer.js +0 -47
  30. package/dist/analyzers/dataflow-analyzer.d.ts +0 -29
  31. package/dist/analyzers/dataflow-analyzer.js +0 -425
  32. package/dist/analyzers/graphql-analyzer.d.ts +0 -22
  33. package/dist/analyzers/graphql-analyzer.js +0 -386
  34. package/dist/analyzers/pages-analyzer.d.ts +0 -84
  35. package/dist/analyzers/pages-analyzer.js +0 -1695
  36. package/dist/analyzers/rails/index.d.ts +0 -46
  37. package/dist/analyzers/rails/index.js +0 -145
  38. package/dist/analyzers/rails/rails-controller-analyzer.d.ts +0 -82
  39. package/dist/analyzers/rails/rails-controller-analyzer.js +0 -478
  40. package/dist/analyzers/rails/rails-grpc-analyzer.d.ts +0 -44
  41. package/dist/analyzers/rails/rails-grpc-analyzer.js +0 -262
  42. package/dist/analyzers/rails/rails-model-analyzer.d.ts +0 -88
  43. package/dist/analyzers/rails/rails-model-analyzer.js +0 -493
  44. package/dist/analyzers/rails/rails-react-analyzer.d.ts +0 -41
  45. package/dist/analyzers/rails/rails-react-analyzer.js +0 -529
  46. package/dist/analyzers/rails/rails-routes-analyzer.d.ts +0 -62
  47. package/dist/analyzers/rails/rails-routes-analyzer.js +0 -540
  48. package/dist/analyzers/rails/rails-view-analyzer.d.ts +0 -49
  49. package/dist/analyzers/rails/rails-view-analyzer.js +0 -386
  50. package/dist/analyzers/rails/ruby-parser.d.ts +0 -63
  51. package/dist/analyzers/rails/ruby-parser.js +0 -212
  52. package/dist/analyzers/rest-api-analyzer.d.ts +0 -65
  53. package/dist/analyzers/rest-api-analyzer.js +0 -479
  54. package/dist/core/cache.d.ts +0 -47
  55. package/dist/core/cache.js +0 -151
  56. package/dist/core/engine.d.ts +0 -46
  57. package/dist/core/engine.js +0 -319
  58. package/dist/core/index.d.ts +0 -2
  59. package/dist/core/index.js +0 -2
  60. package/dist/generators/markdown-generator.d.ts +0 -25
  61. package/dist/generators/markdown-generator.js +0 -782
  62. package/dist/generators/mermaid-generator.d.ts +0 -35
  63. package/dist/generators/mermaid-generator.js +0 -364
  64. package/dist/generators/page-map-generator.d.ts +0 -22
  65. package/dist/generators/rails-map-generator.d.ts +0 -21
  66. package/dist/server/doc-server.d.ts +0 -30
  67. package/dist/utils/env-detector.d.ts +0 -31
  68. package/dist/utils/env-detector.js +0 -188
  69. package/dist/utils/parallel.d.ts +0 -23
  70. package/dist/utils/parallel.js +0 -70
  71. package/dist/utils/port.d.ts +0 -15
  72. package/dist/utils/port.js +0 -41
@@ -1,51 +1,15 @@
1
- /**
2
- * Rails Map Generator
3
- * Rails分析結果をインタラクティブなHTMLページとして生成する
4
- */
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
- import { analyzeRailsApp, } from '../analyzers/rails/index.js';
8
- export class RailsMapGenerator {
9
- rootPath;
10
- result = null;
11
- constructor(rootPath) {
12
- this.rootPath = rootPath;
13
- }
14
- async generate(options = {}) {
15
- if (!this.rootPath)
16
- throw new Error('Root path required for analysis');
17
- const { title = 'Rails Application Map' } = options;
18
- // Run analysis
19
- this.result = await analyzeRailsApp(this.rootPath);
20
- // Generate HTML
21
- const html = this.generateHTML(title);
22
- // Save if output path specified
23
- if (options.outputPath) {
24
- fs.writeFileSync(options.outputPath, html);
25
- console.log(`\n📄 Generated: ${options.outputPath}`);
26
- }
27
- return html;
28
- }
29
- // Generate from existing analysis result (for doc-server)
30
- generateFromResult(analysisResult, title = 'Rails Application Map') {
31
- this.result = analysisResult;
32
- return this.generateHTML(title);
33
- }
34
- generateHTML(title) {
35
- if (!this.result)
36
- throw new Error('Analysis not run');
37
- const { routes, controllers, models, grpc, summary } = this.result;
38
- return `<!DOCTYPE html>
1
+ import {k}from'./chunk-UJT5KTVK.js';import*as r from'fs';import*as c from'path';var o=class{constructor(t){this.rootPath=t;}result=null;async generate(t={}){if(!this.rootPath)throw new Error("Root path required for analysis");let{title:e="Rails Application Map"}=t;this.result=await k(this.rootPath);let a=this.generateHTML(e);return t.outputPath&&(r.writeFileSync(t.outputPath,a),console.log(`
2
+ \u{1F4C4} Generated: ${t.outputPath}`)),a}generateFromResult(t,e="Rails Application Map"){return this.result=t,this.generateHTML(e)}generateHTML(t){if(!this.result)throw new Error("Analysis not run");let{routes:e,controllers:a,models:s,grpc:i,summary:l}=this.result;return `<!DOCTYPE html>
39
3
  <html lang="en">
40
4
  <head>
41
5
  <meta charset="UTF-8">
42
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
43
- <title>${title}</title>
7
+ <title>${t}</title>
44
8
  <link rel="stylesheet" href="/rails-map.css">
45
9
  </head>
46
10
  <body>
47
11
  <header>
48
- <h1>🛤️ ${title}</h1>
12
+ <h1>\u{1F6E4}\uFE0F ${t}</h1>
49
13
  <nav class="header-nav">
50
14
  <a href="/page-map" class="nav-link">Page Map</a>
51
15
  <a href="/rails-map" class="nav-link active">Rails Map</a>
@@ -54,31 +18,31 @@ export class RailsMapGenerator {
54
18
  <div class="stats-bar">
55
19
  <div class="stat active" data-view="routes">
56
20
  <div>
57
- <div class="stat-value">${summary.totalRoutes.toLocaleString()}</div>
21
+ <div class="stat-value">${l.totalRoutes.toLocaleString()}</div>
58
22
  <div class="stat-label">Routes</div>
59
23
  </div>
60
24
  </div>
61
25
  <div class="stat" data-view="controllers">
62
26
  <div>
63
- <div class="stat-value">${summary.totalControllers}</div>
27
+ <div class="stat-value">${l.totalControllers}</div>
64
28
  <div class="stat-label">Controllers</div>
65
29
  </div>
66
30
  </div>
67
31
  <div class="stat" data-view="models">
68
32
  <div>
69
- <div class="stat-value">${summary.totalModels}</div>
33
+ <div class="stat-value">${l.totalModels}</div>
70
34
  <div class="stat-label">Models</div>
71
35
  </div>
72
36
  </div>
73
37
  <div class="stat" data-view="grpc">
74
38
  <div>
75
- <div class="stat-value">${summary.totalGrpcServices}</div>
39
+ <div class="stat-value">${l.totalGrpcServices}</div>
76
40
  <div class="stat-label">gRPC</div>
77
41
  </div>
78
42
  </div>
79
43
  <div class="stat" data-view="diagram">
80
44
  <div>
81
- <div class="stat-value">📊</div>
45
+ <div class="stat-value">\u{1F4CA}</div>
82
46
  <div class="stat-label">Diagram</div>
83
47
  </div>
84
48
  </div>
@@ -93,31 +57,31 @@ export class RailsMapGenerator {
93
57
  </div>
94
58
 
95
59
  <div class="sidebar-section namespaces" id="namespaceFilter">
96
- <div class="sidebar-title">Namespaces (${summary.namespaces.length})</div>
60
+ <div class="sidebar-title">Namespaces (${l.namespaces.length})</div>
97
61
  <div class="namespace-list">
98
62
  <div class="namespace-item active" data-namespace="all">
99
63
  <span>All</span>
100
- <span class="namespace-count">${routes.routes.length}</span>
64
+ <span class="namespace-count">${e.routes.length}</span>
101
65
  </div>
102
- ${this.generateNamespaceList(routes.routes)}
66
+ ${this.generateNamespaceList(e.routes)}
103
67
  </div>
104
68
  </div>
105
69
 
106
70
  <div class="sidebar-section" id="methodFilter">
107
71
  <div class="sidebar-title">HTTP Methods</div>
108
72
  <div class="namespace-list methods-list">
109
- ${this.generateMethodFilters(routes.routes)}
73
+ ${this.generateMethodFilters(e.routes)}
110
74
  </div>
111
75
  </div>
112
76
  </aside>
113
77
 
114
78
  <main class="main-panel" id="mainPanel">
115
- ${this.generateRoutesView(routes.routes)}
79
+ ${this.generateRoutesView(e.routes)}
116
80
  </main>
117
81
 
118
82
  <aside class="detail-panel" id="detailPanel">
119
83
  <div class="empty-state">
120
- <div class="empty-state-icon">👆</div>
84
+ <div class="empty-state-icon">\u{1F446}</div>
121
85
  <div>Select an item to view details</div>
122
86
  </div>
123
87
  </aside>
@@ -125,10 +89,10 @@ export class RailsMapGenerator {
125
89
 
126
90
  <script>
127
91
  // Data
128
- const routes = ${JSON.stringify(routes.routes)};
129
- const controllers = ${JSON.stringify(controllers.controllers)};
130
- const models = ${JSON.stringify(models.models)};
131
- const grpcServices = ${JSON.stringify(grpc.services)};
92
+ const routes = ${JSON.stringify(e.routes)};
93
+ const controllers = ${JSON.stringify(a.controllers)};
94
+ const models = ${JSON.stringify(s.models)};
95
+ const grpcServices = ${JSON.stringify(i.services)};
132
96
 
133
97
  // State
134
98
  let currentView = 'routes';
@@ -399,9 +363,9 @@ export class RailsMapGenerator {
399
363
  <div class="controller-header">
400
364
  <div>
401
365
  <div class="controller-name">\${ctrl.className}</div>
402
- <div class="controller-namespace">\${ctrl.namespace || 'root'} \${ctrl.actions.length} actions</div>
366
+ <div class="controller-namespace">\${ctrl.namespace || 'root'} \u2022 \${ctrl.actions.length} actions</div>
403
367
  </div>
404
- <span>▶</span>
368
+ <span>\u25B6</span>
405
369
  </div>
406
370
  <div class="controller-actions">
407
371
  \${ctrl.actions.map(action => \`
@@ -496,11 +460,11 @@ export class RailsMapGenerator {
496
460
  \${displayedGrpc.map((svc, idx) => \`
497
461
  <div class="model-card" onclick="showGrpcDetail(\${idx})">
498
462
  <div class="model-name">
499
- 🔌 \${svc.className || 'Unknown'}
463
+ \u{1F50C} \${svc.className || 'Unknown'}
500
464
  </div>
501
465
  <div class="model-stats">
502
- \${svc.namespace ? \`<span>📁 \${svc.namespace}</span>\` : ''}
503
- <span>⚡ \${svc.rpcs ? svc.rpcs.length : 0} RPCs</span>
466
+ \${svc.namespace ? \`<span>\u{1F4C1} \${svc.namespace}</span>\` : ''}
467
+ <span>\u26A1 \${svc.rpcs ? svc.rpcs.length : 0} RPCs</span>
504
468
  </div>
505
469
  </div>
506
470
  \`).join('')}
@@ -525,8 +489,8 @@ export class RailsMapGenerator {
525
489
 
526
490
  let detail = \`
527
491
  <div class="detail-header">
528
- <div class="detail-title">🔌 \${svc.className || 'gRPC Service'}</div>
529
- <button class="close-btn" onclick="closeDetail()">×</button>
492
+ <div class="detail-title">\u{1F50C} \${svc.className || 'gRPC Service'}</div>
493
+ <button class="close-btn" onclick="closeDetail()">\xD7</button>
530
494
  </div>
531
495
  <div class="detail-content">
532
496
  <div class="detail-section">
@@ -683,7 +647,7 @@ export class RailsMapGenerator {
683
647
  detailPanel.innerHTML = \`
684
648
  <div class="detail-header">
685
649
  <div class="detail-title">Route Details</div>
686
- <button class="close-btn" onclick="clearDetail()">×</button>
650
+ <button class="close-btn" onclick="clearDetail()">\xD7</button>
687
651
  </div>
688
652
  <div class="detail-content">
689
653
  <div class="detail-section">
@@ -715,7 +679,7 @@ export class RailsMapGenerator {
715
679
  detailPanel.innerHTML = \`
716
680
  <div class="detail-header">
717
681
  <div class="detail-title">Controller Details</div>
718
- <button class="close-btn" onclick="clearDetail()">×</button>
682
+ <button class="close-btn" onclick="clearDetail()">\xD7</button>
719
683
  </div>
720
684
  <div class="detail-content">
721
685
  <div class="detail-section">
@@ -759,7 +723,7 @@ export class RailsMapGenerator {
759
723
  detailPanel.innerHTML = \`
760
724
  <div class="detail-header">
761
725
  <div class="detail-title">Model Details</div>
762
- <button class="close-btn" onclick="clearDetail()">×</button>
726
+ <button class="close-btn" onclick="clearDetail()">\xD7</button>
763
727
  </div>
764
728
  <div class="detail-content">
765
729
  <div class="detail-section">
@@ -816,7 +780,7 @@ export class RailsMapGenerator {
816
780
  function clearDetail() {
817
781
  detailPanel.innerHTML = \`
818
782
  <div class="empty-state">
819
- <div class="empty-state-icon">👆</div>
783
+ <div class="empty-state-icon">\u{1F446}</div>
820
784
  <div>Select an item to view details</div>
821
785
  </div>
822
786
  \`;
@@ -827,43 +791,19 @@ export class RailsMapGenerator {
827
791
  renderMainPanel();
828
792
  </script>
829
793
  </body>
830
- </html>`;
831
- }
832
- generateNamespaceList(routes) {
833
- const namespaces = new Map();
834
- for (const route of routes) {
835
- const ns = route.namespace || 'root';
836
- namespaces.set(ns, (namespaces.get(ns) || 0) + 1);
837
- }
838
- const sorted = [...namespaces.entries()].sort((a, b) => b[1] - a[1]);
839
- return sorted
840
- .map(([ns, count]) => `
841
- <div class="namespace-item" data-namespace="${ns === 'root' ? '' : ns}">
842
- <span>${ns}</span>
843
- <span class="namespace-count">${count}</span>
794
+ </html>`}generateNamespaceList(t){let e=new Map;for(let s of t){let i=s.namespace||"root";e.set(i,(e.get(i)||0)+1);}return [...e.entries()].sort((s,i)=>i[1]-s[1]).map(([s,i])=>`
795
+ <div class="namespace-item" data-namespace="${s==="root"?"":s}">
796
+ <span>${s}</span>
797
+ <span class="namespace-count">${i}</span>
844
798
  </div>
845
- `)
846
- .join('');
847
- }
848
- generateMethodFilters(routes) {
849
- const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
850
- const counts = new Map();
851
- for (const route of routes) {
852
- counts.set(route.method, (counts.get(route.method) || 0) + 1);
853
- }
854
- return methods
855
- .map((method) => `
856
- <div class="namespace-item" data-method="${method}">
857
- <span class="method-badge method-${method}">${method}</span>
858
- <span class="namespace-count">${counts.get(method) || 0}</span>
799
+ `).join("")}generateMethodFilters(t){let e=["GET","POST","PUT","PATCH","DELETE"],a=new Map;for(let s of t)a.set(s.method,(a.get(s.method)||0)+1);return e.map(s=>`
800
+ <div class="namespace-item" data-method="${s}">
801
+ <span class="method-badge method-${s}">${s}</span>
802
+ <span class="namespace-count">${a.get(s)||0}</span>
859
803
  </div>
860
- `)
861
- .join('');
862
- }
863
- generateRoutesView(routes) {
864
- return `
804
+ `).join("")}generateRoutesView(t){return `
865
805
  <div class="panel-header">
866
- <div class="panel-title">Routes (${routes.length})</div>
806
+ <div class="panel-title">Routes (${t.length})</div>
867
807
  </div>
868
808
  <table class="routes-table">
869
809
  <thead>
@@ -874,35 +814,14 @@ export class RailsMapGenerator {
874
814
  </tr>
875
815
  </thead>
876
816
  <tbody>
877
- ${routes
878
- .slice(0, 200)
879
- .map((route, idx) => `
880
- <tr data-type="route" data-index="${idx}">
881
- <td><span class="method-badge method-${route.method}">${route.method}</span></td>
882
- <td class="path-text">${this.highlightParams(route.path)}</td>
883
- <td class="controller-text">${route.controller}#${route.action}</td>
817
+ ${t.slice(0,200).map((e,a)=>`
818
+ <tr data-type="route" data-index="${a}">
819
+ <td><span class="method-badge method-${e.method}">${e.method}</span></td>
820
+ <td class="path-text">${this.highlightParams(e.path)}</td>
821
+ <td class="controller-text">${e.controller}#${e.action}</td>
884
822
  </tr>
885
- `)
886
- .join('')}
823
+ `).join("")}
887
824
  </tbody>
888
825
  </table>
889
- `;
890
- }
891
- highlightParams(path) {
892
- return path.replace(/:([a-zA-Z_]+)/g, '<span class="param">:$1</span>');
893
- }
894
- }
895
- // Standalone execution
896
- async function main() {
897
- const targetPath = process.argv[2] || process.cwd();
898
- const outputPath = process.argv[3] || path.join(targetPath, 'rails-map.html');
899
- const generator = new RailsMapGenerator(targetPath);
900
- await generator.generate({
901
- title: 'Rails Application Map',
902
- outputPath,
903
- });
904
- }
905
- const isMainModule = import.meta.url === `file://${process.argv[1]}`;
906
- if (isMainModule) {
907
- main().catch(console.error);
908
- }
826
+ `}highlightParams(t){return t.replace(/:([a-zA-Z_]+)/g,'<span class="param">:$1</span>')}};async function m(){let n=process.argv[2]||process.cwd(),t=process.argv[3]||c.join(n,"rails-map.html");await new o(n).generate({title:"Rails Application Map",outputPath:t});}var p=import.meta.url===`file://${process.argv[1]}`;p&&m().catch(console.error);
827
+ export{o as a};
@@ -0,0 +1,36 @@
1
+ import*as L from'fs';import*as x from'path';import {Parser,Language}from'web-tree-sitter';import {fileURLToPath}from'url';import {glob}from'glob';import*as A from'fs/promises';var ue=fileURLToPath(import.meta.url),te=x.dirname(ue),se=false,O=null,D=null;async function ne(){if(D&&O)return D;se||(await Parser.init(),se=true),D=new Parser;let l=[x.join(process.cwd(),"node_modules/tree-sitter-wasms/out/tree-sitter-ruby.wasm"),x.join(te,"../../../node_modules/tree-sitter-wasms/out/tree-sitter-ruby.wasm"),x.join(te,"../../../../tree-sitter-wasms/out/tree-sitter-ruby.wasm")],t=null;for(let e of l)if(L.existsSync(e)){t=e;break}if(!t)throw new Error("tree-sitter-ruby.wasm not found. Please install tree-sitter-wasms package.");return O=await Language.load(t),D.setLanguage(O),D}async function oe(l){let e=(await ne()).parse(l);if(!e)throw new Error("Failed to parse Ruby code");return e}async function N(l){let t=L.readFileSync(l,"utf-8");return oe(t)}function R(l,t){let e=[];l.type===t&&e.push(l);for(let o=0;o<l.childCount;o++){let s=l.child(o);s&&e.push(...R(s,t));}return e}function G(l,t){for(let e=0;e<l.childCount;e++){let o=l.child(e);if(o&&o.type===t)return o}return null}function w(l,t){let e=[];for(let o=0;o<l.childCount;o++){let s=l.child(o);s&&s.type===t&&e.push(s);}return e}function S(l){let t=l.childForFieldName("arguments");if(!t)return [];let e=[];for(let o=0;o<t.childCount;o++){let s=t.child(o);s&&s.type!=="("&&s.type!==")"&&s.type!==","&&e.push(s);}return e}function F(l){let t=l.childForFieldName("name");return t?t.text:null}function M(l){let t=l.childForFieldName("superclass");if(!t)return null;let e=G(t,"constant")||G(t,"scope_resolution");return e?e.text:null}function U(l){let t=l.childForFieldName("name");return t?t.text:null}function Z(l){let t=l.childForFieldName("parameters");if(!t)return [];let e=[];for(let o=0;o<t.childCount;o++){let s=t.child(o);if(s&&(s.type==="identifier"||s.type==="keyword_parameter"||s.type==="optional_parameter"||s.type==="splat_parameter")){let n=s.childForFieldName("name")||s;n.type==="identifier"?e.push(n.text):e.push(s.text);}}return e}var k=class{constructor(t){this.rootPath=t;this.routesDir=x.join(t,"config","routes");}routesDir;routes=[];namespaces=[];resources=[];mountedEngines=[];drawnFiles=[];errors=[];async analyze(){let t=x.join(this.rootPath,"config","routes.rb");if(!L.existsSync(t))return {routes:[],namespaces:[],resources:[],mountedEngines:[],drawnFiles:[],errors:[`routes.rb not found at ${t}`]};try{await this.parseRoutesFile(t,[]);}catch(e){this.errors.push(`Error parsing ${t}: ${e}`);}return {routes:this.routes,namespaces:[...new Set(this.namespaces)],resources:this.resources,mountedEngines:this.mountedEngines,drawnFiles:this.drawnFiles,errors:this.errors}}async parseRoutesFile(t,e){let s=(await N(t)).rootNode,n=R(s,"call");for(let r of n){let a=r.childForFieldName("method");if(!a)continue;let c=a.text,i=r.startPosition.row+1;switch(c){case "get":case "post":case "put":case "patch":case "delete":case "match":this.parseHttpRoute(r,c,e,i);break;case "resources":case "resource":await this.parseResources(r,e,i,c==="resource");break;case "namespace":await this.parseNamespace(r,e,t);break;case "mount":this.parseMount(r,i);break;case "draw":await this.parseDraw(r,e);break;case "devise_for":this.parseDeviseFor(r,e,i);break;case "root":this.parseRoot(r,e,i);break}}}parseHttpRoute(t,e,o,s){let n=S(t);if(n.length===0)return;let r=n[0],a=this.extractStringValue(r);if(!a)return;let c="",i="";for(let u of n)if(u.type==="hash"||u.type==="pair"){let m=u.type==="hash"?w(u,"pair"):[u];for(let d of m){let y=d.child(0)?.text?.replace(/^:/,""),f=d.child(2);if(y==="to"&&f){let g=this.extractStringValue(f);g&&g.includes("#")&&([c,i]=g.split("#"));}}}else if(u.type==="string"||u.type==="string_content"){let m=this.extractStringValue(u);m&&m.includes("#")&&!c&&([c,i]=m.split("#"));}if(!c&&!i){let u=a.replace(/^\//,"").split("/");c=u[0]||"",i=u[1]||"index";}o.length>0&&c&&!c.includes("/")&&(c=`${o.join("/")}/${c}`);let p=this.buildPath(o,a);this.routes.push({method:e==="match"?"ALL":e.toUpperCase(),path:p,controller:c,action:i,namespace:o.join("/")||void 0,line:s});}async parseResources(t,e,o,s){let n=S(t);if(n.length===0)return;let a=n[0].text.replace(/^:/,""),c={name:a,controller:e.length>0?`${e.join("/")}/${a}`:a,nested:[],memberRoutes:[],collectionRoutes:[],line:o};for(let p of n)if(p.type==="hash"){let u=w(p,"pair");for(let m of u){let d=m.child(0)?.text?.replace(/^:/,""),y=m.child(2);d==="only"&&y?c.only=this.extractArrayValues(y):d==="except"&&y&&(c.except=this.extractArrayValues(y));}}this.generateResourceRoutes(c,e,s),this.resources.push(c);let i=t.childForFieldName("block");if(i){let p=R(i,"call");for(let u of p){let m=u.childForFieldName("method")?.text;if(m==="member"){let d=u.childForFieldName("block");d&&this.parseMemberCollectionRoutes(d,c,e,"member");}else if(m==="collection"){let d=u.childForFieldName("block");d&&this.parseMemberCollectionRoutes(d,c,e,"collection");}}}}parseMemberCollectionRoutes(t,e,o,s){let n=R(t,"call");for(let r of n){let a=r.childForFieldName("method");if(!a)continue;let c=a.text;if(!["get","post","put","patch","delete"].includes(c))continue;let i=S(r);if(i.length===0)continue;let p=i[0].text.replace(/^:/,""),u=s==="member"?`/${e.name}/:id/${p}`:`/${e.name}/${p}`,m={method:c.toUpperCase(),path:this.buildPath(o,u),controller:e.controller,action:p,namespace:o.join("/")||void 0,line:r.startPosition.row+1};s==="member"?e.memberRoutes.push(m):e.collectionRoutes.push(m),this.routes.push(m);}}async parseNamespace(t,e,o){let s=S(t);if(s.length===0)return;let n=s[0].text.replace(/^:/,"");this.namespaces.push(n);let r=[...e,n],a=t.childForFieldName("block");if(a){let c=R(a,"call");for(let i of c){let p=i.childForFieldName("method");if(!p)continue;let u=p.text,m=i.startPosition.row+1;switch(u){case "get":case "post":case "put":case "patch":case "delete":case "match":this.parseHttpRoute(i,u,r,m);break;case "resources":case "resource":await this.parseResources(i,r,m,u==="resource");break;case "draw":await this.parseDraw(i,r);break}}}}parseMount(t,e){let o=S(t);if(o.length===0)return;let n=o[0].text,r="/";for(let a of o)if(a.type==="hash"||a.type==="pair"){let c=a.type==="hash"?w(a,"pair"):[a];for(let i of c){let p=i.child(0)?.text?.replace(/^:/,""),u=i.child(2);p==="at"&&u&&(r=this.extractStringValue(u)||r);}}else if(a.type==="string"){let c=this.extractStringValue(a);c&&c.startsWith("/")&&(r=c);}this.mountedEngines.push({engine:n,mountPath:r,line:e});}async parseDraw(t,e){let o=S(t);if(o.length===0)return;let s=o[0].text.replace(/^:/,""),n=x.join(this.routesDir,`${s}.rb`);if(L.existsSync(n)){this.drawnFiles.push(n);try{await this.parseRoutesFile(n,e);}catch(r){this.errors.push(`Error parsing drawn file ${n}: ${r}`);}}}parseDeviseFor(t,e,o){let s=S(t);if(s.length===0)return;let n=s[0].text.replace(/^:/,""),r=[{method:"GET",path:`/${n}/sign_in`,action:"new",controller:"devise/sessions"},{method:"POST",path:`/${n}/sign_in`,action:"create",controller:"devise/sessions"},{method:"DELETE",path:`/${n}/sign_out`,action:"destroy",controller:"devise/sessions"},{method:"GET",path:`/${n}/password/new`,action:"new",controller:"devise/passwords"},{method:"POST",path:`/${n}/password`,action:"create",controller:"devise/passwords"},{method:"GET",path:`/${n}/sign_up`,action:"new",controller:"devise/registrations"},{method:"POST",path:`/${n}`,action:"create",controller:"devise/registrations"}];for(let a of r)this.routes.push({method:a.method,path:this.buildPath(e,a.path),controller:a.controller,action:a.action,namespace:e.join("/")||void 0,line:o,authenticated:false});}parseRoot(t,e,o){let s=S(t),n="",r="index";for(let a of s)if(a.type==="string"){let c=this.extractStringValue(a);c&&c.includes("#")&&([n,r]=c.split("#"));}else if(a.type==="hash"||a.type==="pair"){let c=a.type==="hash"?w(a,"pair"):[a];for(let i of c){let p=i.child(0)?.text?.replace(/^:/,""),u=i.child(2);if(p==="to"&&u){let m=this.extractStringValue(u);m&&m.includes("#")&&([n,r]=m.split("#"));}}}n&&this.routes.push({method:"GET",path:this.buildPath(e,"/"),controller:n,action:r,namespace:e.join("/")||void 0,line:o});}generateResourceRoutes(t,e,o){let s=this.buildPath(e,`/${t.name}`),n=o?["show","new","create","edit","update","destroy"]:["index","show","new","create","edit","update","destroy"],r=t.only||(t.except?n.filter(i=>!t.except.includes(i)):n),a=[];o||r.includes("index")&&a.push({method:"GET",path:s,action:"index"}),r.includes("new")&&a.push({method:"GET",path:`${s}/new`,action:"new"}),r.includes("create")&&a.push({method:"POST",path:s,action:"create"});let c=o?s:`${s}/:id`;r.includes("show")&&a.push({method:"GET",path:c,action:"show"}),r.includes("edit")&&a.push({method:"GET",path:`${c}/edit`,action:"edit"}),r.includes("update")&&(a.push({method:"PUT",path:c,action:"update"}),a.push({method:"PATCH",path:c,action:"update"})),r.includes("destroy")&&a.push({method:"DELETE",path:c,action:"destroy"});for(let i of a)this.routes.push({method:i.method,path:i.path,controller:t.controller,action:i.action,namespace:e.join("/")||void 0,line:t.line});}buildPath(t,e){return e.startsWith("/")?e:`${t.length>0?`/${t.join("/")}`:""}/${e}`}extractStringValue(t){if(t.type==="string"){let e=G(t,"string_content");return e?e.text:t.text.replace(/^["']|["']$/g,"")}return t.type==="string_content"?t.text:t.type==="simple_symbol"||t.type==="symbol"?t.text.replace(/^:/,""):t.text.replace(/^["']|["']$/g,"")}extractArrayValues(t){let e=[];if(t.type==="array")for(let o=0;o<t.childCount;o++){let s=t.child(o);if(s&&s.type!=="["&&s.type!=="]"&&s.type!==","){let n=this.extractStringValue(s);n&&e.push(n);}}else {let o=this.extractStringValue(t);o&&e.push(o);}return e}};async function me(){let l=process.argv[2]||process.cwd();console.log(`Analyzing routes in: ${l}`);let e=await new k(l).analyze();if(console.log(`
2
+ === Rails Routes Analysis ===
3
+ `),console.log(`Total routes: ${e.routes.length}`),console.log(`Namespaces: ${e.namespaces.join(", ")||"(none)"}`),console.log(`Resources: ${e.resources.length}`),console.log(`Mounted engines: ${e.mountedEngines.length}`),console.log(`External route files: ${e.drawnFiles.length}`),e.errors.length>0){console.log(`
4
+ --- Errors ---`);for(let o of e.errors)console.log(` \u274C ${o}`);}console.log(`
5
+ --- Sample Routes (first 30) ---`);for(let o of e.routes.slice(0,30))console.log(` ${o.method.padEnd(7)} ${o.path.padEnd(50)} => ${o.controller}#${o.action}`);console.log(`
6
+ --- Mounted Engines ---`);for(let o of e.mountedEngines)console.log(` ${o.engine} => ${o.mountPath}`);console.log(`
7
+ --- External Route Files ---`);for(let o of e.drawnFiles)console.log(` ${x.basename(o)}`);}var de=import.meta.url===`file://${process.argv[1]}`;de&&me().catch(console.error);var V=class{constructor(t){this.rootPath=t;this.controllersDir=x.join(t,"app","controllers");}controllersDir;controllers=[];errors=[];async analyze(){if(!L.existsSync(this.controllersDir))return {controllers:[],totalActions:0,namespaces:[],concerns:[],errors:[`Controllers directory not found at ${this.controllersDir}`]};let t=await glob("**/*_controller.rb",{cwd:this.controllersDir,ignore:["concerns/**"]});for(let n of t){let r=x.join(this.controllersDir,n);try{let a=await this.parseControllerFile(r,n);a&&this.controllers.push(a);}catch(a){this.errors.push(`Error parsing ${n}: ${a}`);}}let e=[...new Set(this.controllers.filter(n=>n.namespace).map(n=>n.namespace))],o=[...new Set(this.controllers.flatMap(n=>n.concerns))],s=this.controllers.reduce((n,r)=>n+r.actions.length,0);return {controllers:this.controllers,totalActions:s,namespaces:e,concerns:o,errors:this.errors}}async parseControllerFile(t,e){let s=(await N(t)).rootNode,n=e.replace(/_controller\.rb$/,"").split("/"),r=n.length>1?n.slice(0,-1).join("/"):void 0,a=n[n.length-1],c=R(s,"class");if(c.length===0)return null;let i=c[0],p=F(i),u=M(i);if(!p)return null;let m={name:a,filePath:e,className:p,parentClass:u||"ApplicationController",namespace:r,actions:[],beforeActions:[],afterActions:[],aroundActions:[],skipBeforeActions:[],concerns:[],helpers:[],rescueFrom:[],line:i.startPosition.row+1},d=R(i,"call");for(let h of d){let b=h.childForFieldName("method");if(!b)continue;let v=b.text,C=h.startPosition.row+1;switch(v){case "before_action":case "before_filter":this.parseFilter(h,m.beforeActions,C);break;case "after_action":case "after_filter":this.parseFilter(h,m.afterActions,C);break;case "around_action":case "around_filter":this.parseFilter(h,m.aroundActions,C);break;case "skip_before_action":case "skip_before_filter":this.parseFilter(h,m.skipBeforeActions,C);break;case "include":this.parseInclude(h,m.concerns);break;case "helper":this.parseHelper(h,m.helpers);break;case "layout":m.layoutInfo=this.parseLayout(h);break;case "rescue_from":this.parseRescueFrom(h,m.rescueFrom,C);break}}R(i,"method");let f="public",g=i.childForFieldName("body");if(g)for(let h=0;h<g.childCount;h++){let b=g.child(h);if(b){if(b.type==="identifier"){let v=b.text;v==="private"?f="private":v==="protected"?f="protected":v==="public"&&(f="public");}else if(b.type==="method"){let v=this.parseMethod(b,f);v&&m.actions.push(v);}}}return m}parseFilter(t,e,o){let s=this.getCallArguments(t);if(s.length===0)return;let a={name:s[0].text.replace(/^:/,""),line:o};for(let c of s.slice(1))if(c.type==="hash"){let i=w(c,"pair");for(let p of i){let u=p.child(0)?.text?.replace(/^:/,""),m=p.child(2);if(!(!u||!m))switch(u){case "only":a.only=this.extractArrayValues(m);break;case "except":a.except=this.extractArrayValues(m);break;case "if":a.if=m.text;break;case "unless":a.unless=m.text;break}}}e.push(a);}parseInclude(t,e){let o=this.getCallArguments(t);for(let s of o)(s.type==="constant"||s.type==="scope_resolution")&&e.push(s.text);}parseHelper(t,e){let o=this.getCallArguments(t);for(let s of o){let n=s.text.replace(/^:/,"");e.push(n);}}parseLayout(t){let e=this.getCallArguments(t);if(e.length===0)return;let o=e[0],s=o.text.replace(/^["']|["']$/g,"");s.startsWith(":")&&(s=s.substring(1)),(o.type==="lambda"||o.type==="proc")&&(s="(dynamic)");let n={name:s};for(let r of e.slice(1))r.type==="hash"&&(n.conditions=r.text);return n}parseRescueFrom(t,e,o){let s=this.getCallArguments(t);if(s.length===0)return;let n=s[0].text,r="unknown";for(let a of s.slice(1))if(a.type==="hash"||a.type==="pair"){let c=a.type==="hash"?w(a,"pair"):[a];for(let i of c){let p=i.child(0)?.text?.replace(/^:/,""),u=i.child(2);p==="with"&&u&&(r=u.text.replace(/^:/,""));}}e.push({exception:n,handler:r,line:o});}parseMethod(t,e){let o=U(t);if(!o||t.text.includes("def self."))return null;let s={name:o,line:t.startPosition.row+1,visibility:e,parameters:Z(t),servicesCalled:[],modelsCalled:[],methodCalls:[],instanceVarAssignments:[]},n=t.text,r=/@([a-z_][a-z0-9_]*)\s*=\s*([^\n]+)/gi,a;for(;(a=r.exec(n))!==null;){let p=a[1],u=a[2].trim().slice(0,100),m,d=u.match(/^([A-Z][a-zA-Z0-9]+)\.(find|find_by|find_by!|where|all|first|last|new|create|create!|build)/);d&&(m=d[1]);let y=u.match(/^@([a-z_]+)\.([a-z_]+)/);y&&!m&&(m=`${y[1]}.${y[2]}`);let f=u.match(/^current_([a-z_]+)/);f&&!m&&(m=f[1].charAt(0).toUpperCase()+f[1].slice(1));let g=u.match(/^([A-Z][a-zA-Z0-9]+Service)\.(call|new|perform)/);g&&!m&&(m=`Service:${g[1]}`),s.instanceVarAssignments&&s.instanceVarAssignments.push({name:p,assignedType:m,assignedValue:u.length>60?u.slice(0,57)+"...":u});}(n.includes("render json:")||n.includes("render :json"))&&(s.rendersJson=true),n.includes("render")&&!s.rendersJson&&(s.rendersHtml=true);let c=n.match(/redirect_to\s+([^,\n]+)/);if(c&&(s.redirectsTo=c[1].trim()),n.includes("respond_to")){let p=[];n.includes("format.html")&&p.push("html"),n.includes("format.json")&&p.push("json"),n.includes("format.xml")&&p.push("xml"),n.includes("format.js")&&p.push("js"),n.includes("format.csv")&&p.push("csv"),n.includes("format.pdf")&&p.push("pdf"),p.length>0&&(s.respondsTo=p);}let i=R(t,"call");for(let p of i){let u=p.childForFieldName("receiver"),m=p.childForFieldName("method");if(u&&m){let d=u.text,y=m.text;d.endsWith("Service")&&["call","new","perform","execute"].includes(y)&&(s.servicesCalled.includes(d)||s.servicesCalled.push(d));let f=["find","find_by","find_by!","where","all","first","last","create","create!","new","update","update!","destroy","delete"];/^[A-Z][a-zA-Z]+$/.test(d)&&f.includes(y)&&(["Rails","ActiveRecord","ActionController","ApplicationRecord"].includes(d)||s.modelsCalled.includes(d)||s.modelsCalled.push(d)),s.methodCalls.push(`${d}.${y}`);}else m&&!u&&s.methodCalls.push(m.text);}return s}getCallArguments(t){let e=t.childForFieldName("arguments");if(!e){let s=[];for(let n=0;n<t.childCount;n++){let r=t.child(n);r&&!["identifier","(",")",",","call"].includes(r.type)&&r!==t.childForFieldName("method")&&r!==t.childForFieldName("receiver")&&s.push(r);}return s}let o=[];for(let s=0;s<e.childCount;s++){let n=e.child(s);n&&n.type!=="("&&n.type!==")"&&n.type!==","&&o.push(n);}return o}extractArrayValues(t){let e=[];if(t.type==="array")for(let o=0;o<t.childCount;o++){let s=t.child(o);s&&s.type!=="["&&s.type!=="]"&&s.type!==","&&e.push(s.text.replace(/^:/,""));}else e.push(t.text.replace(/^:/,""));return e}};async function he(){let l=process.argv[2]||process.cwd();console.log(`Analyzing controllers in: ${l}`);let e=await new V(l).analyze();if(console.log(`
8
+ === Rails Controllers Analysis ===
9
+ `),console.log(`Total controllers: ${e.controllers.length}`),console.log(`Total actions: ${e.totalActions}`),console.log(`Namespaces: ${e.namespaces.join(", ")||"(none)"}`),console.log(`Shared concerns: ${e.concerns.length}`),e.errors.length>0){console.log(`
10
+ --- Errors (${e.errors.length}) ---`);for(let n of e.errors.slice(0,5))console.log(` \u274C ${n}`);e.errors.length>5&&console.log(` ... and ${e.errors.length-5} more`);}console.log(`
11
+ --- Sample Controllers (first 10) ---`);for(let n of e.controllers.slice(0,10))console.log(`
12
+ \u{1F4C1} ${n.className} (${n.filePath})`),console.log(` Parent: ${n.parentClass}`),console.log(` Actions (${n.actions.length}): ${n.actions.map(r=>r.name).slice(0,5).join(", ")}${n.actions.length>5?"...":""}`),n.beforeActions.length>0&&console.log(` Before: ${n.beforeActions.map(r=>r.name).join(", ")}`),n.concerns.length>0&&console.log(` Concerns: ${n.concerns.join(", ")}`);let o=e.controllers.flatMap(n=>n.actions.filter(r=>r.visibility==="public")),s=e.controllers.flatMap(n=>n.actions.filter(r=>r.visibility==="private"));console.log(`
13
+ --- Action Visibility Summary ---`),console.log(` Public: ${o.length}`),console.log(` Private: ${s.length}`);}var ge=import.meta.url===`file://${process.argv[1]}`;ge&&he().catch(console.error);var j=class{constructor(t){this.rootPath=t;this.modelsDir=x.join(t,"app","models");}modelsDir;models=[];errors=[];async analyze(){if(!L.existsSync(this.modelsDir))return {models:[],totalAssociations:0,totalValidations:0,concerns:[],namespaces:[],errors:[`Models directory not found at ${this.modelsDir}`]};let t=await glob("**/*.rb",{cwd:this.modelsDir,ignore:["concerns/**","application_record.rb"]});for(let r of t){let a=x.join(this.modelsDir,r);try{let c=await this.parseModelFile(a,r);c&&this.models.push(c);}catch(c){this.errors.push(`Error parsing ${r}: ${c}`);}}let e=[...new Set(this.models.flatMap(r=>r.concerns))],o=[...new Set(this.models.map(r=>{let a=r.filePath.split("/");return a.length>1?a.slice(0,-1).join("/"):null}).filter(r=>r!==null))],s=this.models.reduce((r,a)=>r+a.associations.length,0),n=this.models.reduce((r,a)=>r+a.validations.length,0);return {models:this.models,totalAssociations:s,totalValidations:n,concerns:e,namespaces:o,errors:this.errors}}async parseModelFile(t,e){let s=(await N(t)).rootNode,n=R(s,"class");if(n.length===0)return null;let r=n[0],a=F(r),c=M(r);if(!a)return null;c&&this.isActiveRecordModel(c);let i={name:a.replace(/.*::/,""),filePath:e,className:a,parentClass:c||"ApplicationRecord",associations:[],validations:[],callbacks:[],scopes:[],concerns:[],enums:[],attributes:[],classMethodsCount:0,instanceMethodsCount:0,line:r.startPosition.row+1};i.tableName=this.parseTableName(r);let p=R(r,"call");for(let d of p){let y=d.childForFieldName("method");if(!y)continue;let f=y.text,g=d.startPosition.row+1;["belongs_to","has_one","has_many","has_and_belongs_to_many"].includes(f)?this.parseAssociation(d,f,i.associations,g):f.startsWith("validates")||f==="validate"?this.parseValidation(d,f,i.validations,g):this.isCallback(f)?this.parseCallback(d,f,i.callbacks,g):f==="scope"?this.parseScope(d,i.scopes,g):f==="include"?this.parseInclude(d,i.concerns):f==="enum"?this.parseEnum(d,i.enums,g):f==="attribute"&&this.parseAttribute(d,i.attributes,g);}let u=R(r,"method"),m=R(r,"singleton_method");return i.instanceMethodsCount=u.length,i.classMethodsCount=m.length,i}isActiveRecordModel(t){return ["ApplicationRecord","ActiveRecord::Base","ActiveRecord"].some(o=>t.includes(o))}parseTableName(t){let e=R(t,"call");for(let s of e)if(s.childForFieldName("method")?.text==="table_name="){let r=this.getCallArguments(s);if(r.length>0)return r[0].text.replace(/^["']|["']$/g,"")}let o=R(t,"assignment");for(let s of o)if(s.child(0)?.text?.includes("table_name")){let r=s.child(2);if(r)return r.text.replace(/^["']|["']$/g,"")}}parseAssociation(t,e,o,s){let n=this.getCallArguments(t);if(n.length===0)return;let a=n[0].text.replace(/^:/,""),c={type:e,name:a,line:s};for(let i of n.slice(1))if(i.type==="hash"){let p=w(i,"pair");for(let u of p){let m=u.child(0)?.text?.replace(/^:/,""),d=u.child(2);if(!(!m||!d))switch(m){case "class_name":c.className=d.text.replace(/^["']|["']$/g,"");break;case "foreign_key":c.foreignKey=d.text.replace(/^["']|["']$/g,"").replace(/^:/,"");break;case "through":c.through=d.text.replace(/^:/,"");break;case "polymorphic":c.polymorphic=d.text==="true";break;case "dependent":c.dependent=d.text.replace(/^:/,"");break;case "optional":c.optional=d.text==="true";break}}}o.push(c);}parseValidation(t,e,o,s){let n=this.getCallArguments(t);if(n.length===0)return;let r=[],a={},c=e;for(let i of n)if(i.type==="simple_symbol"||i.type==="symbol")r.push(i.text.replace(/^:/,""));else if(i.type==="hash"){let p=w(i,"pair");for(let u of p){let m=u.child(0)?.text?.replace(/^:/,""),d=u.child(2);m&&d&&(["presence","uniqueness","numericality","length","format","inclusion","exclusion","acceptance","confirmation"].includes(m)&&(c=m),a[m]=d.text);}}(r.length>0||e==="validate")&&o.push({type:c,attributes:r,options:Object.keys(a).length>0?a:void 0,line:s});}isCallback(t){return ["before_validation","after_validation","before_save","around_save","after_save","before_create","around_create","after_create","before_update","around_update","after_update","before_destroy","around_destroy","after_destroy","after_commit","after_rollback","after_initialize","after_find","after_touch"].includes(t)}parseCallback(t,e,o,s){let n=this.getCallArguments(t);if(n.length===0)return;let a=n[0].text.replace(/^:/,""),c={type:e,method:a,line:s};for(let i of n.slice(1))if(i.type==="hash"){let p=w(i,"pair");for(let u of p){let m=u.child(0)?.text?.replace(/^:/,""),d=u.child(2);m&&d&&["if","unless"].includes(m)&&(c.conditions=`${m}: ${d.text}`);}}o.push(c);}parseScope(t,e,o){let s=this.getCallArguments(t);if(s.length===0)return;let r=s[0].text.replace(/^:/,""),a=s.length>1&&(s[1].type==="lambda"||s[1].text.includes("->"));e.push({name:r,lambda:a,line:o});}parseInclude(t,e){let o=this.getCallArguments(t);for(let s of o)(s.type==="constant"||s.type==="scope_resolution")&&e.push(s.text);}parseEnum(t,e,o){let s=this.getCallArguments(t);if(s.length!==0){for(let n of s)if(n.type==="hash"){let r=w(n,"pair");for(let a of r){let c=a.child(0)?.text?.replace(/^:/,""),i=a.child(2);if(c&&i&&i.type==="hash"){let p=[],u=w(i,"pair");for(let m of u){let d=m.child(0)?.text?.replace(/^:/,"");d&&p.push(d);}e.push({name:c,values:p,line:o});}else if(c&&i&&i.type==="array"){let p=[];for(let u=0;u<i.childCount;u++){let m=i.child(u);m&&m.type!=="["&&m.type!=="]"&&m.type!==","&&p.push(m.text.replace(/^:/,""));}e.push({name:c,values:p,line:o});}}}}}parseAttribute(t,e,o){let s=this.getCallArguments(t);if(s.length===0)return;let a={name:s[0].text.replace(/^:/,""),line:o};if(s.length>1){let c=s[1];a.type=c.text.replace(/^:/,"");}for(let c of s)if(c.type==="hash"){let i=w(c,"pair");for(let p of i){let u=p.child(0)?.text?.replace(/^:/,""),m=p.child(2);u==="default"&&m&&(a.default=m.text);}}e.push(a);}getCallArguments(t){let e=t.childForFieldName("arguments");if(!e){let s=[];for(let n=0;n<t.childCount;n++){let r=t.child(n);r&&!["identifier","(",")",",","call"].includes(r.type)&&r!==t.childForFieldName("method")&&r!==t.childForFieldName("receiver")&&s.push(r);}return s}let o=[];for(let s=0;s<e.childCount;s++){let n=e.child(s);n&&n.type!=="("&&n.type!==")"&&n.type!==","&&o.push(n);}return o}};async function be(){let l=process.argv[2]||process.cwd();console.log(`Analyzing models in: ${l}`);let e=await new j(l).analyze();if(console.log(`
14
+ === Rails Models Analysis ===
15
+ `),console.log(`Total models: ${e.models.length}`),console.log(`Total associations: ${e.totalAssociations}`),console.log(`Total validations: ${e.totalValidations}`),console.log(`Shared concerns: ${e.concerns.length}`),console.log(`Namespaces: ${e.namespaces.join(", ")||"(none)"}`),e.errors.length>0){console.log(`
16
+ --- Errors (${e.errors.length}) ---`);for(let a of e.errors.slice(0,5))console.log(` \u274C ${a}`);e.errors.length>5&&console.log(` ... and ${e.errors.length-5} more`);}console.log(`
17
+ --- Sample Models (first 15) ---`);for(let a of e.models.slice(0,15)){if(console.log(`
18
+ \u{1F4E6} ${a.className} (${a.filePath})`),console.log(` Parent: ${a.parentClass}`),a.associations.length>0){let c=a.associations.slice(0,3).map(i=>`${i.type} :${i.name}`);console.log(` Associations: ${c.join(", ")}${a.associations.length>3?"...":""}`);}if(a.validations.length>0&&console.log(` Validations: ${a.validations.length}`),a.scopes.length>0){let c=a.scopes.slice(0,3).map(i=>i.name);console.log(` Scopes: ${c.join(", ")}${a.scopes.length>3?"...":""}`);}if(a.enums.length>0){let c=a.enums.map(i=>`${i.name}(${i.values.length})`);console.log(` Enums: ${c.join(", ")}`);}a.concerns.length>0&&console.log(` Concerns: ${a.concerns.slice(0,3).join(", ")}${a.concerns.length>3?"...":""}`);}let o=e.models.flatMap(a=>a.associations),s=o.filter(a=>a.type==="belongs_to").length,n=o.filter(a=>a.type==="has_many").length,r=o.filter(a=>a.type==="has_one").length;console.log(`
19
+ --- Association Summary ---`),console.log(` belongs_to: ${s}`),console.log(` has_many: ${n}`),console.log(` has_one: ${r}`);}var xe=import.meta.url===`file://${process.argv[1]}`;xe&&be().catch(console.error);var T=class{constructor(t){this.rootPath=t;this.grpcDir=x.join(t,"app","grpc_services");}grpcDir;services=[];errors=[];async analyze(){if(!L.existsSync(this.grpcDir))return {services:[],totalRpcs:0,namespaces:[],errors:[`gRPC services directory not found at ${this.grpcDir}`]};let t=await glob("**/*_grpc_service.rb",{cwd:this.grpcDir});for(let s of t){let n=x.join(this.grpcDir,s);try{let r=await this.parseServiceFile(n,s);r&&this.services.push(r);}catch(r){this.errors.push(`Error parsing ${s}: ${r}`);}}let e=[...new Set(this.services.filter(s=>s.namespace).map(s=>s.namespace))],o=this.services.reduce((s,n)=>s+n.rpcs.length,0);return {services:this.services,totalRpcs:o,namespaces:e,errors:this.errors}}async parseServiceFile(t,e){let s=(await N(t)).rootNode,n=e.replace(/_grpc_service\.rb$/,"").split("/"),r=n.length>1?n.slice(0,-1).join("/"):void 0,a=n[n.length-1],c=R(s,"class");if(c.length===0)return null;let i=c[0],p=F(i),u=M(i);if(!p)return null;let m={name:a,filePath:e,className:p,parentClass:u||"Unknown",namespace:r,rpcs:[],policies:[],serializers:[],concerns:[],line:i.startPosition.row+1};u&&u.match(/(\w+)::Service$/)&&(m.protoService=u.replace("::Service",""));let d=R(i,"call");for(let h of d)if(h.childForFieldName("method")?.text==="include"){let v=this.getCallArguments(h);for(let C of v)(C.type==="constant"||C.type==="scope_resolution")&&m.concerns.push(C.text);}R(i,"method");let f="public",g=i.childForFieldName("body");if(g)for(let h=0;h<g.childCount;h++){let b=g.child(h);if(b){if(b.type==="identifier"){let v=b.text;v==="private"?f="private":v==="protected"?f="protected":v==="public"&&(f="public");}else if(b.type==="method"&&f==="public"){let v=this.parseRpcMethod(b);if(v){let C=R(b,"call");for(let X of C){let B=X.childForFieldName("method")?.text,P=X.childForFieldName("receiver")?.text;(B==="authorize!"||B==="new")&&P?.includes("Policy")&&(m.policies.includes(P)||m.policies.push(P),v.policyMethod="authorize!"),P?.includes("Serializer")&&B==="new"&&(m.serializers.includes(P)||m.serializers.push(P));}m.rpcs.push(v);}}}}return m}parseRpcMethod(t){let e=U(t);if(!e||["initialize","to_s","inspect","call","perform","execute"].includes(e))return null;Z(t);let n=t.text,r={name:e,line:t.startPosition.row+1,streaming:"none",modelsUsed:[],servicesUsed:[]},a=n.match(/@param\s+\[([^\]]+)\]\s+req/);a&&(r.requestType=a[1]);let c=n.match(/@return\s+\[([^\]]+)\]/);c&&(r.responseType=c[1]);let i=n.matchAll(/\b([A-Z][a-zA-Z]+)\.(find|find_by|where|all|first|last|create|joins|includes)\b/g);for(let u of i){let m=u[1];!["Rails","ActiveRecord","GRPC","Visit","Google"].includes(m)&&!r.modelsUsed.includes(m)&&r.modelsUsed.push(m);}let p=n.matchAll(/\b(\w+Service)\.(call|new|perform)\b/g);for(let u of p){let m=u[1];r.servicesUsed.includes(m)||r.servicesUsed.push(m);}return r}getCallArguments(t){let e=t.childForFieldName("arguments");if(!e){let s=[];for(let n=0;n<t.childCount;n++){let r=t.child(n);r&&!["identifier","(",")",",","call"].includes(r.type)&&r!==t.childForFieldName("method")&&r!==t.childForFieldName("receiver")&&s.push(r);}return s}let o=[];for(let s=0;s<e.childCount;s++){let n=e.child(s);n&&n.type!=="("&&n.type!==")"&&n.type!==","&&o.push(n);}return o}};async function ve(){let l=process.argv[2]||process.cwd();console.log(`Analyzing gRPC services in: ${l}`);let e=await new T(l).analyze();if(console.log(`
20
+ === Rails gRPC Services Analysis ===
21
+ `),console.log(`Total services: ${e.services.length}`),console.log(`Total RPCs: ${e.totalRpcs}`),console.log(`Namespaces: ${e.namespaces.join(", ")||"(none)"}`),e.errors.length>0){console.log(`
22
+ --- Errors (${e.errors.length}) ---`);for(let n of e.errors.slice(0,5))console.log(` \u274C ${n}`);}console.log(`
23
+ --- Sample Services (first 15) ---`);for(let n of e.services.slice(0,15))console.log(`
24
+ \u{1F4E1} ${n.className} (${n.filePath})`),console.log(` Proto: ${n.protoService||"unknown"}`),console.log(` RPCs (${n.rpcs.length}): ${n.rpcs.map(r=>r.name).join(", ")}`),n.policies.length>0&&console.log(` Policies: ${n.policies.join(", ")}`),n.serializers.length>0&&console.log(` Serializers: ${n.serializers.join(", ")}`);let o=e.services.flatMap(n=>n.rpcs),s=o.filter(n=>n.modelsUsed.length>0);console.log(`
25
+ --- RPC Summary ---`),console.log(` Total RPCs: ${o.length}`),console.log(` RPCs using models: ${s.length}`);}var we=import.meta.url===`file://${process.argv[1]}`;we&&ve().catch(console.error);async function K(l){let t=x.join(l,"app/views"),e=x.join(l,"app/controllers");try{await A.access(t);}catch{return {views:[],pages:[],summary:{totalViews:0,totalPages:0,byController:{},byTemplate:{}}}}let o=await glob("**/*.{haml,erb,html.haml,html.erb,yml}",{cwd:t,nodir:true}),s=[],n={},r={};for(let c of o){let i=await Ae(t,c);i&&(s.push(i),n[i.controller]=(n[i.controller]||0)+1,r[i.template]=(r[i.template]||0)+1);}let a=await _e(e,s,l);return {views:s,pages:a,summary:{totalViews:s.length,totalPages:a.length,byController:n,byTemplate:r}}}async function Ae(l,t){let e=x.join(l,t);try{let o=await A.readFile(e,"utf-8"),s=t.split("/");if(s.some(g=>g.endsWith("_mailer")||g==="layouts"||g==="shared"||g==="devise"))return null;let n=s.pop()||"",r=s.join("/")||"application",a=n.split("."),c=a[0].replace(/^_/,""),i=n.startsWith("_"),p;n.endsWith(".yml")?p="yml":n.endsWith(".haml")?p="haml":n.endsWith(".erb")?p="erb":p="other";let u=a.length>2?a[1]:"html";if(i)return null;let m=[],d=[],y=[],f=[];return p==="yml"?(y=$e(o),f=[{name:"App",ssr:!0,propsVar:"@yml_data"}]):(m=Ce(o,p),d=Ne(o,p),y=Pe(o),f=Se(o,p)),{name:c,path:t,controller:r,action:c,format:u,template:p,partials:m,helpers:d,instanceVars:y,reactComponents:f}}catch{return null}}function Ce(l,t){let e=[];if(t==="haml"){let o=l.matchAll(/=\s*render\s+(?:partial:\s*)?['"]([^'"]+)['"]/g);for(let s of o)e.push(s[1]);}else if(t==="erb"){let o=l.matchAll(/<%=?\s*render\s+(?:partial:\s*)?['"]([^'"]+)['"]/g);for(let s of o)e.push(s[1]);}return [...new Set(e)]}function Ne(l,t){let e=[],o=/\b(link_to|form_for|form_with|image_tag|content_for|yield|render|t|l|raw|html_safe|simple_form_for)\b/g,s=l.matchAll(o);for(let n of s)e.push(n[1]);return [...new Set(e)]}function Se(l,t){let e=[],o=/render_react_component\s*\(?\s*["']([^"']+)["'](?:,\s*\{[^}]*\})?\s*(?:,\s*ssr:\s*(true|false))?\)?/g,s;for(;(s=o.exec(l))!==null;)e.push({name:s[1],ssr:s[2]==="true"});let n=/data:\s*\{\s*react_component:\s*["']([^"']+)["'](?:,\s*react_component_props:\s*(@?\w+)(?:\.to_json)?)?/g;for(;(s=n.exec(l))!==null;)e.push({name:s[1],propsVar:s[2],ssr:false});let r=/ReactComponent\s+name=["']([^"']+)["']/g;for(;(s=r.exec(l))!==null;)e.push({name:s[1],ssr:false});let a=new Set;return e.filter(c=>a.has(c.name)?false:(a.add(c.name),true))}function $e(l){let t=[],e=l.split(`
26
+ `);for(let o of e){let s=o.match(/^([a-z_]+):/);s&&!s[1].startsWith("_")&&t.push(s[1]);let n=o.match(/^\s+-\s+(\w+)/);n&&t.push(n[1]);}return [...new Set(t)].slice(0,50)}function Pe(l){let t=[],e=l.matchAll(/@(\w+)/g);for(let o of e)["import","media","keyframes","charset"].includes(o[1])||t.push(o[1]);return [...new Set(t)]}async function _e(l,t,e){let o=[];try{await A.access(l);}catch{return o}let s=await glob("**/*_controller.rb",{cwd:l,nodir:true}),n=await Fe(e);for(let r of s){let a=x.join(l,r),c=await A.readFile(a,"utf-8"),i=r.replace(/_controller\.rb$/,"").replace(/\//g,"/"),p=Me(c,i,r,t,n);o.push(...p);}return o}async function Fe(l){let t=new Map;try{let e=x.join(l,".repomap","rails-routes.json"),o=await A.readFile(e,"utf-8"),s=JSON.parse(o);for(let n of s){let r=`${n.controller}#${n.action}`;t.set(r,{path:n.path,method:n.method});}}catch{}return t}function Me(l,t,e,o,s){let n=[],r=l.split(/\n\s*(private|protected)\b/)[0],a=/def\s+(\w+)/g,c;for(;(c=a.exec(r))!==null;){let i=c[1];["initialize","new","create","update","destroy","index","show","edit"].includes(i)||i.startsWith("set_")||i.startsWith("_");let p=c.index,u=Ie(r,p),m=ke(u,e),d=Ve(u),y=je(u),f=Te(u),g=o.find(v=>v.controller===t&&v.action===i),h=`${t}#${i}`,b=s.get(h);n.push({route:b?.path||`/${t}/${i}`,method:b?.method||"GET",controller:t,action:i,view:g,apis:m,services:d,grpcCalls:y,modelAccess:f});}return n}function Ie(l,t){let e=0,o=false,s="";for(let n=t;n<l.length;n++){let r=l.slice(n,l.indexOf(`
27
+ `,n)+1||l.length);if(r.match(/^\s*(def|class|module|if|unless|case|while|until|for|begin|do)\b/)&&(e++,o=true),r.match(/^\s*end\b/)&&(e--,o&&e===0)||(s+=r,n=l.indexOf(`
28
+ `,n),n===-1))break}return s}function ke(l,t){let e=[],o=[/HTTPClient\.(get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/gi,/RestClient\.(get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/gi,/Faraday\.(get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/gi,/Net::HTTP\.(get|post)\s*\(/gi];for(let s of o){let n;for(;(n=s.exec(l))!==null;)e.push({type:"http",name:n[2]||"HTTP call",method:n[1]?.toUpperCase(),source:t});}return e}function Ve(l){let t=[],e=/(\w+(?:::\w+)*Service)\.(?:call!?|new)/g,o;for(;(o=e.exec(l))!==null;)t.push(o[1]);return [...new Set(t)]}function je(l){let t=[],e=[/(\w+(?:::\w+)*Grpc(?:::\w+)?)\./g,/Grpc::(\w+(?:::\w+)*)/g,/(\w+GrpcService)\./g];for(let o of e){let s;for(;(s=o.exec(l))!==null;)t.push(s[1]);}return [...new Set(t)]}function Te(l){let t=[],e=/([A-Z][a-zA-Z0-9]+)\.(?:find|where|find_by|first|last|all|create|update|destroy|new)/g,o;for(;(o=e.exec(l))!==null;)["File","Dir","Time","Date","DateTime","JSON","YAML","CSV","Logger"].includes(o[1])||t.push(o[1]);return [...new Set(t)]}var ze=["app/javascript/packs","app/javascript/entrypoints","app/frontend/entrypoints","app/javascript/application","frontend/assets/javascripts/entries","frontend/entries","app/assets/javascripts/entries","client/entries","src/entries"],Ee=["app/javascript/components","app/javascript/react","app/javascript/src/components","app/javascript/bundles","app/frontend/components","app/frontend/react","frontend/assets/javascripts/react","frontend/assets/javascripts/components","frontend/src","frontend/src/components","frontend/components","client/components","src/components"],E={dataReactComponent:/react_component:\s*["']([A-Za-z0-9_/]+)["']/g,renderReactComponent:/render_react_component\s*\(?\s*["']([A-Za-z0-9_/]+)["']/g,reactComponent:/<%=?\s*react_component\s*\(\s*["']([A-Za-z0-9_/]+)["']/g,reduxStore:/<%=?\s*redux_store\s*\(\s*["']([A-Za-z0-9_/]+)["']/g,dataComponent:/data-component\s*[=:]\s*["']([A-Za-z0-9_/]+)["']/g,dataReactClass:/data-react-class\s*[=:]\s*["']([A-Za-z0-9_/]+)["']/g};async function Q(l){let t=new Map,e=[],o=await De(l);console.log(` \u{1F4C2} Detected paths: ${o.entryDirs.length} entry dirs, ${o.componentDirs.length} component dirs (${o.integrationPattern})`);for(let a of o.entryDirs){let c=x.join(l,a);try{await A.access(c);let i=await glob("**/*.{tsx,ts,jsx,js}",{cwd:c,nodir:!0,ignore:["**/*.d.ts","**/*.test.*","**/*.spec.*"]});for(let p of i){let u=await Ue(x.join(c,p),p,a);if(u&&(e.push(u),u.componentName)){let m=t.get(u.componentName);m?(m.entryFile=x.join(a,p),m.importPath=u.imports[0]):t.set(u.componentName,{name:u.componentName,entryFile:x.join(a,p),importPath:u.imports[0],ssr:!1,usedIn:[]});}}}catch{}}let s=x.join(l,"app/views");try{await A.access(s);let a=await glob("**/*.{haml,erb,html.haml,html.erb,slim}",{cwd:s,nodir:!0});for(let c of a){let i=await Ze(x.join(s,c),c);for(let p of i){let u=t.get(p.componentName);u?(u.usedIn.push({viewPath:c,controller:p.controller,action:p.action,propsVar:p.propsVar,line:p.line,pattern:p.pattern}),p.ssr&&(u.ssr=!0)):t.set(p.componentName,{name:p.componentName,ssr:p.ssr,usedIn:[{viewPath:c,controller:p.controller,action:p.action,propsVar:p.propsVar,line:p.line,pattern:p.pattern}]});}}}catch{}await Be(l,t,o.componentDirs);let n=Array.from(t.values()),r=n.filter(a=>a.ssr).length;return {components:n,entryPoints:e,detectedPaths:o,summary:{totalComponents:n.length,totalEntryPoints:e.length,ssrComponents:r,clientComponents:n.length-r}}}async function De(l){let t=[],e=[],o="unknown";for(let s of ze){let n=x.join(l,s);try{(await A.stat(n)).isDirectory()&&t.push(s);}catch{}}for(let s of Ee){let n=x.join(l,s);try{(await A.stat(n)).isDirectory()&&e.push(s);}catch{}}if(o=await Ge(l),t.length===0){let s=await Le(l);t.push(...s);}return e.length===0&&t.length>0&&e.push(...t),{entryDirs:t,componentDirs:e,integrationPattern:o}}async function Ge(l){try{let t=x.join(l,"Gemfile"),e=await A.readFile(t,"utf-8");if(e.includes("react_on_rails"))return "react_on_rails";if(e.includes("react-rails"))return "react-rails";if(e.includes("vite_rails")||e.includes("vite_ruby"))return "vite";if(e.includes("webpacker"))return "webpacker";try{return await A.access(x.join(l,"vite.config.ts")),"vite"}catch{}try{return await A.access(x.join(l,"vite.config.js")),"vite"}catch{}return "custom"}catch{return "unknown"}}async function Le(l){let t=[],e=["app/**/entries","app/**/packs","frontend/**/entries","client/**/entries","src/**/entries"];for(let o of e)try{let s=await glob(o,{cwd:l,nodir:!1});for(let n of s){let r=x.join(l,n);try{(await A.stat(r)).isDirectory()&&t.push(n);}catch{}}}catch{}return t}async function Ue(l,t,e){try{let o=await A.readFile(l,"utf-8"),s=[/\[data-react-component[=:][\s]*["']?([A-Za-z0-9_]+)["']?\]/,/\[data-component[=:][\s]*["']?([A-Za-z0-9_]+)["']?\]/,/\[data-react-class[=:][\s]*["']?([A-Za-z0-9_]+)["']?\]/,/getElementById\s*\(\s*["']([A-Za-z0-9_-]+)["']\s*\)/,/querySelector\s*\(\s*["']#([A-Za-z0-9_-]+)["']\s*\)/],n=null,r;for(let p of s){let u=o.match(p);if(u){n=u[1],r=u[0];break}}n||(n=x.basename(t,x.extname(t)).split(/[-_]/).map(u=>u.charAt(0).toUpperCase()+u.slice(1)).join(""));let a=[],c=o.matchAll(/import\s+(?:\{[^}]+\}|\*\s+as\s+\w+|\w+)\s+from\s+["']([^"']+)["']/g);for(let p of c){let u=p[1];(u.includes("/react/")||u.includes("/components/")||u.includes("/containers/")||u.includes("/bundles/")||u.includes("/pages/")||u.match(/\/[A-Z][a-zA-Z0-9]*/))&&a.push(u);}let i=o.matchAll(/require\s*\(\s*["']([^"']+)["']\s*\)/g);for(let p of i){let u=p[1];(u.includes("/react/")||u.includes("/components/")||u.includes("/containers/"))&&a.push(u);}return !n&&a.length===0?null:{file:t,fullPath:x.join(e,t),componentName:n||"",imports:a,selector:r}}catch{return null}}async function Ze(l,t){let e=[];try{let s=(await A.readFile(l,"utf-8")).split(`
29
+ `),n=t.split("/"),r=n.pop()||"",a=n.join("/")||"application",c=r.split(".")[0].replace(/^_/,""),i=0;for(let p of s){i++;let u=p.matchAll(E.dataReactComponent);for(let h of u){let b=p.match(/react_component_props:\s*(@?\w+(?:\.\w+)*)/);e.push({componentName:h[1],controller:a,action:c,propsVar:b?b[1]:void 0,line:i,pattern:"data-react-component",ssr:!1});}let m=p.match(E.renderReactComponent);if(m){let h=p.match(/ssr:\s*(true|false|@\w+)/);e.push({componentName:m[1],controller:a,action:c,line:i,pattern:"render_react_component",ssr:h?h[1]==="true"||h[1].startsWith("@"):!1});}let d=p.match(E.reactComponent);if(d){let h=p.match(/props:\s*(@?\w+(?:\.\w+)*)/),b=p.match(/prerender:\s*(true|false)/);e.push({componentName:d[1],controller:a,action:c,propsVar:h?h[1]:void 0,line:i,pattern:"react_component",ssr:b?b[1]==="true":!1});}let y=p.match(E.reduxStore);y&&e.push({componentName:y[1],controller:a,action:c,line:i,pattern:"redux_store",ssr:!1});let f=p.match(E.dataComponent);f&&e.push({componentName:f[1],controller:a,action:c,line:i,pattern:"data-react-component",ssr:!1});let g=p.match(E.dataReactClass);g&&e.push({componentName:g[1],controller:a,action:c,line:i,pattern:"data-react-component",ssr:!1});}}catch{}return e}async function Be(l,t,e){for(let[o,s]of t)if(!(!o||typeof o!="string")){if(s.importPath&&typeof s.importPath=="string"){let n=s.importPath.replace(/\.js$/,"").replace(/\.tsx?$/,"").replace(/^\.\.\//,"").replace(/^\.\//,"");s.sourceFile=n;}else if(!s.sourceFile){let n=[".tsx",".ts",".jsx",".js"],r=[o,Oe(o),We(o)].filter(Boolean),a=false;for(let c of e){if(a)break;for(let i of r){if(a)break;for(let p of n){let u=[x.join(l,c,i,`index${p}`),x.join(l,c,i,`${i}${p}`),x.join(l,c,`${i}${p}`),x.join(l,c,"components",`${i}${p}`),x.join(l,c,"containers",`${i}${p}`)];for(let m of u)try{await A.access(m),s.sourceFile=x.relative(l,m),a=!0;break}catch{}}}}}}}function Oe(l){return l?l.replace(/([A-Z])/g,"_$1").toLowerCase().replace(/^_/,""):""}function We(l){return l?l.replace(/([A-Z])/g,"-$1").toLowerCase().replace(/^-/,""):""}async function He(l){console.log(`
30
+ \u{1F4E6} Analyzing Rails application at: ${l}
31
+ `),console.log("\u{1F504} Analyzing routes...");let e=await new k(l).analyze();console.log(` \u2705 Found ${e.routes.length} routes`),console.log("\u{1F504} Analyzing controllers...");let s=await new V(l).analyze();console.log(` \u2705 Found ${s.controllers.length} controllers with ${s.totalActions} actions`),console.log("\u{1F504} Analyzing models...");let r=await new j(l).analyze();console.log(` \u2705 Found ${r.models.length} models with ${r.totalAssociations} associations`),console.log("\u{1F504} Analyzing gRPC services...");let c=await new T(l).analyze();console.log(` \u2705 Found ${c.services.length} gRPC services with ${c.totalRpcs} RPCs`),console.log("\u{1F504} Analyzing views...");let i=await K(l);console.log(` \u2705 Found ${i.summary.totalViews} views and ${i.summary.totalPages} pages`),console.log("\u{1F504} Analyzing React components...");let p=await Q(l);console.log(` \u2705 Found ${p.summary.totalComponents} React components (${p.summary.ssrComponents} SSR, ${p.summary.clientComponents} client)`);let u=[...new Set([...e.namespaces,...s.namespaces,...r.namespaces,...c.namespaces])],m=[...new Set([...s.concerns,...r.concerns])],d={totalRoutes:e.routes.length,totalControllers:s.controllers.length,totalActions:s.totalActions,totalModels:r.models.length,totalAssociations:r.totalAssociations,totalValidations:r.totalValidations,totalGrpcServices:c.services.length,totalRpcs:c.totalRpcs,totalViews:i.summary.totalViews,totalPages:i.summary.totalPages,totalReactComponents:p.summary.totalComponents,ssrReactComponents:p.summary.ssrComponents,namespaces:u,concerns:m};return {routes:e,controllers:s,models:r,grpc:c,views:i,react:p,summary:d}}async function qe(){let l=process.argv[2]||process.cwd(),t=await He(l);console.log(`
32
+ `+"=".repeat(60)),console.log("\u{1F4CA} RAILS APPLICATION ANALYSIS SUMMARY"),console.log("=".repeat(60)+`
33
+ `),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 Routes \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total routes: ${String(t.summary.totalRoutes).padStart(6)} \u2502`),console.log(`\u2502 Resources: ${String(t.routes.resources.length).padStart(6)} \u2502`),console.log(`\u2502 Mounted engines: ${String(t.routes.mountedEngines.length).padStart(6)} \u2502`),console.log(`\u2502 External files: ${String(t.routes.drawnFiles.length).padStart(6)} \u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 Controllers \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total controllers: ${String(t.summary.totalControllers).padStart(6)} \u2502`),console.log(`\u2502 Total actions: ${String(t.summary.totalActions).padStart(6)} \u2502`),console.log(`\u2502 Namespaces: ${String(t.controllers.namespaces.length).padStart(6)} \u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 Models \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total models: ${String(t.summary.totalModels).padStart(6)} \u2502`),console.log(`\u2502 Associations: ${String(t.summary.totalAssociations).padStart(6)} \u2502`),console.log(`\u2502 Validations: ${String(t.summary.totalValidations).padStart(6)} \u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 gRPC Services \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total services: ${String(t.summary.totalGrpcServices).padStart(6)} \u2502`),console.log(`\u2502 Total RPCs: ${String(t.summary.totalRpcs).padStart(6)} \u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 Shared \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Total namespaces: ${String(t.summary.namespaces.length).padStart(6)} \u2502`),console.log(`\u2502 Total concerns: ${String(t.summary.concerns.length).padStart(6)} \u2502`),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");let e=t.routes.errors.length+t.controllers.errors.length+t.models.errors.length+t.grpc.errors.length;e>0?console.log(`
34
+ \u26A0\uFE0F Total errors: ${e}`):console.log(`
35
+ \u2705 Analysis completed without errors!`);}var Je=import.meta.url===`file://${process.argv[1]}`;Je&&qe().catch(console.error);
36
+ export{ne as a,oe as b,N as c,R as d,k as e,V as f,j as g,T as h,K as i,Q as j,He as k};
@@ -0,0 +1 @@
1
+ import*as a from'fs/promises';import*as c from'path';async function d(s){let t=[],i=await f(s);i.detected&&t.push(i);let p=await l(s);p.detected&&t.push(p);let e=t.some(o=>o.type==="nextjs"),n=t.some(o=>o.type==="react"||o.type==="nextjs"),u=t.some(o=>o.type==="rails"),r="generic";return e?r="nextjs":n?r="react":u&&(r="rails"),{environments:t,hasNextjs:e,hasReact:n,hasRails:u,primary:r}}async function f(s){let t={type:"rails",detected:false,path:s,features:[]};try{let i=c.join(s,"Gemfile"),p=c.join(s,"config","routes.rb");await a.access(i),await a.access(p);let e=await a.readFile(i,"utf-8");if(!(e.includes("gem 'rails'")||e.includes('gem "rails"')))return t;t.detected=!0;let u=e.match(/gem ['"]rails['"],\s*['"]([^'"]+)['"]/);u&&(t.version=u[1]);let r=[];try{await a.access(c.join(s,"app","grpc_services")),r.push("grpc");}catch{}try{(await a.readFile(c.join(s,"config","application.rb"),"utf-8")).includes("config.api_only = true")&&r.push("api-only");}catch{}(e.includes("gem 'graphql'")||e.includes('gem "graphql"'))&&r.push("graphql"),(e.includes("gem 'devise'")||e.includes('gem "devise"'))&&r.push("devise"),t.features=r;}catch{}return t}async function l(s){let t={type:"react",detected:false,path:s,features:[]};try{let i=c.join(s,"package.json"),p=JSON.parse(await a.readFile(i,"utf-8")),e={...p.dependencies,...p.devDependencies};if(!e.react)return t;t.detected=!0,t.version=e.react;let n=[];if(e.next){t.type="nextjs",t.version=e.next;try{await a.access(c.join(s,"app")),n.push("app-router");}catch{}try{await a.access(c.join(s,"pages")),n.push("pages-router");}catch{}try{await a.access(c.join(s,"src","pages")),n.push("pages-router");}catch{}try{await a.access(c.join(s,"src","app")),n.push("app-router");}catch{}}(e["@apollo/client"]||e.graphql||e["graphql-request"]||e.urql)&&n.push("graphql"),e.typescript&&n.push("typescript"),(e.redux||e["@reduxjs/toolkit"])&&n.push("redux"),e.zustand&&n.push("zustand"),(e.jotai||e.recoil)&&n.push("atomic-state"),t.features=n;}catch{}return t}function h(s){let t=[],i=[];return (s.hasNextjs||s.hasReact)&&t.push("pages","graphql","dataflow","rest-api"),s.hasRails&&i.push("routes","controllers","models","grpc"),{frontend:t,backend:i}}export{d as a,h as b};
@@ -0,0 +1,19 @@
1
+ var F=class{generateAll(t,e){let n=[];for(let a of t)n.push(this.generateNavigationDiagram(a)),n.push(this.generateDataFlowDiagram(a)),n.push(this.generateComponentDiagram(a)),n.push(this.generateGraphQLDiagram(a));return t.length>1&&n.push(this.generateCrossRepoDiagram(t,e)),n}generateNavigationDiagram(t){let e=["flowchart TB"," %% Page Navigation Flow - Grouped by Category"],n=new Map,a=0,r=new Map;for(let i of t.pages){let c=i.path.split("/").filter(Boolean)[0]||"root",h=r.get(c)||[];h.push(i),r.set(c,h);}for(let[i,p]of r){let c=i.replace(/[^a-zA-Z0-9]/g,"_"),h=i==="root"?"Root Pages":`/${i}`;e.push(""),e.push(` subgraph ${c}["${h}"]`),e.push(" direction TB");for(let l of p){let m=`P${a++}`;n.set(l.path,m);let u=l.path.split("/").filter(Boolean),g=u.length>1?u.slice(1).join("/"):l.path,f=l.authentication.required?" AUTH":"";e.push(` ${m}["${g}${f}"]`);}e.push(" end");}let s=0,o=30;e.push(""),e.push(" %% Navigation Links");for(let i of t.pages){if(s>=o)break;let p=n.get(i.path);for(let c of i.linkedPages.slice(0,2)){if(s>=o)break;let h=n.get(c);p&&h&&p!==h&&(e.push(` ${p} --> ${h}`),s++);}}e.push(""),e.push(" %% Styling"),e.push(" classDef authRequired fill:#fee2e2,stroke:#ef4444,color:#991b1b"),e.push(" classDef public fill:#dcfce7,stroke:#22c55e,color:#166534");for(let i of t.pages){let p=n.get(i.path);p&&(i.authentication.required?e.push(` class ${p} authRequired`):e.push(` class ${p} public`));}return {type:"flowchart",title:`${t.repository} - Page Navigation`,content:e.join(`
2
+ `),relatedFiles:t.pages.map(i=>i.filePath)}}generateDataFlowDiagram(t){let e=["flowchart LR"," %% Data Flow Diagram"],n=new Map,a=0,r=h=>{let l=`${h.type}:${h.name}`;if(!n.has(l)){let m=h.type.charAt(0).toUpperCase();n.set(l,`${m}${a++}`);}return n.get(l)??`N${a++}`},o=h=>h.replace(/[\u{1F4E1}\u{270F}\u{FE0F}\u{1F504}\u{1F4E6}]/gu,"").trim().substring(0,40),i=t.dataFlows.filter(h=>h.name.includes("\u{1F4E1}")||h.operations.some(l=>l.includes("Query"))),p=t.dataFlows.filter(h=>h.name.includes("\u270F\uFE0F")||h.operations.some(l=>l.includes("Mutation"))),c=t.dataFlows.filter(h=>h.name.includes("\u{1F504}")||h.source.type==="context"||h.operations.some(l=>l.includes("Context")));if(i.length>0){e.push(""),e.push(" subgraph Queries[\u{1F4E1} Queries]"),e.push(" direction TB");for(let h of i.slice(0,20)){let l=r(h.source),m=r(h.target),u=o(h.source.name),g=o(h.target.name);e.push(` ${l}(("${u}"))`),e.push(` ${m}["${g}"]`),e.push(` ${l} --> ${m}`);}e.push(" end");}if(p.length>0){e.push(""),e.push(" subgraph Mutations[\u270F\uFE0F Mutations]"),e.push(" direction TB");for(let h of p.slice(0,20)){let l=r(h.source),m=r(h.target),u=o(h.source.name),g=o(h.target.name);e.push(` ${l}["${u}"]`),e.push(` ${m}(("${g}"))`),e.push(` ${l} --> ${m}`);}e.push(" end");}if(c.length>0){e.push(""),e.push(" subgraph Context[\u{1F504} Context]"),e.push(" direction TB");for(let h of c.slice(0,15)){let l=r(h.source),m=r(h.target),u=o(h.source.name),g=o(h.target.name);e.push(` ${l}{{"${u}"}}`),e.push(` ${m}["${g}"]`),e.push(` ${l} -.-> ${m}`);}e.push(" end");}return e.push(""),e.push(" %% Styling"),e.push(" classDef query fill:#dbeafe,stroke:#3b82f6,color:#1e40af"),e.push(" classDef mutation fill:#fce7f3,stroke:#ec4899,color:#9d174d"),e.push(" classDef context fill:#d1fae5,stroke:#10b981,color:#065f46"),{type:"flowchart",title:`${t.repository} - Data Flow`,content:e.join(`
3
+ `),relatedFiles:t.dataFlows.map(h=>h.source.name)}}generateComponentDiagram(t){let e=["flowchart TB"," %% Component Hierarchy"],n=new Map;for(let s of t.components){let o=n.get(s.type)||[];o.push(s),n.set(s.type,o);}for(let[s,o]of n){e.push(` subgraph ${s.charAt(0).toUpperCase()+s.slice(1)}s`);for(let i of o.slice(0,20)){let p=i.name.replace(/[^a-zA-Z0-9]/g,"_");e.push(` ${p}["${i.name}"]`);}e.push(" end");}let a=0,r=50;for(let s of t.components){if(a>=r)break;let o=s.name.replace(/[^a-zA-Z0-9]/g,"_");for(let i of s.dependencies.slice(0,3)){if(a>=r)break;let p=i.replace(/[^a-zA-Z0-9]/g,"_");e.push(` ${o} --> ${p}`),a++;}}return {type:"flowchart",title:`${t.repository} - Component Hierarchy`,content:e.join(`
4
+ `),relatedFiles:t.components.map(s=>s.filePath)}}generateGraphQLDiagram(t){let e=["flowchart LR"," %% GraphQL Operations"],n=t.graphqlOperations.filter(s=>s.type==="query"),a=t.graphqlOperations.filter(s=>s.type==="mutation"),r=t.graphqlOperations.filter(s=>s.type==="fragment");if(e.push(' API[("GraphQL API")]'),n.length>0){e.push(" subgraph Queries");for(let s of n.slice(0,15)){let o=`Q_${s.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${o}["${s.name}"]`),e.push(` ${o} --> API`);}e.push(" end");}if(a.length>0){e.push(" subgraph Mutations");for(let s of a.slice(0,15)){let o=`M_${s.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${o}["${s.name}"]`),e.push(` ${o} --> API`);}e.push(" end");}if(r.length>0){e.push(" subgraph Fragments");for(let s of r.slice(0,10)){let o=`F_${s.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${o}[/"${s.name}"/]`);}e.push(" end");}return {type:"flowchart",title:`${t.repository} - GraphQL Operations`,content:e.join(`
5
+ `),relatedFiles:t.graphqlOperations.map(s=>s.filePath)}}generateCrossRepoDiagram(t,e){let n=["flowchart TB"," %% Cross-Repository Architecture"];for(let a of t){let r=a.repository.replace(/[^a-zA-Z0-9]/g,"_");n.push(` subgraph ${r}["${a.repository}"]`),n.push(` ${r}_pages["\u{1F4C4} ${a.pages.length} Pages"]`),n.push(` ${r}_gql["\u{1F537} ${a.graphqlOperations.length} GraphQL Ops"]`),n.push(` ${r}_comp["\u{1F9E9} ${a.components.length} Components"]`),n.push(" end");}for(let a of e){let r=a.sourceRepo.replace(/[^a-zA-Z0-9]/g,"_"),s=a.targetRepo.replace(/[^a-zA-Z0-9]/g,"_"),o="-->";a.linkType==="api-call"?o="==>":a.linkType==="graphql-operation"&&(o="-..->"),n.push(` ${r}_gql ${o}|"${a.linkType}"| ${s}_gql`);}return {type:"flowchart",title:"Cross-Repository Architecture",content:n.join(`
6
+ `),relatedFiles:t.map(a=>a.repository)}}generateSequenceDiagram(t){let e=["sequenceDiagram",` %% ${t.name}`],n=[t.source,...t.via,t.target];for(let s of n)e.push(` participant ${s.name}`);let a=t.source;for(let s=0;s<t.via.length;s++){let o=t.via[s],i=t.operations[s]||"data";e.push(` ${a.name}->>+${o.name}: ${i}`),a=o;}let r=t.operations[t.operations.length-1]||"data";return e.push(` ${a.name}->>+${t.target.name}: ${r}`),e.push(` ${t.target.name}-->>-${t.source.name}: response`),{type:"sequence",title:t.name,content:e.join(`
7
+ `),relatedFiles:[]}}};var q=class{generateDocumentation(t){let e=new Map;e.set("index.md",this.generateIndex(t));for(let n of t.repositories)e.set(`repos/${n.name}/index.md`,this.generateRepoIndex(n)),e.set(`repos/${n.name}/pages.md`,this.generatePagesDoc(n)),e.set(`repos/${n.name}/components.md`,this.generateComponentsDoc(n)),e.set(`repos/${n.name}/graphql.md`,this.generateGraphQLDoc(n)),e.set(`repos/${n.name}/dataflow.md`,this.generateDataFlowDoc(n));return e.set("cross-repo.md",this.generateCrossRepoDoc(t)),e.set("diagrams.md",this.generateDiagramsDoc(t.diagrams)),e}generateIndex(t){let n=[`# ${t.repositories.length===1?`${t.repositories[0].displayName} Documentation`:"Project Documentation"}`,"",`Generated: ${t.generatedAt}`,"",t.repositories.length>1?"## Repositories":"## Overview",""];for(let a of t.repositories)n.push(`### [${a.displayName}](/docs/repos/${a.name}/index)`),n.push(""),n.push(`- **Version**: ${a.version}`),n.push(`- **Commit**: \`${a.commitHash.substring(0,7)}\``),n.push(`- **Pages**: ${a.summary.totalPages}`),n.push(`- **Components**: ${a.summary.totalComponents}`),n.push(`- **GraphQL Ops**: ${a.summary.totalGraphQLOperations}`),n.push("");return n.push("## Quick Links"),n.push(""),n.push("- [Cross Repository](/docs/cross-repo)"),n.push("- [Diagrams](/docs/diagrams)"),n.push("- [Page Map (Interactive)](/page-map)"),n.push(""),n.join(`
8
+ `)}generateRepoIndex(t){return [`# ${t.displayName}`,"",`Version: ${t.version} | Commit: \`${t.commitHash.substring(0,7)}\``,"","## Overview","","| Metric | Count |","|--------|-------|",`| Pages | ${t.summary.totalPages} |`,`| Components | ${t.summary.totalComponents} |`,`| GraphQL Operations | ${t.summary.totalGraphQLOperations} |`,`| Data Flows | ${t.summary.totalDataFlows} |`,`| Auth Required | ${t.summary.authRequiredPages} |`,`| Public | ${t.summary.publicPages} |`,"","## Documentation","",`- [Pages](/docs/repos/${t.name}/pages)`,`- [Components](/docs/repos/${t.name}/components)`,`- [GraphQL](/docs/repos/${t.name}/graphql)`,`- [Data Flow](/docs/repos/${t.name}/dataflow)`,"","## Quick Access","","- [Page Map](/page-map)","- [Diagrams](/docs/diagrams)",""].join(`
9
+ `)}generatePagesDoc(t){let e=[`# ${t.displayName} - Pages`,""],n=t.analysis.pages.filter(o=>o.authentication.required).length,a=t.analysis.pages.filter(o=>o.dataFetching.some(i=>!i.type.includes("Mutation"))).length,r=t.analysis.pages.filter(o=>o.dataFetching.some(i=>i.type.includes("Mutation"))).length;e.push("| Metric | Value |"),e.push("|--------|-------|"),e.push(`| Total | **${t.analysis.pages.length}** |`),e.push(`| Auth Required | ${n} |`),e.push(`| With Queries | ${a} |`),e.push(`| With Mutations | ${r} |`),e.push("");let s=new Map;for(let o of t.analysis.pages){let i=o.path.split("/")[1]||"root",p=s.get(i)||[];p.push(o),s.set(i,p);}for(let[o,i]of s){e.push(`## /${o}`),e.push(""),e.push("| Page | Auth | Layout | Data |"),e.push("|------|------|--------|------|");for(let p of i){let c=p.path.replace(`/${o}`,"")||"/",h=p.authentication.required?"Required":"Public",l=p.layout||"-",m=[],u=p.dataFetching.filter(C=>!C.type.includes("Mutation")),g=p.dataFetching.filter(C=>C.type.includes("Mutation"));for(let C of u.slice(0,2)){let $=C.operationName||"";if(!$||$.trim().length<2)continue;let D=$.startsWith("\u2192")||$.startsWith("->"),y=$.replace(/^[→\->\s]+/,"");y&&y.trim().length>0&&(D?m.push(`<span class="gql-ref" data-ref="${y}" title="Component">${y}</span>`):m.push(`<span class="gql-op" data-op="${y}">${y}</span>`));}for(let C of g.slice(0,2)){let $=C.operationName||"";if(!$||$.trim().length<2)continue;let D=$.startsWith("\u2192")||$.startsWith("->"),y=$.replace(/^[→\->\s]+/,"");y&&y.trim().length>0&&(D?m.push(`<span class="gql-ref mutation" data-ref="${y}" title="Component">${y}</span>`):m.push(`<span class="gql-op mutation" data-op="${y}">${y}</span>`));}let f=u.length+g.length-Math.min(u.length,2)-Math.min(g.length,2);f>0&&m.push(`<span class="gql-more" data-type="all" data-page="${p.path}">+${f} more</span>`);let d=m.length>0?m.join(" "):"-";e.push(`| \`${c}\` | ${h} | ${l} | ${d} |`);}e.push("");for(let p of i){let c=p.dataFetching.filter(l=>!l.type.includes("Mutation")),h=p.dataFetching.filter(l=>l.type.includes("Mutation"));if(c.length>0||h.length>0){e.push(`### ${p.path}`),e.push(""),e.push(`> ${p.filePath}`),e.push("");let l=c.filter(u=>u.operationName&&u.operationName.trim().length>=2);if(l.length>0){e.push(`**Queries (${l.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let u of l){let g=u.operationName||"",f=g.startsWith("\u2192")||g.startsWith("->"),d=g.replace(/^[→\->\s]+/,"");f?e.push(`<span class="gql-ref" data-ref="${d}" title="Component">${d}</span>`):e.push(`<span class="gql-op" data-op="${d}">${d}</span>`);}e.push("</div>"),e.push("");}let m=h.filter(u=>u.operationName&&u.operationName.trim().length>=2);if(m.length>0){e.push(`**Mutations (${m.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let u of m){let g=u.operationName||"",f=g.startsWith("\u2192")||g.startsWith("->"),d=g.replace(/^[→\->\s]+/,"");f?e.push(`<span class="gql-ref mutation" data-ref="${d}" title="Component">${d}</span>`):e.push(`<span class="gql-op mutation" data-op="${d}">${d}</span>`);}e.push("</div>"),e.push("");}e.push("");}}}return e.join(`
10
+ `)}generateComponentsDoc(t){let e=[`# ${t.displayName} - Components`,""],n=new Map;for(let r of t.analysis.components){let s=n.get(r.type)||[];s.push(r),n.set(r.type,s);}e.push("| Type | Count |"),e.push("|------|-------|"),e.push(`| Container | ${n.get("container")?.length||0} |`),e.push(`| Presentational | ${n.get("presentational")?.length||0} |`),e.push(`| Layout | ${n.get("layout")?.length||0} |`),e.push(`| Hook | ${n.get("hook")?.length||0} |`),e.push(`| **Total** | **${t.analysis.components.length}** |`),e.push("");let a=new Map;for(let r of t.analysis.pages)a.set(r.path,[]);for(let r of t.analysis.components)for(let s of t.analysis.pages){let o=this.extractFeatureFromPage(s.filePath),i=this.extractFeatureFromComponent(r.filePath);o&&i&&o===i&&a.get(s.path)?.push(r);}e.push("## By Page"),e.push("");for(let[r,s]of a){if(s.length===0)continue;let o=s.filter(c=>c.type==="container"),i=s.filter(c=>c.type==="presentational"),p=s.filter(c=>c.type==="hook");e.push(`### ${r}`),e.push(""),e.push("| Component | Type | Data |"),e.push("|-----------|------|------|");for(let c of o){let h=this.formatComponentDataOps(c);e.push(`| ${c.name} | Container | ${h||"-"} |`);}for(let c of i.slice(0,10))e.push(`| ${c.name} | UI | - |`);i.length>10&&e.push(`| *+${i.length-10} more* | UI | - |`);for(let c of p)e.push(`| ${c.name} | Hook | - |`);e.push("");}e.push("## By Type"),e.push("");for(let[r,s]of n){e.push(`### ${r.charAt(0).toUpperCase()+r.slice(1)} (${s.length})`),e.push(""),e.push("| Name | File |"),e.push("|------|------|");for(let o of s.slice(0,25)){let i=o.filePath.replace("src/features/","").replace("src/","");e.push(`| ${o.name} | ${i} |`);}s.length>25&&e.push(`| *+${s.length-25} more* | |`),e.push("");}return e.join(`
11
+ `)}extractFeatureFromPage(t){let e=t.split("/");return e.length>1?e[0]:null}extractFeatureFromComponent(t){let e=t.match(/src\/features\/([^/]+)/);return e?e[1]:null}formatComponentDataOps(t){let e=[],n=[];for(let u of t.hooks){let g=u.match(/(?:useQuery|Query):\s*(\w+)/),f=u.match(/(?:useMutation|Mutation):\s*(\w+)/);g&&g[1]&&g[1].trim().length>=2?e.push(g[1]):f&&f[1]&&f[1].trim().length>=2&&n.push(f[1]);}let a=e.filter(u=>u&&u.trim().length>=2),r=n.filter(u=>u&&u.trim().length>=2);if(a.length===0&&r.length===0)return "";let s=[],o=2,i=2,p=a.slice(0,o);for(let u of p)s.push(`<span class="gql-op" data-op="${u}">${u}</span>`);let c=r.slice(0,i);for(let u of c)s.push(`<span class="gql-op mutation" data-op="${u}">${u}</span>`);let h=a.slice(o),l=r.slice(i),m=h.length+l.length;if(m>0){let u=JSON.stringify(a).replace(/"/g,"&quot;"),g=JSON.stringify(r).replace(/"/g,"&quot;");s.push(`<span class="gql-ref" data-ref="${t.name}" data-queries="${u}" data-mutations="${g}" title="View all ${a.length} queries and ${r.length} mutations">+${m} more</span>`);}return `<div class="gql-ops-inline">${s.join(" ")}</div>`}generateGraphQLDoc(t){let e=[`# ${t.displayName} - GraphQL`,""],n=t.analysis.graphqlOperations.filter(s=>s.type==="query"),a=t.analysis.graphqlOperations.filter(s=>s.type==="mutation"),r=t.analysis.graphqlOperations.filter(s=>s.type==="fragment");if(e.push("| Type | Count |"),e.push("|------|-------|"),e.push(`| Query | ${n.length} |`),e.push(`| Mutation | ${a.length} |`),e.push(`| Fragment | ${r.length} |`),e.push(`| **Total** | **${t.analysis.graphqlOperations.length}** |`),e.push(""),n.length>0){e.push("## Queries"),e.push("");for(let s of n.slice(0,80)){e.push(`### ${s.name}`),e.push("");let o=s.returnType||"unknown",i=s.variables.length,p=s.usedIn.length;if(e.push(`> Return: \`${o}\` | Variables: ${i} | Used: ${p} files`),e.push(""),s.variables.length>0){e.push("| Variable | Type |"),e.push("|----------|------|");for(let c of s.variables)e.push(`| ${c.name} | \`${c.type}\` |`);e.push("");}s.fields&&s.fields.length>0&&(e.push("```graphql"),e.push(this.formatGraphQLFields(s.fields,0)),e.push("```"),e.push(""));}n.length>80&&e.push(`*+${n.length-80} more queries*
12
+ `);}if(a.length>0){e.push("## Mutations"),e.push("");for(let s of a.slice(0,80)){e.push(`### ${s.name}`),e.push("");let o=s.variables.length,i=s.usedIn.length;if(e.push(`> Variables: ${o} | Used: ${i} files`),e.push(""),s.variables.length>0){e.push("| Variable | Type |"),e.push("|----------|------|");for(let p of s.variables)e.push(`| ${p.name} | \`${p.type}\` |`);e.push("");}s.fields&&s.fields.length>0&&(e.push("```graphql"),e.push(this.formatGraphQLFields(s.fields,0)),e.push("```"),e.push(""));}a.length>80&&e.push(`*+${a.length-80} more mutations*
13
+ `);}if(r.length>0){e.push("## Fragments"),e.push(""),e.push("| Name | Type | Fields |"),e.push("|------|------|--------|");for(let s of r.slice(0,50)){let o=s.fields?.length||0;e.push(`| ${s.name} | ${s.returnType||"-"} | ${o} |`);}r.length>50&&e.push(`| *+${r.length-50} more* | | |`),e.push("");}return e.join(`
14
+ `)}formatGraphQLFields(t,e){if(!t||t.length===0)return "";let n=[];for(let a of t){let r=" ".repeat(e);a.fields&&a.fields.length>0?(n.push(`${r}${a.name} {`),n.push(this.formatGraphQLFields(a.fields,e+1)),n.push(`${r}}`)):n.push(`${r}${a.name}`);}return n.join(`
15
+ `)}generateDataFlowDoc(t){let e=[`# ${t.displayName} - Data Flow`,""],n=t.analysis.dataFlows.filter(o=>o.name.includes("\u{1F4E1}")||o.operations.some(i=>i.includes("Query"))),a=t.analysis.dataFlows.filter(o=>o.name.includes("\u270F\uFE0F")||o.operations.some(i=>i.includes("Mutation"))),r=t.analysis.dataFlows.filter(o=>o.source.type==="context");e.push("## Overview"),e.push(""),e.push("| Type | Count | Direction |"),e.push("|------|-------|-----------|"),e.push(`| \`QUERY\` | ${n.length} | Server \u2192 Component |`),e.push(`| \`MUTATION\` | ${a.length} | Component \u2192 Server |`),e.push(`| \`CONTEXT\` | ${r.length} | Provider \u2192 Consumer |`),e.push(`| **Total** | **${t.analysis.dataFlows.length}** | |`),e.push(""),e.push("## Architecture"),e.push(""),e.push("```mermaid"),e.push("flowchart LR"),e.push(' subgraph Server["GraphQL Server"]'),e.push(" API[(API)]"),e.push(" end"),e.push(' subgraph Client["React Application"]'),e.push(" Apollo[Apollo Client]"),e.push(" Container[Container Component]"),e.push(" View[View Component]"),e.push(" end"),e.push(" API -->|Query Response| Apollo"),e.push(" Apollo -->|Cache/Data| Container"),e.push(" Container -->|Props| View"),e.push(" View -->|User Action| Container"),e.push(" Container -->|Mutation| Apollo"),e.push(" Apollo -->|GraphQL Request| API"),e.push("```"),e.push(""),e.push("## Page Data Flows"),e.push("");for(let o of t.analysis.pages){let i=this.extractFeatureFromPage(o.filePath),p=t.analysis.components.filter(u=>this.extractFeatureFromComponent(u.filePath)===i);if(!(o.dataFetching.length>0||p.some(u=>u.stateManagement.some(g=>g.includes("Apollo")||g.includes("Context")))))continue;e.push(`### ${o.path}`),e.push(""),e.push(`\`FILE: ${o.filePath}\``),e.push("");let h=this.getPageOperations(o,p,t.analysis.graphqlOperations),l=h.queries.filter(u=>u&&u.trim().length>0),m=h.mutations.filter(u=>u&&u.trim().length>0);if(l.length>0||m.length>0){e.push("```mermaid"),e.push("flowchart LR");let u=o.path.replace(/[^a-zA-Z0-9]/g,"_"),g=o.path.replace(/"/g,"'");e.push(` Page${u}["${g}"]`),l.slice(0,5).forEach((f,d)=>{let C=`Q${u}_${d}`,$=f.replace(/"/g,"'").replace(/[<>]/g,"");e.push(` ${C}["${$}"]:::query --> Page${u}`);}),m.slice(0,5).forEach((f,d)=>{let C=`M${u}_${d}`,$=f.replace(/"/g,"'").replace(/[<>]/g,"");e.push(` Page${u} --> ${C}["${$}"]:::mutation`);}),e.push(" classDef query fill:#dbeafe,stroke:#1d4ed8,color:#1e40af"),e.push(" classDef mutation fill:#fce7f3,stroke:#be185d,color:#9d174d"),e.push("```"),e.push("");}if(h.queries.length>0||h.mutations.length>0){if(l.length>0){e.push(`**Queries (${l.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let u of l){let g=u.startsWith("\u2192")||u.startsWith("->"),f=u.replace(/^[→\->\s]+/,"");f&&f.trim().length>0&&(g?e.push(`<span class="gql-ref" data-ref="${f}" title="Component: ${f}">${f}</span>`):e.push(`<span class="gql-op" data-op="${f}">${f}</span>`));}e.push("</div>"),e.push("");}if(m.length>0){e.push(`**Mutations (${m.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let u of m){let g=u.startsWith("\u2192")||u.startsWith("->"),f=u.replace(/^[→\->\s]+/,"");f&&f.trim().length>0&&(g?e.push(`<span class="gql-ref mutation" data-ref="${f}" title="Component: ${f}">${f}</span>`):e.push(`<span class="gql-op mutation" data-op="${f}">${f}</span>`));}e.push("</div>"),e.push("");}}e.push("---"),e.push("");}let s=new Set;for(let o of r)s.add(o.source.name);if(s.size>0){e.push("## Context Providers"),e.push(""),e.push("| Provider | Description |"),e.push("|----------|-------------|");for(let o of s)e.push(`| \`${o}\` | Provides shared state |`);e.push("");}return e.join(`
16
+ `)}getPageOperations(t,e,n){let a=new Set,r=new Set,s=o=>{if(!o)return false;let i=o.trim();return i.length>=2&&/[a-zA-Z]/.test(i)};for(let o of t.dataFetching){let p=(o.operationName?.replace(/^[→\->\s]+/,"")||"").replace(/Document$/g,"");s(p)&&(o.type?.includes("Mutation")?r.add(p):a.add(p));}for(let o of e)for(let i of o.hooks){if(i.includes("Query")){let p=i.match(/:\s*(.+)$/);p&&s(p[1])&&a.add(p[1].trim());}if(i.includes("Mutation")){let p=i.match(/:\s*(.+)$/);p&&s(p[1])&&r.add(p[1].trim());}}return {queries:Array.from(a).filter(s),mutations:Array.from(r).filter(s)}}generateCrossRepoDoc(t){let e=["# \u30AF\u30ED\u30B9\u30EA\u30DD\u30B8\u30C8\u30EA\u5206\u6790","","## \u30A2\u30FC\u30AD\u30C6\u30AF\u30C1\u30E3\u6982\u8981","","```mermaid","flowchart TB"];for(let n of t.repositories){let a=n.name.replace(/[^a-zA-Z0-9]/g,"_");e.push(` subgraph ${a}["${n.displayName}"]`),e.push(` ${a}_core["Core"]`),e.push(" end");}e.push("```"),e.push(""),e.push("## API\u63A5\u7D9A"),e.push("");for(let n of t.crossRepoAnalysis.apiConnections)e.push(`- **${n.frontend}** \u2192 **${n.backend}**: \`${n.endpoint}\``);e.push(""),e.push("## \u5171\u6709\u578B"),e.push("");for(let n of t.crossRepoAnalysis.sharedTypes)e.push(`- \`${n}\``);return e.push(""),e.join(`
17
+ `)}createPageDataFlowDiagram(t,e,n){let a=[],r=[],s=[],o=[];for(let i of e){i.type==="container"&&o.push(i.name);for(let p of i.hooks){if(p.includes("Query")||p.includes("\u{1F4E1}")){let c=p.includes(":")?p.split(":")[1].trim():p;r.includes(c)||r.push(c);}if(p.includes("Mutation")||p.includes("\u270F\uFE0F")){let c=p.includes(":")?p.split(":")[1].trim():p;s.includes(c)||s.push(c);}}}for(let i of t.dataFetching){let p=i.operationName.replace(/^→\s*/,"");i.type.includes("Query")&&!r.includes(p)?r.push(p):i.type.includes("Mutation")&&!s.includes(p)&&s.push(p);}if(a.push(`[Page: ${t.path}]`),a.push("\u2502"),r.length>0||s.length>0){a.push("\u251C\u2500 \u{1F4E1} \u30C7\u30FC\u30BF\u53D6\u5F97 (Query)");for(let i of r.slice(0,5))a.push(`\u2502 \u251C\u2500 ${i.substring(0,40)}`),a.push("\u2502 \u2502 \u2514\u2500 GraphQL Server \u2192 Apollo Cache \u2192 Component");if(r.length>5&&a.push(`\u2502 \u2514\u2500 ... \u4ED6 ${r.length-5} \u4EF6`),s.length>0){a.push("\u2502"),a.push("\u251C\u2500 \u270F\uFE0F \u30C7\u30FC\u30BF\u66F4\u65B0 (Mutation)");for(let i of s.slice(0,5))a.push(`\u2502 \u251C\u2500 ${i.substring(0,40)}`),a.push("\u2502 \u2502 \u2514\u2500 Component \u2192 GraphQL Server \u2192 Apollo Cache");s.length>5&&a.push(`\u2502 \u2514\u2500 ... \u4ED6 ${s.length-5} \u4EF6`);}}if(o.length>0){a.push("\u2502"),a.push("\u251C\u2500 \u{1F4E6} Container Components");for(let i of o.slice(0,5))a.push(`\u2502 \u2514\u2500 ${i}`);o.length>5&&a.push(`\u2502 \u2514\u2500 ... \u4ED6 ${o.length-5} \u4EF6`);}return a.push("\u2502"),a.push("\u2514\u2500 [Render]"),a.join(`
18
+ `)}generateDiagramsDoc(t){let e=["# Diagrams",""];e.push("## Overview"),e.push(""),e.push("| Diagram | Type | Description |"),e.push("|---------|------|-------------|");for(let n of t)e.push(`| ${n.title} | \`${n.type.toUpperCase()}\` | Auto-generated |`);e.push("");for(let n of t)e.push(`## ${n.title}`),e.push(""),e.push(`\`TYPE: ${n.type.toUpperCase()}\``),e.push(""),e.push("```mermaid"),e.push(n.content),e.push("```"),e.push("");return e.join(`
19
+ `)}};export{F as a,q as b};
package/dist/cli.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  #!/usr/bin/env node
2
- export {};