@wtdlee/repomap 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -12
- package/dist/analyzers/index.d.ts +175 -25
- package/dist/analyzers/index.js +1 -1
- package/dist/{chunk-QZWPOG5B.js → chunk-GCIRJGW3.js} +78 -45
- package/dist/chunk-H7VVRHQZ.js +34 -0
- package/dist/chunk-HPBPEGHS.js +19 -0
- package/dist/{chunk-UR7HVBHH.js → chunk-JDM7Y7PX.js} +34 -28
- package/dist/{chunk-H4YGP3GL.js → chunk-OQAXO3X2.js} +346 -22
- package/dist/chunk-TNUKDIO7.js +5 -0
- package/dist/cli.js +17 -33
- package/dist/dataflow-analyzer-CJ2T0cGS.d.ts +345 -0
- package/dist/generators/assets/docs.css +176 -46
- package/dist/generators/assets/favicon/apple-touch-icon.png +0 -0
- package/dist/generators/assets/favicon/favicon-96x96.png +0 -0
- package/dist/generators/assets/favicon/favicon.ico +0 -0
- package/dist/generators/assets/favicon/favicon.svg +3 -0
- package/dist/generators/assets/favicon/site.webmanifest +21 -0
- package/dist/generators/assets/favicon/web-app-manifest-192x192.png +0 -0
- package/dist/generators/assets/favicon/web-app-manifest-512x512.png +0 -0
- package/dist/generators/assets/page-map.css +392 -87
- package/dist/generators/assets/rails-map.css +221 -48
- package/dist/generators/index.d.ts +0 -8
- package/dist/generators/index.js +1 -1
- package/dist/index.d.ts +18 -9
- package/dist/index.js +1 -1
- package/dist/page-map-generator-3GO6GL2P.js +1 -0
- package/dist/{rails-FFISZ4AE.js → rails-3HNUFTQV.js} +1 -1
- package/dist/rails-map-generator-CAQZUBI6.js +1 -0
- package/dist/server/index.d.ts +2 -6
- package/dist/server/index.js +1 -1
- package/dist/types.d.ts +12 -3
- package/package.json +1 -1
- package/dist/chunk-PTR5IROV.js +0 -36
- package/dist/chunk-WJIBUCXB.js +0 -2
- package/dist/chunk-XWZH2RDG.js +0 -19
- package/dist/dataflow-analyzer-mlxaq5qn.d.ts +0 -206
- package/dist/page-map-generator-HBKSOX2E.js +0 -1
- package/dist/rails-map-generator-UFLCMFAT.js +0 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let r=[],u=n?.envResult,t=n?.railsAnalysis,
|
|
1
|
+
var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let r=[],u=n?.envResult,t=n?.railsAnalysis,o=n?.activeTab||"pages",e=s.repositories[0]?.displayName||s.repositories[0]?.name||"Repository";for(let p of s.repositories){this.graphqlOps.push(...p.analysis?.graphqlOperations||[]),this.apiCalls.push(...p.analysis?.apiCalls||[]);let f=p.analysis?.components||[];for(let a of f)this.components.push({name:a.name,filePath:a.filePath,type:a.type,dependencies:a.dependencies||[],hooks:a.hooks||[]});}for(let p of s.repositories){let f=p.analysis?.pages||[];for(let a of f)r.push({...a,repo:p.name,children:[],parent:null,depth:0});}let{rootPages:i,relations:l}=this.buildHierarchy(r);return this.renderPageMapHtml(r,i,l,e,{envResult:u,railsAnalysis:t,activeTab:o})}buildHierarchy(s){let n=new Map,r=[];for(let t of s)n.set(t.path,t);for(let t of s){let o=t.path.split("/").filter(Boolean);for(let e=o.length-1;e>=1;e--){let i="/"+o.slice(0,e).join("/"),l=n.get(i);if(l){t.parent=i,t.depth=l.depth+1,l.children.includes(t.path)||l.children.push(t.path),r.push({from:i,to:t.path,type:"parent-child",description:`Sub-page of ${i}`});break}}if(t.parent||(t.depth=Math.max(0,o.length-1)),t.layout)for(let e of s)e.path!==t.path&&e.layout===t.layout&&(r.find(l=>l.type==="same-layout"&&(l.from===t.path&&l.to===e.path||l.from===e.path&&l.to===t.path))||r.push({from:t.path,to:e.path,type:"same-layout",description:`Both use ${t.layout}`}));}return {rootPages:s.filter(t=>!t.parent).sort((t,o)=>t.path.localeCompare(o.path)),relations:r}}renderPageMapHtml(s,n,r,u,t){let o=t?.envResult,e=t?.railsAnalysis,i=t?.activeTab||"pages",l=JSON.stringify(this.graphqlOps.map(c=>({name:c.name,type:c.type,variables:c.variables,fields:c.fields,returnType:c.returnType,usedIn:c.usedIn}))),p=JSON.stringify(this.components),f=e?JSON.stringify(e.routes.routes):"[]",a=e?JSON.stringify(e.controllers.controllers):"[]",h=e?JSON.stringify(e.models.models):"[]",v=e?JSON.stringify(e.views):'{ "views": [], "pages": [], "summary": {} }',y=e?JSON.stringify(e.react):'{ "components": [], "entryPoints": [], "summary": {} }',d=e?JSON.stringify(e.grpc):'{ "services": [] }',C=e?JSON.stringify(e.summary):"null",m=o?.hasRails||false,b=o?.hasNextjs||false,w=o?.hasReact||false,x=new Map;for(let c of s){let g=c.path.split("/").filter(Boolean)[0]||"root";x.has(g)||x.set(g,[]),x.get(g)?.push(c);}return `<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Page Map</title>
|
|
6
|
+
<title>Page Map - Repomap</title>
|
|
7
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg">
|
|
9
|
+
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png">
|
|
10
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
|
|
11
|
+
<link rel="manifest" href="/favicon/site.webmanifest">
|
|
7
12
|
<link rel="stylesheet" href="/page-map.css">
|
|
8
13
|
</head>
|
|
9
14
|
<body>
|
|
@@ -141,7 +146,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
141
146
|
// Frontend data
|
|
142
147
|
const pages = ${JSON.stringify(s)};
|
|
143
148
|
const relations = ${JSON.stringify(r)};
|
|
144
|
-
const graphqlOps = ${
|
|
149
|
+
const graphqlOps = ${l};
|
|
145
150
|
const components = ${p};
|
|
146
151
|
const apiCallsData = ${JSON.stringify(this.apiCalls)};
|
|
147
152
|
window.apiCalls = apiCallsData;
|
|
@@ -1938,8 +1943,10 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
1938
1943
|
// Extract GraphQL from this component's hooks
|
|
1939
1944
|
if (comp.hooks) {
|
|
1940
1945
|
comp.hooks.forEach(hook => {
|
|
1941
|
-
|
|
1942
|
-
|
|
1946
|
+
// Only match hooks with "Query: " or "Mutation: " prefix (from dataflow analyzer)
|
|
1947
|
+
// This avoids matching unrelated hooks like useQueryParams
|
|
1948
|
+
if (hook.startsWith('Query: ') || hook.startsWith('Mutation: ') || hook.startsWith('Subscription: ')) {
|
|
1949
|
+
let queryName = hook.replace('Query: ', '').replace('Mutation: ', '').replace('Subscription: ', '').trim();
|
|
1943
1950
|
// Skip empty names or hooks without actual operation names
|
|
1944
1951
|
if (!queryName) {
|
|
1945
1952
|
return;
|
|
@@ -1984,38 +1991,41 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
1984
1991
|
const graphqlOps = allDataFetching.filter(df => df.type !== 'component');
|
|
1985
1992
|
const componentRefs = allDataFetching.filter(df => df.type === 'component');
|
|
1986
1993
|
|
|
1987
|
-
// Parse operations to extract path
|
|
1994
|
+
// Parse operations to extract source path from df.source field or operationName pattern
|
|
1988
1995
|
const parsedOps = graphqlOps.map(df => {
|
|
1989
1996
|
const rawName = df.operationName || '';
|
|
1990
|
-
|
|
1997
|
+
const source = df.source || '';
|
|
1998
|
+
|
|
1999
|
+
// Count leading arrows for depth (from extractComponentGraphQL)
|
|
1991
2000
|
const arrowCount = (rawName.match(/\u2192/g) || []).length;
|
|
1992
2001
|
|
|
1993
|
-
// Extract query name and
|
|
1994
|
-
let queryName = rawName.replace(/^[\u2192\\s]+/, '').
|
|
1995
|
-
let sourcePath = '';
|
|
2002
|
+
// Extract query name - remove arrows and (via xxx) pattern
|
|
2003
|
+
let queryName = rawName.replace(/^[\u2192\\s]+/, '').trim();
|
|
2004
|
+
let sourcePath = 'Direct';
|
|
2005
|
+
let depth = 0;
|
|
1996
2006
|
|
|
1997
|
-
// Extract
|
|
2007
|
+
// Method 1: Extract from (via xxx) pattern in operationName (from extractComponentGraphQL)
|
|
1998
2008
|
const viaMatch = queryName.match(/\\s*\\(via\\s+([^)]+)\\)/);
|
|
1999
2009
|
if (viaMatch) {
|
|
2000
2010
|
sourcePath = viaMatch[1];
|
|
2001
2011
|
queryName = queryName.replace(viaMatch[0], '').trim();
|
|
2012
|
+
depth = arrowCount || 1;
|
|
2002
2013
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2014
|
+
// Method 2: Use df.source field (from engine.ts enrichPagesWithHookGraphQL)
|
|
2015
|
+
else if (source.startsWith('component:')) {
|
|
2016
|
+
sourcePath = source.replace('component:', '');
|
|
2017
|
+
depth = 1;
|
|
2018
|
+
} else if (source.startsWith('hook:')) {
|
|
2019
|
+
sourcePath = source.replace('hook:', '');
|
|
2020
|
+
depth = 1;
|
|
2009
2021
|
}
|
|
2010
|
-
|
|
2011
|
-
// Further clean the query name
|
|
2012
|
-
queryName = queryName.replace(/^[\u2192\\s]+/, '').trim();
|
|
2022
|
+
// "import:xxx" or no source stays as Direct
|
|
2013
2023
|
|
|
2014
2024
|
return {
|
|
2015
2025
|
...df,
|
|
2016
2026
|
queryName,
|
|
2017
|
-
sourcePath
|
|
2018
|
-
depth
|
|
2027
|
+
sourcePath,
|
|
2028
|
+
depth
|
|
2019
2029
|
};
|
|
2020
2030
|
});
|
|
2021
2031
|
|
|
@@ -2077,21 +2087,41 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2077
2087
|
: directOps.length + ' total';
|
|
2078
2088
|
dataHtml += '<div class="detail-section"><h4>Data Operations <span style="font-weight:normal;font-size:11px;color:var(--text2)">(' + countLabel + ')</span></h4>';
|
|
2079
2089
|
|
|
2090
|
+
// Calculate continuous UI indent levels (depth gaps become 1 step)
|
|
2091
|
+
let prevDepth = -1;
|
|
2092
|
+
let uiLevel = -1;
|
|
2093
|
+
const pathToUiLevel = new Map();
|
|
2080
2094
|
sortedPaths.forEach(pathName => {
|
|
2081
2095
|
const ops = groupedByPath.get(pathName);
|
|
2082
|
-
const
|
|
2083
|
-
|
|
2096
|
+
const depth = pathName === 'Direct' ? 0 : (ops[0]?.depth || 1);
|
|
2097
|
+
if (depth > prevDepth) {
|
|
2098
|
+
uiLevel++;
|
|
2099
|
+
}
|
|
2100
|
+
pathToUiLevel.set(pathName, uiLevel);
|
|
2101
|
+
prevDepth = depth;
|
|
2102
|
+
});
|
|
2084
2103
|
|
|
2085
|
-
|
|
2104
|
+
sortedPaths.forEach(pathName => {
|
|
2105
|
+
const ops = groupedByPath.get(pathName);
|
|
2106
|
+
const isDirect = pathName === 'Direct';
|
|
2107
|
+
const depthIndicator = isDirect ? '' : '\u21B3 ';
|
|
2108
|
+
const pathLabel = isDirect ? 'Direct (this page)' : pathName;
|
|
2109
|
+
// UI indent: 4px per level added to base padding (10px)
|
|
2110
|
+
const uiLevel = pathToUiLevel.get(pathName) || 0;
|
|
2111
|
+
const uiIndent = uiLevel * 4;
|
|
2112
|
+
const totalPadding = 10 + uiIndent;
|
|
2113
|
+
|
|
2114
|
+
// Group container, header aligned with detail-item content
|
|
2086
2115
|
dataHtml += '<div class="data-path-group" style="margin:8px 0">' +
|
|
2087
|
-
'<div class="data-path-header" style="font-size:11px;color:var(--text2);margin-bottom:4px;padding-left:'+
|
|
2116
|
+
'<div class="data-path-header" style="font-size:11px;color:var(--text2);margin-bottom:4px;padding-left:'+totalPadding+'px">' +
|
|
2088
2117
|
depthIndicator + '<span class="text-accent">' + pathLabel + '</span> (' + ops.length + ')' +
|
|
2089
2118
|
'</div>';
|
|
2090
2119
|
|
|
2091
2120
|
ops.forEach(op => {
|
|
2092
2121
|
const isQ = !op.type?.includes('Mutation');
|
|
2093
2122
|
const srcArg = op.sourcePath !== 'Direct' ? ",\\'"+op.sourcePath.replace(/'/g, "\\\\'")+"\\'": '';
|
|
2094
|
-
|
|
2123
|
+
// detail-item keeps base padding, adds indent
|
|
2124
|
+
dataHtml += '<div class="detail-item data-op" style="padding:8px 10px 8px '+totalPadding+'px" onclick="showDataDetail(\\''+op.queryName.replace(/'/g, "\\\\'")+"\\'"+srcArg+')">' +
|
|
2095
2125
|
'<span class="tag '+(isQ?'tag-query':'tag-mutation')+'" style="font-size:10px">'+(isQ?'Q':'M')+'</span> '+op.queryName+'</div>';
|
|
2096
2126
|
});
|
|
2097
2127
|
|
|
@@ -2177,9 +2207,9 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2177
2207
|
if (!comp || visited.has(comp.name)) return false;
|
|
2178
2208
|
visited.add(comp.name);
|
|
2179
2209
|
|
|
2180
|
-
// Check hooks for GraphQL queries
|
|
2181
|
-
if (comp.hooks && comp.hooks.some(h =>
|
|
2182
|
-
h.
|
|
2210
|
+
// Check hooks for GraphQL queries (only match "Query: X" or "Mutation: X" format)
|
|
2211
|
+
if (comp.hooks && comp.hooks.some(h =>
|
|
2212
|
+
h.startsWith('Query: ') || h.startsWith('Mutation: ') || h.startsWith('Subscription: ')
|
|
2183
2213
|
)) {
|
|
2184
2214
|
return true;
|
|
2185
2215
|
}
|
|
@@ -2264,9 +2294,9 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2264
2294
|
]);
|
|
2265
2295
|
|
|
2266
2296
|
// Debug: log pagesWithGraphQL count
|
|
2267
|
-
console.log('\u{1F4CA} GraphQL Stats: totalComponents=' + components.length +
|
|
2268
|
-
', componentsWithGraphQL=' + components.filter(c => c.hooks && c.hooks.some(h => h.
|
|
2269
|
-
', pagesWithGraphQL=' + pagesWithGraphQL.size +
|
|
2297
|
+
console.log('\u{1F4CA} GraphQL Stats: totalComponents=' + components.length +
|
|
2298
|
+
', componentsWithGraphQL=' + components.filter(c => c.hooks && c.hooks.some(h => h.startsWith('Query: ') || h.startsWith('Mutation: '))).length +
|
|
2299
|
+
', pagesWithGraphQL=' + pagesWithGraphQL.size +
|
|
2270
2300
|
', totalPages=' + pages.length);
|
|
2271
2301
|
|
|
2272
2302
|
const pagesWithRestApi = new Set(pages.filter(p => {
|
|
@@ -2486,6 +2516,8 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2486
2516
|
document.querySelectorAll('.page-item').forEach(p => {
|
|
2487
2517
|
p.style.removeProperty('display');
|
|
2488
2518
|
p.style.display = 'flex';
|
|
2519
|
+
// Reset opacity (set by hierarchies filter)
|
|
2520
|
+
p.style.removeProperty('opacity');
|
|
2489
2521
|
});
|
|
2490
2522
|
}
|
|
2491
2523
|
|
|
@@ -2644,9 +2676,8 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2644
2676
|
closeDetail();
|
|
2645
2677
|
});
|
|
2646
2678
|
|
|
2647
|
-
// Expand "more" items
|
|
2679
|
+
// Expand "more" items - inserts items before the button and removes the button
|
|
2648
2680
|
window.expandMore = function(type, items, btn) {
|
|
2649
|
-
const container = btn.parentElement;
|
|
2650
2681
|
let html = '';
|
|
2651
2682
|
items.forEach(item => {
|
|
2652
2683
|
if (type === 'usedIn') {
|
|
@@ -2659,7 +2690,9 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2659
2690
|
'<span class="tag" style="background:#6b7280">FRAGMENT</span> '+item.name+'</div>';
|
|
2660
2691
|
}
|
|
2661
2692
|
});
|
|
2662
|
-
|
|
2693
|
+
// Insert new items before the button, then remove the button
|
|
2694
|
+
btn.insertAdjacentHTML('beforebegin', html);
|
|
2695
|
+
btn.remove();
|
|
2663
2696
|
};
|
|
2664
2697
|
|
|
2665
2698
|
function showDataDetail(rawName, sourcePath) {
|
|
@@ -2779,7 +2812,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2779
2812
|
op.usedIn.slice(0,8).forEach(f => { html += '<div class="detail-item">'+f+'</div>'; });
|
|
2780
2813
|
if (op.usedIn.length > 8) {
|
|
2781
2814
|
const remaining = op.usedIn.slice(8);
|
|
2782
|
-
html += '<div class="expand-more" onclick="expandMore(\\'usedIn\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" style="color:var(--accent);font-size:11px;cursor:pointer;padding:4px 0">\u25B8 Show '+(op.usedIn.length-8)+' more files</div>';
|
|
2815
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'usedIn\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" style="color:var(--accent);font-size:11px;cursor:pointer;padding:4px 0">\u25B8 Show '+(op.usedIn.length-8)+' more files</div>';
|
|
2783
2816
|
}
|
|
2784
2817
|
html += '</div>';
|
|
2785
2818
|
}
|
|
@@ -2822,7 +2855,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2822
2855
|
});
|
|
2823
2856
|
if (queries.length > 5) {
|
|
2824
2857
|
const remaining = queries.slice(5).map(o => ({name: o.name}));
|
|
2825
|
-
html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 5) + ' more queries</div>';
|
|
2858
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 5) + ' more queries</div>';
|
|
2826
2859
|
}
|
|
2827
2860
|
}
|
|
2828
2861
|
|
|
@@ -2834,7 +2867,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2834
2867
|
});
|
|
2835
2868
|
if (mutations.length > 5) {
|
|
2836
2869
|
const remaining = mutations.slice(5).map(o => ({name: o.name}));
|
|
2837
|
-
html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more mutations</div>';
|
|
2870
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more mutations</div>';
|
|
2838
2871
|
}
|
|
2839
2872
|
}
|
|
2840
2873
|
|
|
@@ -2846,7 +2879,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2846
2879
|
});
|
|
2847
2880
|
if (fragments.length > 3) {
|
|
2848
2881
|
const remaining = fragments.slice(3).map(o => ({name: o.name}));
|
|
2849
|
-
html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more fragments</div>';
|
|
2882
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more fragments</div>';
|
|
2850
2883
|
}
|
|
2851
2884
|
}
|
|
2852
2885
|
|
|
@@ -2962,7 +2995,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2962
2995
|
});
|
|
2963
2996
|
if (queries.length > 8) {
|
|
2964
2997
|
const remaining = queries.slice(8).map(o => ({name: o.name}));
|
|
2965
|
-
html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 8) + ' more</div>';
|
|
2998
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 8) + ' more</div>';
|
|
2966
2999
|
}
|
|
2967
3000
|
}
|
|
2968
3001
|
|
|
@@ -2974,7 +3007,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2974
3007
|
});
|
|
2975
3008
|
if (mutations.length > 5) {
|
|
2976
3009
|
const remaining = mutations.slice(5).map(o => ({name: o.name}));
|
|
2977
|
-
html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more</div>';
|
|
3010
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more</div>';
|
|
2978
3011
|
}
|
|
2979
3012
|
}
|
|
2980
3013
|
|
|
@@ -2986,7 +3019,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
2986
3019
|
});
|
|
2987
3020
|
if (fragments.length > 3) {
|
|
2988
3021
|
const remaining = fragments.slice(3).map(o => ({name: o.name}));
|
|
2989
|
-
html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more</div>';
|
|
3022
|
+
html += '<div class="expand-more" onclick="event.stopPropagation(); expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more</div>';
|
|
2990
3023
|
}
|
|
2991
3024
|
}
|
|
2992
3025
|
|
|
@@ -3588,7 +3621,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
3588
3621
|
setTimeout(updatePageGqlCounts, 100);
|
|
3589
3622
|
</script>
|
|
3590
3623
|
</body>
|
|
3591
|
-
</html>`}buildTreeHtml(s,n){let r=["#ef4444","#f97316","#eab308","#22c55e","#14b8a6","#3b82f6","#8b5cf6","#ec4899"],u=0;return Array.from(s.entries()).sort((t,
|
|
3624
|
+
</html>`}buildTreeHtml(s,n){let r=["#ef4444","#f97316","#eab308","#22c55e","#14b8a6","#3b82f6","#8b5cf6","#ec4899"],u=0;return Array.from(s.entries()).sort((t,o)=>t[0].localeCompare(o[0])).map(([t,o])=>{let e=r[u++%r.length],i=o.sort((a,h)=>a.path.localeCompare(h.path)),l=new Set(i.map(a=>a.path)),p=new Map;for(let a of i){let h=a.path.split("/").filter(Boolean),v=0;for(let y=h.length-1;y>=1;y--){let d="/"+h.slice(0,y).join("/");if(l.has(d)){v=(p.get(d)??0)+1;break}}p.set(a.path,v);}let f=i.map(a=>{let h=this.getPageType(a.path),v=p.get(a.path)??0,d=a.repo||"",C=n.some(g=>g.repo&&g.repo!==d),m=d.split("/").pop()?.split("-").map(g=>g.substring(0,4)).join("-")||d.substring(0,8),b=C&&d?`<span class="tag tag-repo" title="${d}">${m}</span>`:"",w=/^\/[A-Z]/.test(a.path)||a.filePath&&a.filePath.includes("components/pages"),x=w&&a.filePath?a.filePath.replace(/\.tsx?$/,"").replace(/^(frontend\/src\/|src\/)/,""):a.path,c=w?'<span class="tag tag-info" title="SPA Component Page">SPA</span>':"";return `<div class="page-item" data-path="${a.path}" data-repo="${d}" onclick="selectPage('${a.path}')" style="--depth:${v}">
|
|
3592
3625
|
<span class="page-type" style="--type-color:${h.color}">${h.label}</span>
|
|
3593
3626
|
<span class="page-path">${x}</span>
|
|
3594
3627
|
<div class="page-tags">
|
|
@@ -3602,7 +3635,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
|
|
|
3602
3635
|
<div class="group-header" onclick="toggleGroup(this)" style="--group-color:${e}">
|
|
3603
3636
|
<span class="group-arrow">\u25BC</span>
|
|
3604
3637
|
<span class="group-name">/${t}</span>
|
|
3605
|
-
<span class="group-count">${
|
|
3638
|
+
<span class="group-count">${o.length}</span>
|
|
3606
3639
|
</div>
|
|
3607
3640
|
<div class="group-content">${f}</div>
|
|
3608
3641
|
</div>`}).join("")}getPageType(s){let n=s.split("/").filter(Boolean).pop()||"";return n==="new"||s.endsWith("/new")?{label:"CREATE",color:"#22c55e"}:n==="edit"||s.includes("/edit")?{label:"EDIT",color:"#f59e0b"}:n.startsWith("[")||n.startsWith(":")?{label:"DETAIL",color:"#3b82f6"}:s.includes("setting")?{label:"SETTINGS",color:"#6b7280"}:{label:"LIST",color:"#06b6d4"}}};export{P as a};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import*as G from'fs';import*as x from'path';import {Parser,Language}from'web-tree-sitter';import {fileURLToPath}from'url';import {createRequire}from'module';import {glob}from'glob';import*as A from'fs/promises';var ue=createRequire(import.meta.url);var me=fileURLToPath(import.meta.url);x.dirname(me);var te=false,O=null,D=null;async function se(){if(D&&O)return D;te||(await Parser.init(),te=true),D=new Parser;let l=null;try{let e=ue.resolve("tree-sitter-wasms/package.json");l=x.join(x.dirname(e),"out/tree-sitter-ruby.wasm");}catch{let e=x.join(process.cwd(),"node_modules/tree-sitter-wasms/out/tree-sitter-ruby.wasm");G.existsSync(e)&&(l=e);}if(!l||!G.existsSync(l))throw new Error("tree-sitter-ruby.wasm not found. Please ensure tree-sitter-wasms package is installed.");return O=await Language.load(l),D.setLanguage(O),D}async function ne(l){let t=(await se()).parse(l);if(!t)throw new Error("Failed to parse Ruby code");return t}async function N(l){let e=G.readFileSync(l,"utf-8");return ne(e)}function R(l,e){let t=[];l.type===e&&t.push(l);for(let o=0;o<l.childCount;o++){let n=l.child(o);n&&t.push(...R(n,e));}return t}function L(l,e){for(let t=0;t<l.childCount;t++){let o=l.child(t);if(o&&o.type===e)return o}return null}function w(l,e){let t=[];for(let o=0;o<l.childCount;o++){let n=l.child(o);n&&n.type===e&&t.push(n);}return t}function S(l){let e=l.childForFieldName("arguments");if(!e)return [];let t=[];for(let o=0;o<e.childCount;o++){let n=e.child(o);n&&n.type!=="("&&n.type!==")"&&n.type!==","&&t.push(n);}return t}function F(l){let e=l.childForFieldName("name");return e?e.text:null}function M(l){let e=l.childForFieldName("superclass");if(!e)return null;let t=L(e,"constant")||L(e,"scope_resolution");return t?t.text:null}function U(l){let e=l.childForFieldName("name");return e?e.text:null}function Z(l){let e=l.childForFieldName("parameters");if(!e)return [];let t=[];for(let o=0;o<e.childCount;o++){let n=e.child(o);if(n&&(n.type==="identifier"||n.type==="keyword_parameter"||n.type==="optional_parameter"||n.type==="splat_parameter")){let s=n.childForFieldName("name")||n;s.type==="identifier"?t.push(s.text):t.push(n.text);}}return t}var k=class{constructor(e){this.rootPath=e;this.routesDir=x.join(e,"config","routes");}routesDir;routes=[];namespaces=[];resources=[];mountedEngines=[];drawnFiles=[];errors=[];async analyze(){let e=x.join(this.rootPath,"config","routes.rb");if(!G.existsSync(e))return {routes:[],namespaces:[],resources:[],mountedEngines:[],drawnFiles:[],errors:[`routes.rb not found at ${e}`]};try{await this.parseRoutesFile(e,[]);}catch(t){this.errors.push(`Error parsing ${e}: ${t}`);}return {routes:this.routes,namespaces:[...new Set(this.namespaces)],resources:this.resources,mountedEngines:this.mountedEngines,drawnFiles:this.drawnFiles,errors:this.errors}}async parseRoutesFile(e,t){let n=(await N(e)).rootNode,s=R(n,"call");for(let a of s){let r=a.childForFieldName("method");if(!r)continue;let c=r.text,i=a.startPosition.row+1;switch(c){case "get":case "post":case "put":case "patch":case "delete":case "match":this.parseHttpRoute(a,c,t,i);break;case "resources":case "resource":await this.parseResources(a,t,i,c==="resource");break;case "namespace":await this.parseNamespace(a,t,e);break;case "mount":this.parseMount(a,i);break;case "draw":await this.parseDraw(a,t);break;case "devise_for":this.parseDeviseFor(a,t,i);break;case "root":this.parseRoot(a,t,i);break}}}parseHttpRoute(e,t,o,n){let s=S(e);if(s.length===0)return;let a=s[0],r=this.extractStringValue(a);if(!r)return;let c="",i="";for(let p of s)if(p.type==="hash"||p.type==="pair"){let m=p.type==="hash"?w(p,"pair"):[p];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(p.type==="string"||p.type==="string_content"){let m=this.extractStringValue(p);m&&m.includes("#")&&!c&&([c,i]=m.split("#"));}if(!c&&!i){let p=r.replace(/^\//,"").split("/");c=p[0]||"",i=p[1]||"index";}o.length>0&&c&&!c.includes("/")&&(c=`${o.join("/")}/${c}`);let u=this.buildPath(o,r);this.routes.push({method:t==="match"?"ALL":t.toUpperCase(),path:u,controller:c,action:i,namespace:o.join("/")||void 0,line:n});}async parseResources(e,t,o,n){let s=S(e);if(s.length===0)return;let r=s[0].text.replace(/^:/,""),c={name:r,controller:t.length>0?`${t.join("/")}/${r}`:r,nested:[],memberRoutes:[],collectionRoutes:[],line:o};for(let u of s)if(u.type==="hash"){let p=w(u,"pair");for(let m of p){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,t,n),this.resources.push(c);let i=e.childForFieldName("block");if(i){let u=R(i,"call");for(let p of u){let m=p.childForFieldName("method")?.text;if(m==="member"){let d=p.childForFieldName("block");d&&this.parseMemberCollectionRoutes(d,c,t,"member");}else if(m==="collection"){let d=p.childForFieldName("block");d&&this.parseMemberCollectionRoutes(d,c,t,"collection");}}}}parseMemberCollectionRoutes(e,t,o,n){let s=R(e,"call");for(let a of s){let r=a.childForFieldName("method");if(!r)continue;let c=r.text;if(!["get","post","put","patch","delete"].includes(c))continue;let i=S(a);if(i.length===0)continue;let u=i[0].text.replace(/^:/,""),p=n==="member"?`/${t.name}/:id/${u}`:`/${t.name}/${u}`,m={method:c.toUpperCase(),path:this.buildPath(o,p),controller:t.controller,action:u,namespace:o.join("/")||void 0,line:a.startPosition.row+1};n==="member"?t.memberRoutes.push(m):t.collectionRoutes.push(m),this.routes.push(m);}}async parseNamespace(e,t,o){let n=S(e);if(n.length===0)return;let s=n[0].text.replace(/^:/,"");this.namespaces.push(s);let a=[...t,s],r=e.childForFieldName("block");if(r){let c=R(r,"call");for(let i of c){let u=i.childForFieldName("method");if(!u)continue;let p=u.text,m=i.startPosition.row+1;switch(p){case "get":case "post":case "put":case "patch":case "delete":case "match":this.parseHttpRoute(i,p,a,m);break;case "resources":case "resource":await this.parseResources(i,a,m,p==="resource");break;case "draw":await this.parseDraw(i,a);break}}}}parseMount(e,t){let o=S(e);if(o.length===0)return;let s=o[0].text,a="/";for(let r of o)if(r.type==="hash"||r.type==="pair"){let c=r.type==="hash"?w(r,"pair"):[r];for(let i of c){let u=i.child(0)?.text?.replace(/^:/,""),p=i.child(2);u==="at"&&p&&(a=this.extractStringValue(p)||a);}}else if(r.type==="string"){let c=this.extractStringValue(r);c&&c.startsWith("/")&&(a=c);}this.mountedEngines.push({engine:s,mountPath:a,line:t});}async parseDraw(e,t){let o=S(e);if(o.length===0)return;let n=o[0].text.replace(/^:/,""),s=x.join(this.routesDir,`${n}.rb`);if(G.existsSync(s)){this.drawnFiles.push(s);try{await this.parseRoutesFile(s,t);}catch(a){this.errors.push(`Error parsing drawn file ${s}: ${a}`);}}}parseDeviseFor(e,t,o){let n=S(e);if(n.length===0)return;let s=n[0].text.replace(/^:/,""),a=[{method:"GET",path:`/${s}/sign_in`,action:"new",controller:"devise/sessions"},{method:"POST",path:`/${s}/sign_in`,action:"create",controller:"devise/sessions"},{method:"DELETE",path:`/${s}/sign_out`,action:"destroy",controller:"devise/sessions"},{method:"GET",path:`/${s}/password/new`,action:"new",controller:"devise/passwords"},{method:"POST",path:`/${s}/password`,action:"create",controller:"devise/passwords"},{method:"GET",path:`/${s}/sign_up`,action:"new",controller:"devise/registrations"},{method:"POST",path:`/${s}`,action:"create",controller:"devise/registrations"}];for(let r of a)this.routes.push({method:r.method,path:this.buildPath(t,r.path),controller:r.controller,action:r.action,namespace:t.join("/")||void 0,line:o,authenticated:false});}parseRoot(e,t,o){let n=S(e),s="",a="index";for(let r of n)if(r.type==="string"){let c=this.extractStringValue(r);c&&c.includes("#")&&([s,a]=c.split("#"));}else if(r.type==="hash"||r.type==="pair"){let c=r.type==="hash"?w(r,"pair"):[r];for(let i of c){let u=i.child(0)?.text?.replace(/^:/,""),p=i.child(2);if(u==="to"&&p){let m=this.extractStringValue(p);m&&m.includes("#")&&([s,a]=m.split("#"));}}}s&&this.routes.push({method:"GET",path:this.buildPath(t,"/"),controller:s,action:a,namespace:t.join("/")||void 0,line:o});}generateResourceRoutes(e,t,o){let n=this.buildPath(t,`/${e.name}`),s=o?["show","new","create","edit","update","destroy"]:["index","show","new","create","edit","update","destroy"],a=e.only||(e.except?s.filter(i=>!e.except.includes(i)):s),r=[];o||a.includes("index")&&r.push({method:"GET",path:n,action:"index"}),a.includes("new")&&r.push({method:"GET",path:`${n}/new`,action:"new"}),a.includes("create")&&r.push({method:"POST",path:n,action:"create"});let c=o?n:`${n}/:id`;a.includes("show")&&r.push({method:"GET",path:c,action:"show"}),a.includes("edit")&&r.push({method:"GET",path:`${c}/edit`,action:"edit"}),a.includes("update")&&(r.push({method:"PUT",path:c,action:"update"}),r.push({method:"PATCH",path:c,action:"update"})),a.includes("destroy")&&r.push({method:"DELETE",path:c,action:"destroy"});for(let i of r)this.routes.push({method:i.method,path:i.path,controller:e.controller,action:i.action,namespace:t.join("/")||void 0,line:e.line});}buildPath(e,t){return t.startsWith("/")?t:`${e.length>0?`/${e.join("/")}`:""}/${t}`}extractStringValue(e){if(e.type==="string"){let t=L(e,"string_content");return t?t.text:e.text.replace(/^["']|["']$/g,"")}return e.type==="string_content"?e.text:e.type==="simple_symbol"||e.type==="symbol"?e.text.replace(/^:/,""):e.text.replace(/^["']|["']$/g,"")}extractArrayValues(e){let t=[];if(e.type==="array")for(let o=0;o<e.childCount;o++){let n=e.child(o);if(n&&n.type!=="["&&n.type!=="]"&&n.type!==","){let s=this.extractStringValue(n);s&&t.push(s);}}else {let o=this.extractStringValue(e);o&&t.push(o);}return t}};async function de(){let l=process.argv[2]||process.cwd();console.log(`Analyzing routes in: ${l}`);let t=await new k(l).analyze();if(console.log(`
|
|
2
|
+
=== Rails Routes Analysis ===
|
|
3
|
+
`),console.log(`Total routes: ${t.routes.length}`),console.log(`Namespaces: ${t.namespaces.join(", ")||"(none)"}`),console.log(`Resources: ${t.resources.length}`),console.log(`Mounted engines: ${t.mountedEngines.length}`),console.log(`External route files: ${t.drawnFiles.length}`),t.errors.length>0){console.log(`
|
|
4
|
+
--- Errors ---`);for(let o of t.errors)console.log(` \u274C ${o}`);}console.log(`
|
|
5
|
+
--- Sample Routes (first 30) ---`);for(let o of t.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 t.mountedEngines)console.log(` ${o.engine} => ${o.mountPath}`);console.log(`
|
|
7
|
+
--- External Route Files ---`);for(let o of t.drawnFiles)console.log(` ${x.basename(o)}`);}var fe=import.meta.url===`file://${process.argv[1]}`;fe&&de().catch(console.error);var V=class{constructor(e){this.rootPath=e;this.controllersDir=x.join(e,"app","controllers");}controllersDir;controllers=[];errors=[];async analyze(){if(!G.existsSync(this.controllersDir))return {controllers:[],totalActions:0,namespaces:[],concerns:[],errors:[`Controllers directory not found at ${this.controllersDir}`]};let e=await glob("**/*_controller.rb",{cwd:this.controllersDir,ignore:["concerns/**"]});for(let s of e){let a=x.join(this.controllersDir,s);try{let r=await this.parseControllerFile(a,s);r&&this.controllers.push(r);}catch(r){this.errors.push(`Error parsing ${s}: ${r}`);}}let t=[...new Set(this.controllers.filter(s=>s.namespace).map(s=>s.namespace))],o=[...new Set(this.controllers.flatMap(s=>s.concerns))],n=this.controllers.reduce((s,a)=>s+a.actions.length,0);return {controllers:this.controllers,totalActions:n,namespaces:t,concerns:o,errors:this.errors}}async parseControllerFile(e,t){let n=(await N(e)).rootNode,s=t.replace(/_controller\.rb$/,"").split("/"),a=s.length>1?s.slice(0,-1).join("/"):void 0,r=s[s.length-1],c=R(n,"class");if(c.length===0)return null;let i=c[0],u=F(i),p=M(i);if(!u)return null;let m={name:r,filePath:t,className:u,parentClass:p||"ApplicationController",namespace:a,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(e,t,o){let n=this.getCallArguments(e);if(n.length===0)return;let r={name:n[0].text.replace(/^:/,""),line:o};for(let c of n.slice(1))if(c.type==="hash"){let i=w(c,"pair");for(let u of i){let p=u.child(0)?.text?.replace(/^:/,""),m=u.child(2);if(!(!p||!m))switch(p){case "only":r.only=this.extractArrayValues(m);break;case "except":r.except=this.extractArrayValues(m);break;case "if":r.if=m.text;break;case "unless":r.unless=m.text;break}}}t.push(r);}parseInclude(e,t){let o=this.getCallArguments(e);for(let n of o)(n.type==="constant"||n.type==="scope_resolution")&&t.push(n.text);}parseHelper(e,t){let o=this.getCallArguments(e);for(let n of o){let s=n.text.replace(/^:/,"");t.push(s);}}parseLayout(e){let t=this.getCallArguments(e);if(t.length===0)return;let o=t[0],n=o.text.replace(/^["']|["']$/g,"");n.startsWith(":")&&(n=n.substring(1)),(o.type==="lambda"||o.type==="proc")&&(n="(dynamic)");let s={name:n};for(let a of t.slice(1))a.type==="hash"&&(s.conditions=a.text);return s}parseRescueFrom(e,t,o){let n=this.getCallArguments(e);if(n.length===0)return;let s=n[0].text,a="unknown";for(let r of n.slice(1))if(r.type==="hash"||r.type==="pair"){let c=r.type==="hash"?w(r,"pair"):[r];for(let i of c){let u=i.child(0)?.text?.replace(/^:/,""),p=i.child(2);u==="with"&&p&&(a=p.text.replace(/^:/,""));}}t.push({exception:s,handler:a,line:o});}parseMethod(e,t){let o=U(e);if(!o||e.text.includes("def self."))return null;let n={name:o,line:e.startPosition.row+1,visibility:t,parameters:Z(e),servicesCalled:[],modelsCalled:[],methodCalls:[],instanceVarAssignments:[]},s=e.text,a=/@([a-z_][a-z0-9_]*)\s*=\s*([^\n]+)/gi,r;for(;(r=a.exec(s))!==null;){let u=r[1],p=r[2].trim().slice(0,100),m,d=p.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=p.match(/^@([a-z_]+)\.([a-z_]+)/);y&&!m&&(m=`${y[1]}.${y[2]}`);let f=p.match(/^current_([a-z_]+)/);f&&!m&&(m=f[1].charAt(0).toUpperCase()+f[1].slice(1));let g=p.match(/^([A-Z][a-zA-Z0-9]+Service)\.(call|new|perform)/);g&&!m&&(m=`Service:${g[1]}`),n.instanceVarAssignments&&n.instanceVarAssignments.push({name:u,assignedType:m,assignedValue:p.length>60?p.slice(0,57)+"...":p});}(s.includes("render json:")||s.includes("render :json"))&&(n.rendersJson=true),s.includes("render")&&!n.rendersJson&&(n.rendersHtml=true);let c=s.match(/redirect_to\s+([^,\n]+)/);if(c&&(n.redirectsTo=c[1].trim()),s.includes("respond_to")){let u=[];s.includes("format.html")&&u.push("html"),s.includes("format.json")&&u.push("json"),s.includes("format.xml")&&u.push("xml"),s.includes("format.js")&&u.push("js"),s.includes("format.csv")&&u.push("csv"),s.includes("format.pdf")&&u.push("pdf"),u.length>0&&(n.respondsTo=u);}let i=R(e,"call");for(let u of i){let p=u.childForFieldName("receiver"),m=u.childForFieldName("method");if(p&&m){let d=p.text,y=m.text;d.endsWith("Service")&&["call","new","perform","execute"].includes(y)&&(n.servicesCalled.includes(d)||n.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)||n.modelsCalled.includes(d)||n.modelsCalled.push(d)),n.methodCalls.push(`${d}.${y}`);}else m&&!p&&n.methodCalls.push(m.text);}return n}getCallArguments(e){let t=e.childForFieldName("arguments");if(!t){let n=[];for(let s=0;s<e.childCount;s++){let a=e.child(s);a&&!["identifier","(",")",",","call"].includes(a.type)&&a!==e.childForFieldName("method")&&a!==e.childForFieldName("receiver")&&n.push(a);}return n}let o=[];for(let n=0;n<t.childCount;n++){let s=t.child(n);s&&s.type!=="("&&s.type!==")"&&s.type!==","&&o.push(s);}return o}extractArrayValues(e){let t=[];if(e.type==="array")for(let o=0;o<e.childCount;o++){let n=e.child(o);n&&n.type!=="["&&n.type!=="]"&&n.type!==","&&t.push(n.text.replace(/^:/,""));}else t.push(e.text.replace(/^:/,""));return t}};async function ge(){let l=process.argv[2]||process.cwd();console.log(`Analyzing controllers in: ${l}`);let t=await new V(l).analyze();if(console.log(`
|
|
8
|
+
=== Rails Controllers Analysis ===
|
|
9
|
+
`),console.log(`Total controllers: ${t.controllers.length}`),console.log(`Total actions: ${t.totalActions}`),console.log(`Namespaces: ${t.namespaces.join(", ")||"(none)"}`),console.log(`Shared concerns: ${t.concerns.length}`),t.errors.length>0){console.log(`
|
|
10
|
+
--- Errors (${t.errors.length}) ---`);for(let s of t.errors.slice(0,5))console.log(` \u274C ${s}`);t.errors.length>5&&console.log(` ... and ${t.errors.length-5} more`);}console.log(`
|
|
11
|
+
--- Sample Controllers (first 10) ---`);for(let s of t.controllers.slice(0,10))console.log(`
|
|
12
|
+
\u{1F4C1} ${s.className} (${s.filePath})`),console.log(` Parent: ${s.parentClass}`),console.log(` Actions (${s.actions.length}): ${s.actions.map(a=>a.name).slice(0,5).join(", ")}${s.actions.length>5?"...":""}`),s.beforeActions.length>0&&console.log(` Before: ${s.beforeActions.map(a=>a.name).join(", ")}`),s.concerns.length>0&&console.log(` Concerns: ${s.concerns.join(", ")}`);let o=t.controllers.flatMap(s=>s.actions.filter(a=>a.visibility==="public")),n=t.controllers.flatMap(s=>s.actions.filter(a=>a.visibility==="private"));console.log(`
|
|
13
|
+
--- Action Visibility Summary ---`),console.log(` Public: ${o.length}`),console.log(` Private: ${n.length}`);}var ye=import.meta.url===`file://${process.argv[1]}`;ye&&ge().catch(console.error);var j=class{constructor(e){this.rootPath=e;this.modelsDir=x.join(e,"app","models");}modelsDir;models=[];errors=[];async analyze(){if(!G.existsSync(this.modelsDir))return {models:[],totalAssociations:0,totalValidations:0,concerns:[],namespaces:[],errors:[`Models directory not found at ${this.modelsDir}`]};let e=await glob("**/*.rb",{cwd:this.modelsDir,ignore:["concerns/**","application_record.rb"]});for(let a of e){let r=x.join(this.modelsDir,a);try{let c=await this.parseModelFile(r,a);c&&this.models.push(c);}catch(c){this.errors.push(`Error parsing ${a}: ${c}`);}}let t=[...new Set(this.models.flatMap(a=>a.concerns))],o=[...new Set(this.models.map(a=>{let r=a.filePath.split("/");return r.length>1?r.slice(0,-1).join("/"):null}).filter(a=>a!==null))],n=this.models.reduce((a,r)=>a+r.associations.length,0),s=this.models.reduce((a,r)=>a+r.validations.length,0);return {models:this.models,totalAssociations:n,totalValidations:s,concerns:t,namespaces:o,errors:this.errors}}async parseModelFile(e,t){let n=(await N(e)).rootNode,s=R(n,"class");if(s.length===0)return null;let a=s[0],r=F(a),c=M(a);if(!r)return null;c&&this.isActiveRecordModel(c);let i={name:r.replace(/.*::/,""),filePath:t,className:r,parentClass:c||"ApplicationRecord",associations:[],validations:[],callbacks:[],scopes:[],concerns:[],enums:[],attributes:[],classMethodsCount:0,instanceMethodsCount:0,line:a.startPosition.row+1};i.tableName=this.parseTableName(a);let u=R(a,"call");for(let d of u){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 p=R(a,"method"),m=R(a,"singleton_method");return i.instanceMethodsCount=p.length,i.classMethodsCount=m.length,i}isActiveRecordModel(e){return ["ApplicationRecord","ActiveRecord::Base","ActiveRecord"].some(o=>e.includes(o))}parseTableName(e){let t=R(e,"call");for(let n of t)if(n.childForFieldName("method")?.text==="table_name="){let a=this.getCallArguments(n);if(a.length>0)return a[0].text.replace(/^["']|["']$/g,"")}let o=R(e,"assignment");for(let n of o)if(n.child(0)?.text?.includes("table_name")){let a=n.child(2);if(a)return a.text.replace(/^["']|["']$/g,"")}}parseAssociation(e,t,o,n){let s=this.getCallArguments(e);if(s.length===0)return;let r=s[0].text.replace(/^:/,""),c={type:t,name:r,line:n};for(let i of s.slice(1))if(i.type==="hash"){let u=w(i,"pair");for(let p of u){let m=p.child(0)?.text?.replace(/^:/,""),d=p.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(e,t,o,n){let s=this.getCallArguments(e);if(s.length===0)return;let a=[],r={},c=t;for(let i of s)if(i.type==="simple_symbol"||i.type==="symbol")a.push(i.text.replace(/^:/,""));else if(i.type==="hash"){let u=w(i,"pair");for(let p of u){let m=p.child(0)?.text?.replace(/^:/,""),d=p.child(2);m&&d&&(["presence","uniqueness","numericality","length","format","inclusion","exclusion","acceptance","confirmation"].includes(m)&&(c=m),r[m]=d.text);}}(a.length>0||t==="validate")&&o.push({type:c,attributes:a,options:Object.keys(r).length>0?r:void 0,line:n});}isCallback(e){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(e)}parseCallback(e,t,o,n){let s=this.getCallArguments(e);if(s.length===0)return;let r=s[0].text.replace(/^:/,""),c={type:t,method:r,line:n};for(let i of s.slice(1))if(i.type==="hash"){let u=w(i,"pair");for(let p of u){let m=p.child(0)?.text?.replace(/^:/,""),d=p.child(2);m&&d&&["if","unless"].includes(m)&&(c.conditions=`${m}: ${d.text}`);}}o.push(c);}parseScope(e,t,o){let n=this.getCallArguments(e);if(n.length===0)return;let a=n[0].text.replace(/^:/,""),r=n.length>1&&(n[1].type==="lambda"||n[1].text.includes("->"));t.push({name:a,lambda:r,line:o});}parseInclude(e,t){let o=this.getCallArguments(e);for(let n of o)(n.type==="constant"||n.type==="scope_resolution")&&t.push(n.text);}parseEnum(e,t,o){let n=this.getCallArguments(e);if(n.length!==0){for(let s of n)if(s.type==="hash"){let a=w(s,"pair");for(let r of a){let c=r.child(0)?.text?.replace(/^:/,""),i=r.child(2);if(c&&i&&i.type==="hash"){let u=[],p=w(i,"pair");for(let m of p){let d=m.child(0)?.text?.replace(/^:/,"");d&&u.push(d);}t.push({name:c,values:u,line:o});}else if(c&&i&&i.type==="array"){let u=[];for(let p=0;p<i.childCount;p++){let m=i.child(p);m&&m.type!=="["&&m.type!=="]"&&m.type!==","&&u.push(m.text.replace(/^:/,""));}t.push({name:c,values:u,line:o});}}}}}parseAttribute(e,t,o){let n=this.getCallArguments(e);if(n.length===0)return;let r={name:n[0].text.replace(/^:/,""),line:o};if(n.length>1){let c=n[1];r.type=c.text.replace(/^:/,"");}for(let c of n)if(c.type==="hash"){let i=w(c,"pair");for(let u of i){let p=u.child(0)?.text?.replace(/^:/,""),m=u.child(2);p==="default"&&m&&(r.default=m.text);}}t.push(r);}getCallArguments(e){let t=e.childForFieldName("arguments");if(!t){let n=[];for(let s=0;s<e.childCount;s++){let a=e.child(s);a&&!["identifier","(",")",",","call"].includes(a.type)&&a!==e.childForFieldName("method")&&a!==e.childForFieldName("receiver")&&n.push(a);}return n}let o=[];for(let n=0;n<t.childCount;n++){let s=t.child(n);s&&s.type!=="("&&s.type!==")"&&s.type!==","&&o.push(s);}return o}};async function xe(){let l=process.argv[2]||process.cwd();console.log(`Analyzing models in: ${l}`);let t=await new j(l).analyze();if(console.log(`
|
|
14
|
+
=== Rails Models Analysis ===
|
|
15
|
+
`),console.log(`Total models: ${t.models.length}`),console.log(`Total associations: ${t.totalAssociations}`),console.log(`Total validations: ${t.totalValidations}`),console.log(`Shared concerns: ${t.concerns.length}`),console.log(`Namespaces: ${t.namespaces.join(", ")||"(none)"}`),t.errors.length>0){console.log(`
|
|
16
|
+
--- Errors (${t.errors.length}) ---`);for(let r of t.errors.slice(0,5))console.log(` \u274C ${r}`);t.errors.length>5&&console.log(` ... and ${t.errors.length-5} more`);}console.log(`
|
|
17
|
+
--- Sample Models (first 15) ---`);for(let r of t.models.slice(0,15)){if(console.log(`
|
|
18
|
+
\u{1F4E6} ${r.className} (${r.filePath})`),console.log(` Parent: ${r.parentClass}`),r.associations.length>0){let c=r.associations.slice(0,3).map(i=>`${i.type} :${i.name}`);console.log(` Associations: ${c.join(", ")}${r.associations.length>3?"...":""}`);}if(r.validations.length>0&&console.log(` Validations: ${r.validations.length}`),r.scopes.length>0){let c=r.scopes.slice(0,3).map(i=>i.name);console.log(` Scopes: ${c.join(", ")}${r.scopes.length>3?"...":""}`);}if(r.enums.length>0){let c=r.enums.map(i=>`${i.name}(${i.values.length})`);console.log(` Enums: ${c.join(", ")}`);}r.concerns.length>0&&console.log(` Concerns: ${r.concerns.slice(0,3).join(", ")}${r.concerns.length>3?"...":""}`);}let o=t.models.flatMap(r=>r.associations),n=o.filter(r=>r.type==="belongs_to").length,s=o.filter(r=>r.type==="has_many").length,a=o.filter(r=>r.type==="has_one").length;console.log(`
|
|
19
|
+
--- Association Summary ---`),console.log(` belongs_to: ${n}`),console.log(` has_many: ${s}`),console.log(` has_one: ${a}`);}var Re=import.meta.url===`file://${process.argv[1]}`;Re&&xe().catch(console.error);var T=class{constructor(e){this.rootPath=e;this.grpcDir=x.join(e,"app","grpc_services");}grpcDir;services=[];errors=[];async analyze(){if(!G.existsSync(this.grpcDir))return {services:[],totalRpcs:0,namespaces:[],errors:[`gRPC services directory not found at ${this.grpcDir}`]};let e=await glob("**/*_grpc_service.rb",{cwd:this.grpcDir});for(let n of e){let s=x.join(this.grpcDir,n);try{let a=await this.parseServiceFile(s,n);a&&this.services.push(a);}catch(a){this.errors.push(`Error parsing ${n}: ${a}`);}}let t=[...new Set(this.services.filter(n=>n.namespace).map(n=>n.namespace))],o=this.services.reduce((n,s)=>n+s.rpcs.length,0);return {services:this.services,totalRpcs:o,namespaces:t,errors:this.errors}}async parseServiceFile(e,t){let n=(await N(e)).rootNode,s=t.replace(/_grpc_service\.rb$/,"").split("/"),a=s.length>1?s.slice(0,-1).join("/"):void 0,r=s[s.length-1],c=R(n,"class");if(c.length===0)return null;let i=c[0],u=F(i),p=M(i);if(!u)return null;let m={name:r,filePath:t,className:u,parentClass:p||"Unknown",namespace:a,rpcs:[],policies:[],serializers:[],concerns:[],line:i.startPosition.row+1};p&&p.match(/(\w+)::Service$/)&&(m.protoService=p.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,_=X.childForFieldName("receiver")?.text;(B==="authorize!"||B==="new")&&_?.includes("Policy")&&(m.policies.includes(_)||m.policies.push(_),v.policyMethod="authorize!"),_?.includes("Serializer")&&B==="new"&&(m.serializers.includes(_)||m.serializers.push(_));}m.rpcs.push(v);}}}}return m}parseRpcMethod(e){let t=U(e);if(!t||["initialize","to_s","inspect","call","perform","execute"].includes(t))return null;Z(e);let s=e.text,a={name:t,line:e.startPosition.row+1,streaming:"none",modelsUsed:[],servicesUsed:[]},r=s.match(/@param\s+\[([^\]]+)\]\s+req/);r&&(a.requestType=r[1]);let c=s.match(/@return\s+\[([^\]]+)\]/);c&&(a.responseType=c[1]);let i=s.matchAll(/\b([A-Z][a-zA-Z]+)\.(find|find_by|where|all|first|last|create|joins|includes)\b/g);for(let p of i){let m=p[1];!["Rails","ActiveRecord","GRPC","Visit","Google"].includes(m)&&!a.modelsUsed.includes(m)&&a.modelsUsed.push(m);}let u=s.matchAll(/\b(\w+Service)\.(call|new|perform)\b/g);for(let p of u){let m=p[1];a.servicesUsed.includes(m)||a.servicesUsed.push(m);}return a}getCallArguments(e){let t=e.childForFieldName("arguments");if(!t){let n=[];for(let s=0;s<e.childCount;s++){let a=e.child(s);a&&!["identifier","(",")",",","call"].includes(a.type)&&a!==e.childForFieldName("method")&&a!==e.childForFieldName("receiver")&&n.push(a);}return n}let o=[];for(let n=0;n<t.childCount;n++){let s=t.child(n);s&&s.type!=="("&&s.type!==")"&&s.type!==","&&o.push(s);}return o}};async function we(){let l=process.argv[2]||process.cwd();console.log(`Analyzing gRPC services in: ${l}`);let t=await new T(l).analyze();if(console.log(`
|
|
20
|
+
=== Rails gRPC Services Analysis ===
|
|
21
|
+
`),console.log(`Total services: ${t.services.length}`),console.log(`Total RPCs: ${t.totalRpcs}`),console.log(`Namespaces: ${t.namespaces.join(", ")||"(none)"}`),t.errors.length>0){console.log(`
|
|
22
|
+
--- Errors (${t.errors.length}) ---`);for(let s of t.errors.slice(0,5))console.log(` \u274C ${s}`);}console.log(`
|
|
23
|
+
--- Sample Services (first 15) ---`);for(let s of t.services.slice(0,15))console.log(`
|
|
24
|
+
\u{1F4E1} ${s.className} (${s.filePath})`),console.log(` Proto: ${s.protoService||"unknown"}`),console.log(` RPCs (${s.rpcs.length}): ${s.rpcs.map(a=>a.name).join(", ")}`),s.policies.length>0&&console.log(` Policies: ${s.policies.join(", ")}`),s.serializers.length>0&&console.log(` Serializers: ${s.serializers.join(", ")}`);let o=t.services.flatMap(s=>s.rpcs),n=o.filter(s=>s.modelsUsed.length>0);console.log(`
|
|
25
|
+
--- RPC Summary ---`),console.log(` Total RPCs: ${o.length}`),console.log(` RPCs using models: ${n.length}`);}var Ae=import.meta.url===`file://${process.argv[1]}`;Ae&&we().catch(console.error);async function K(l){let e=x.join(l,"app/views"),t=x.join(l,"app/controllers");try{await A.access(e);}catch{return {views:[],pages:[],summary:{totalViews:0,totalPages:0,byController:{},byTemplate:{}}}}let o=await glob("**/*.{haml,erb,html.haml,html.erb,yml}",{cwd:e,nodir:true}),n=[],s={},a={};for(let c of o){let i=await Ce(e,c);i&&(n.push(i),s[i.controller]=(s[i.controller]||0)+1,a[i.template]=(a[i.template]||0)+1);}let r=await Fe(t,n,l);return {views:n,pages:r,summary:{totalViews:n.length,totalPages:r.length,byController:s,byTemplate:a}}}async function Ce(l,e){let t=x.join(l,e);try{let o=await A.readFile(t,"utf-8"),n=e.split("/");if(n.some(g=>g.endsWith("_mailer")||g==="layouts"||g==="shared"||g==="devise"))return null;let s=n.pop()||"",a=n.join("/")||"application",r=s.split("."),c=r[0].replace(/^_/,""),i=s.startsWith("_"),u;s.endsWith(".yml")?u="yml":s.endsWith(".haml")?u="haml":s.endsWith(".erb")?u="erb":u="other";let p=r.length>2?r[1]:"html";if(i)return null;let m=[],d=[],y=[],f=[];return u==="yml"?(y=_e(o),f=[{name:"App",ssr:!0,propsVar:"@yml_data"}]):(m=Ne(o,u),d=Se(o,u),y=$e(o),f=Pe(o,u)),{name:c,path:e,controller:a,action:c,format:p,template:u,partials:m,helpers:d,instanceVars:y,reactComponents:f}}catch{return null}}function Ne(l,e){let t=[];if(e==="haml"){let o=l.matchAll(/=\s*render\s+(?:partial:\s*)?['"]([^'"]+)['"]/g);for(let n of o)t.push(n[1]);}else if(e==="erb"){let o=l.matchAll(/<%=?\s*render\s+(?:partial:\s*)?['"]([^'"]+)['"]/g);for(let n of o)t.push(n[1]);}return [...new Set(t)]}function Se(l,e){let t=[],o=/\b(link_to|form_for|form_with|image_tag|content_for|yield|render|t|l|raw|html_safe|simple_form_for)\b/g,n=l.matchAll(o);for(let s of n)t.push(s[1]);return [...new Set(t)]}function Pe(l,e){let t=[],o=/render_react_component\s*\(?\s*["']([^"']+)["'](?:,\s*\{[^}]*\})?\s*(?:,\s*ssr:\s*(true|false))?\)?/g,n;for(;(n=o.exec(l))!==null;)t.push({name:n[1],ssr:n[2]==="true"});let s=/data:\s*\{\s*react_component:\s*["']([^"']+)["'](?:,\s*react_component_props:\s*(@?\w+)(?:\.to_json)?)?/g;for(;(n=s.exec(l))!==null;)t.push({name:n[1],propsVar:n[2],ssr:false});let a=/ReactComponent\s+name=["']([^"']+)["']/g;for(;(n=a.exec(l))!==null;)t.push({name:n[1],ssr:false});let r=new Set;return t.filter(c=>r.has(c.name)?false:(r.add(c.name),true))}function _e(l){let e=[],t=l.split(`
|
|
26
|
+
`);for(let o of t){let n=o.match(/^([a-z_]+):/);n&&!n[1].startsWith("_")&&e.push(n[1]);let s=o.match(/^\s+-\s+(\w+)/);s&&e.push(s[1]);}return [...new Set(e)].slice(0,50)}function $e(l){let e=[],t=l.matchAll(/@(\w+)/g);for(let o of t)["import","media","keyframes","charset"].includes(o[1])||e.push(o[1]);return [...new Set(e)]}async function Fe(l,e,t){let o=[];try{await A.access(l);}catch{return o}let n=await glob("**/*_controller.rb",{cwd:l,nodir:true}),s=await Me(t);for(let a of n){let r=x.join(l,a),c=await A.readFile(r,"utf-8"),i=a.replace(/_controller\.rb$/,"").replace(/\//g,"/"),u=Ie(c,i,a,e,s);o.push(...u);}return o}async function Me(l){let e=new Map;try{let t=x.join(l,".repomap","rails-routes.json"),o=await A.readFile(t,"utf-8"),n=JSON.parse(o);for(let s of n){let a=`${s.controller}#${s.action}`;e.set(a,{path:s.path,method:s.method});}}catch{}return e}function Ie(l,e,t,o,n){let s=[],a=l.split(/\n\s*(private|protected)\b/)[0],r=/def\s+(\w+)/g,c;for(;(c=r.exec(a))!==null;){let i=c[1];["initialize","new","create","update","destroy","index","show","edit"].includes(i)||i.startsWith("set_")||i.startsWith("_");let u=c.index,p=ke(a,u),m=Ve(p,t),d=je(p),y=Te(p),f=ze(p),g=o.find(v=>v.controller===e&&v.action===i),h=`${e}#${i}`,b=n.get(h);s.push({route:b?.path||`/${e}/${i}`,method:b?.method||"GET",controller:e,action:i,view:g,apis:m,services:d,grpcCalls:y,modelAccess:f});}return s}function ke(l,e){let t=0,o=false,n="";for(let s=e;s<l.length;s++){let a=l.slice(s,l.indexOf(`
|
|
27
|
+
`,s)+1||l.length);if(a.match(/^\s*(def|class|module|if|unless|case|while|until|for|begin|do)\b/)&&(t++,o=true),a.match(/^\s*end\b/)&&(t--,o&&t===0)||(n+=a,s=l.indexOf(`
|
|
28
|
+
`,s),s===-1))break}return n}function Ve(l,e){let t=[],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 n of o){let s;for(;(s=n.exec(l))!==null;)t.push({type:"http",name:s[2]||"HTTP call",method:s[1]?.toUpperCase(),source:e});}return t}function je(l){let e=[],t=/(\w+(?:::\w+)*Service)\.(?:call!?|new)/g,o;for(;(o=t.exec(l))!==null;)e.push(o[1]);return [...new Set(e)]}function Te(l){let e=[],t=[/(\w+(?:::\w+)*Grpc(?:::\w+)?)\./g,/Grpc::(\w+(?:::\w+)*)/g,/(\w+GrpcService)\./g];for(let o of t){let n;for(;(n=o.exec(l))!==null;)e.push(n[1]);}return [...new Set(e)]}function ze(l){let e=[],t=/([A-Z][a-zA-Z0-9]+)\.(?:find|where|find_by|first|last|all|create|update|destroy|new)/g,o;for(;(o=t.exec(l))!==null;)["File","Dir","Time","Date","DateTime","JSON","YAML","CSV","Logger"].includes(o[1])||e.push(o[1]);return [...new Set(e)]}var Ee=["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"],De=["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 e=new Map,t=[],o=await Ge(l);for(let r of o.entryDirs){let c=x.join(l,r);try{await A.access(c);let i=await glob("**/*.{tsx,ts,jsx,js}",{cwd:c,nodir:!0,ignore:["**/*.d.ts","**/*.test.*","**/*.spec.*"]});for(let u of i){let p=await Ze(x.join(c,u),u,r);if(p&&(t.push(p),p.componentName)){let m=e.get(p.componentName);m?(m.entryFile=x.join(r,u),m.importPath=p.imports[0]):e.set(p.componentName,{name:p.componentName,entryFile:x.join(r,u),importPath:p.imports[0],ssr:!1,usedIn:[]});}}}catch{}}let n=x.join(l,"app/views");try{await A.access(n);let r=await glob("**/*.{haml,erb,html.haml,html.erb,slim}",{cwd:n,nodir:!0});for(let c of r){let i=await Be(x.join(n,c),c);for(let u of i){let p=e.get(u.componentName);p?(p.usedIn.push({viewPath:c,controller:u.controller,action:u.action,propsVar:u.propsVar,line:u.line,pattern:u.pattern}),u.ssr&&(p.ssr=!0)):e.set(u.componentName,{name:u.componentName,ssr:u.ssr,usedIn:[{viewPath:c,controller:u.controller,action:u.action,propsVar:u.propsVar,line:u.line,pattern:u.pattern}]});}}}catch{}await Oe(l,e,o.componentDirs);let s=Array.from(e.values()),a=s.filter(r=>r.ssr).length;return {components:s,entryPoints:t,detectedPaths:o,summary:{totalComponents:s.length,totalEntryPoints:t.length,ssrComponents:a,clientComponents:s.length-a}}}async function Ge(l){let e=[],t=[],o="unknown";for(let n of Ee){let s=x.join(l,n);try{(await A.stat(s)).isDirectory()&&e.push(n);}catch{}}for(let n of De){let s=x.join(l,n);try{(await A.stat(s)).isDirectory()&&t.push(n);}catch{}}if(o=await Le(l),e.length===0){let n=await Ue(l);e.push(...n);}return t.length===0&&e.length>0&&t.push(...e),{entryDirs:e,componentDirs:t,integrationPattern:o}}async function Le(l){try{let e=x.join(l,"Gemfile"),t=await A.readFile(e,"utf-8");if(t.includes("react_on_rails"))return "react_on_rails";if(t.includes("react-rails"))return "react-rails";if(t.includes("vite_rails")||t.includes("vite_ruby"))return "vite";if(t.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 Ue(l){let e=[],t=["app/**/entries","app/**/packs","frontend/**/entries","client/**/entries","src/**/entries"];for(let o of t)try{let n=await glob(o,{cwd:l,nodir:!1});for(let s of n){let a=x.join(l,s);try{(await A.stat(a)).isDirectory()&&e.push(s);}catch{}}}catch{}return e}async function Ze(l,e,t){try{let o=await A.readFile(l,"utf-8"),n=[/\[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*\)/],s=null,a;for(let u of n){let p=o.match(u);if(p){s=p[1],a=p[0];break}}s||(s=x.basename(e,x.extname(e)).split(/[-_]/).map(p=>p.charAt(0).toUpperCase()+p.slice(1)).join(""));let r=[],c=o.matchAll(/import\s+(?:\{[^}]+\}|\*\s+as\s+\w+|\w+)\s+from\s+["']([^"']+)["']/g);for(let u of c){let p=u[1];(p.includes("/react/")||p.includes("/components/")||p.includes("/containers/")||p.includes("/bundles/")||p.includes("/pages/")||p.match(/\/[A-Z][a-zA-Z0-9]*/))&&r.push(p);}let i=o.matchAll(/require\s*\(\s*["']([^"']+)["']\s*\)/g);for(let u of i){let p=u[1];(p.includes("/react/")||p.includes("/components/")||p.includes("/containers/"))&&r.push(p);}return !s&&r.length===0?null:{file:e,fullPath:x.join(t,e),componentName:s||"",imports:r,selector:a}}catch{return null}}async function Be(l,e){let t=[];try{let n=(await A.readFile(l,"utf-8")).split(`
|
|
29
|
+
`),s=e.split("/"),a=s.pop()||"",r=s.join("/")||"application",c=a.split(".")[0].replace(/^_/,""),i=0;for(let u of n){i++;let p=u.matchAll(E.dataReactComponent);for(let h of p){let b=u.match(/react_component_props:\s*(@?\w+(?:\.\w+)*)/);t.push({componentName:h[1],controller:r,action:c,propsVar:b?b[1]:void 0,line:i,pattern:"data-react-component",ssr:!1});}let m=u.match(E.renderReactComponent);if(m){let h=u.match(/ssr:\s*(true|false|@\w+)/);t.push({componentName:m[1],controller:r,action:c,line:i,pattern:"render_react_component",ssr:h?h[1]==="true"||h[1].startsWith("@"):!1});}let d=u.match(E.reactComponent);if(d){let h=u.match(/props:\s*(@?\w+(?:\.\w+)*)/),b=u.match(/prerender:\s*(true|false)/);t.push({componentName:d[1],controller:r,action:c,propsVar:h?h[1]:void 0,line:i,pattern:"react_component",ssr:b?b[1]==="true":!1});}let y=u.match(E.reduxStore);y&&t.push({componentName:y[1],controller:r,action:c,line:i,pattern:"redux_store",ssr:!1});let f=u.match(E.dataComponent);f&&t.push({componentName:f[1],controller:r,action:c,line:i,pattern:"data-react-component",ssr:!1});let g=u.match(E.dataReactClass);g&&t.push({componentName:g[1],controller:r,action:c,line:i,pattern:"data-react-component",ssr:!1});}}catch{}return t}async function Oe(l,e,t){for(let[o,n]of e)if(!(!o||typeof o!="string")){if(n.importPath&&typeof n.importPath=="string"){let s=n.importPath.replace(/\.js$/,"").replace(/\.tsx?$/,"").replace(/^\.\.\//,"").replace(/^\.\//,"");n.sourceFile=s;}else if(!n.sourceFile){let s=[".tsx",".ts",".jsx",".js"],a=[o,We(o),He(o)].filter(Boolean),r=false;for(let c of t){if(r)break;for(let i of a){if(r)break;for(let u of s){let p=[x.join(l,c,i,`index${u}`),x.join(l,c,i,`${i}${u}`),x.join(l,c,`${i}${u}`),x.join(l,c,"components",`${i}${u}`),x.join(l,c,"containers",`${i}${u}`)];for(let m of p)try{await A.access(m),n.sourceFile=x.relative(l,m),r=!0;break}catch{}}}}}}}function We(l){return l?l.replace(/([A-Z])/g,"_$1").toLowerCase().replace(/^_/,""):""}function He(l){return l?l.replace(/([A-Z])/g,"-$1").toLowerCase().replace(/^-/,""):""}async function qe(l){let e=process.env.REPOMAP_VERBOSE==="1",o=await new k(l).analyze(),s=await new V(l).analyze(),r=await new j(l).analyze(),i=await new T(l).analyze(),u=await K(l),p=await Q(l);e&&console.log(` Rails: ${o.routes.length} routes, ${s.controllers.length} controllers, ${r.models.length} models`);let m=[...new Set([...o.namespaces,...s.namespaces,...r.namespaces,...i.namespaces])],d=[...new Set([...s.concerns,...r.concerns])],y={totalRoutes:o.routes.length,totalControllers:s.controllers.length,totalActions:s.totalActions,totalModels:r.models.length,totalAssociations:r.totalAssociations,totalValidations:r.totalValidations,totalGrpcServices:i.services.length,totalRpcs:i.totalRpcs,totalViews:u.summary.totalViews,totalPages:u.summary.totalPages,totalReactComponents:p.summary.totalComponents,ssrReactComponents:p.summary.ssrComponents,namespaces:m,concerns:d};return {routes:o,controllers:s,models:r,grpc:i,views:u,react:p,summary:y}}async function Je(){let l=process.argv[2]||process.cwd(),e=await qe(l);console.log(`
|
|
30
|
+
`+"=".repeat(60)),console.log("\u{1F4CA} RAILS APPLICATION ANALYSIS SUMMARY"),console.log("=".repeat(60)+`
|
|
31
|
+
`),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(e.summary.totalRoutes).padStart(6)} \u2502`),console.log(`\u2502 Resources: ${String(e.routes.resources.length).padStart(6)} \u2502`),console.log(`\u2502 Mounted engines: ${String(e.routes.mountedEngines.length).padStart(6)} \u2502`),console.log(`\u2502 External files: ${String(e.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(e.summary.totalControllers).padStart(6)} \u2502`),console.log(`\u2502 Total actions: ${String(e.summary.totalActions).padStart(6)} \u2502`),console.log(`\u2502 Namespaces: ${String(e.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(e.summary.totalModels).padStart(6)} \u2502`),console.log(`\u2502 Associations: ${String(e.summary.totalAssociations).padStart(6)} \u2502`),console.log(`\u2502 Validations: ${String(e.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(e.summary.totalGrpcServices).padStart(6)} \u2502`),console.log(`\u2502 Total RPCs: ${String(e.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(e.summary.namespaces.length).padStart(6)} \u2502`),console.log(`\u2502 Total concerns: ${String(e.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 t=e.routes.errors.length+e.controllers.errors.length+e.models.errors.length+e.grpc.errors.length;t>0?console.log(`
|
|
32
|
+
\u26A0\uFE0F Total errors: ${t}`):console.log(`
|
|
33
|
+
\u2705 Analysis completed without errors!`);}var Ke=import.meta.url===`file://${process.argv[1]}`;Ke&&Je().catch(console.error);
|
|
34
|
+
export{se as a,ne 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,qe as k};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
var v=class{generateAll(s,e){let n=[];for(let o of s)n.push(this.generateNavigationDiagram(o)),n.push(this.generateDataFlowDiagram(o)),n.push(this.generateComponentDiagram(o)),n.push(this.generateGraphQLDiagram(o));return s.length>1&&n.push(this.generateCrossRepoDiagram(s,e)),n}generateNavigationDiagram(s){let e=["flowchart TB"," %% Page Navigation Flow - Grouped by Category"],n=new Map,o=0,p=new Map;for(let i of s.pages){let h=i.path.split("/").filter(Boolean)[0]||"root",u=p.get(h)||[];u.push(i),p.set(h,u);}for(let[i,r]of p){let h=i.replace(/[^a-zA-Z0-9]/g,"_"),u=i==="root"?"Root Pages":`/${i}`;e.push(""),e.push(` subgraph ${h}["${u}"]`),e.push(" direction TB");for(let l of r){let m=`P${o++}`;n.set(l.path,m);let c=l.path.split("/").filter(Boolean),f=c.length>1?c.slice(1).join("/"):l.path,g=l.authentication.required?" AUTH":"";e.push(` ${m}["${f}${g}"]`);}e.push(" end");}let t=0,a=30;e.push(""),e.push(" %% Navigation Links");for(let i of s.pages){if(t>=a)break;let r=n.get(i.path);for(let h of i.linkedPages.slice(0,2)){if(t>=a)break;let u=n.get(h);r&&u&&r!==u&&(e.push(` ${r} --> ${u}`),t++);}}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 s.pages){let r=n.get(i.path);r&&(i.authentication.required?e.push(` class ${r} authRequired`):e.push(` class ${r} public`));}return {type:"flowchart",title:`${s.repository} - Page Navigation`,content:e.join(`
|
|
2
|
+
`),relatedFiles:s.pages.map(i=>i.filePath)}}generateDataFlowDiagram(s){let e=["flowchart LR"," %% Data Flow Diagram"],n=new Map,o=0,p=u=>{let l=`${u.type}:${u.name}`;if(!n.has(l)){let m=u.type.charAt(0).toUpperCase();n.set(l,`${m}${o++}`);}return n.get(l)??`N${o++}`},a=u=>u.replace(/[\u{1F4E1}\u{270F}\u{FE0F}\u{1F504}\u{1F4E6}]/gu,"").trim().substring(0,40),i=s.dataFlows.filter(u=>u.name.includes("\u{1F4E1}")||u.operations.some(l=>l.includes("Query"))),r=s.dataFlows.filter(u=>u.name.includes("\u270F\uFE0F")||u.operations.some(l=>l.includes("Mutation"))),h=s.dataFlows.filter(u=>u.name.includes("\u{1F504}")||u.source.type==="context"||u.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 u of i.slice(0,20)){let l=p(u.source),m=p(u.target),c=a(u.source.name),f=a(u.target.name);e.push(` ${l}(("${c}"))`),e.push(` ${m}["${f}"]`),e.push(` ${l} --> ${m}`);}e.push(" end");}if(r.length>0){e.push(""),e.push(" subgraph Mutations[\u270F\uFE0F Mutations]"),e.push(" direction TB");for(let u of r.slice(0,20)){let l=p(u.source),m=p(u.target),c=a(u.source.name),f=a(u.target.name);e.push(` ${l}["${c}"]`),e.push(` ${m}(("${f}"))`),e.push(` ${l} --> ${m}`);}e.push(" end");}if(h.length>0){e.push(""),e.push(" subgraph Context[\u{1F504} Context]"),e.push(" direction TB");for(let u of h.slice(0,15)){let l=p(u.source),m=p(u.target),c=a(u.source.name),f=a(u.target.name);e.push(` ${l}{{"${c}"}}`),e.push(` ${m}["${f}"]`),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:`${s.repository} - Data Flow`,content:e.join(`
|
|
3
|
+
`),relatedFiles:s.dataFlows.map(u=>u.source.name)}}generateComponentDiagram(s){let e=["flowchart TB"," %% Component Hierarchy"],n=new Map;for(let t of s.components){let a=n.get(t.type)||[];a.push(t),n.set(t.type,a);}for(let[t,a]of n){e.push(` subgraph ${t.charAt(0).toUpperCase()+t.slice(1)}s`);for(let i of a.slice(0,20)){let r=i.name.replace(/[^a-zA-Z0-9]/g,"_");e.push(` ${r}["${i.name}"]`);}e.push(" end");}let o=0,p=50;for(let t of s.components){if(o>=p)break;let a=t.name.replace(/[^a-zA-Z0-9]/g,"_");for(let i of t.dependencies.slice(0,3)){if(o>=p)break;let r=i.replace(/[^a-zA-Z0-9]/g,"_");e.push(` ${a} --> ${r}`),o++;}}return {type:"flowchart",title:`${s.repository} - Component Hierarchy`,content:e.join(`
|
|
4
|
+
`),relatedFiles:s.components.map(t=>t.filePath)}}generateGraphQLDiagram(s){let e=["flowchart LR"," %% GraphQL Operations"],n=s.graphqlOperations.filter(t=>t.type==="query"),o=s.graphqlOperations.filter(t=>t.type==="mutation"),p=s.graphqlOperations.filter(t=>t.type==="fragment");if(e.push(' API[("GraphQL API")]'),n.length>0){e.push(" subgraph Queries");for(let t of n.slice(0,15)){let a=`Q_${t.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${a}["${t.name}"]`),e.push(` ${a} --> API`);}e.push(" end");}if(o.length>0){e.push(" subgraph Mutations");for(let t of o.slice(0,15)){let a=`M_${t.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${a}["${t.name}"]`),e.push(` ${a} --> API`);}e.push(" end");}if(p.length>0){e.push(" subgraph Fragments");for(let t of p.slice(0,10)){let a=`F_${t.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${a}[/"${t.name}"/]`);}e.push(" end");}return {type:"flowchart",title:`${s.repository} - GraphQL Operations`,content:e.join(`
|
|
5
|
+
`),relatedFiles:s.graphqlOperations.map(t=>t.filePath)}}generateCrossRepoDiagram(s,e){let n=["flowchart TB"," %% Cross-Repository Architecture"];for(let o of s){let p=o.repository.replace(/[^a-zA-Z0-9]/g,"_");n.push(` subgraph ${p}["${o.repository}"]`),n.push(` ${p}_pages["\u{1F4C4} ${o.pages.length} Pages"]`),n.push(` ${p}_gql["\u{1F537} ${o.graphqlOperations.length} GraphQL Ops"]`),n.push(` ${p}_comp["\u{1F9E9} ${o.components.length} Components"]`),n.push(" end");}for(let o of e){let p=o.sourceRepo.replace(/[^a-zA-Z0-9]/g,"_"),t=o.targetRepo.replace(/[^a-zA-Z0-9]/g,"_"),a="-->";o.linkType==="api-call"?a="==>":o.linkType==="graphql-operation"&&(a="-..->"),n.push(` ${p}_gql ${a}|"${o.linkType}"| ${t}_gql`);}return {type:"flowchart",title:"Cross-Repository Architecture",content:n.join(`
|
|
6
|
+
`),relatedFiles:s.map(o=>o.repository)}}generateSequenceDiagram(s){let e=["sequenceDiagram",` %% ${s.name}`],n=[s.source,...s.via,s.target];for(let t of n)e.push(` participant ${t.name}`);let o=s.source;for(let t=0;t<s.via.length;t++){let a=s.via[t],i=s.operations[t]||"data";e.push(` ${o.name}->>+${a.name}: ${i}`),o=a;}let p=s.operations[s.operations.length-1]||"data";return e.push(` ${o.name}->>+${s.target.name}: ${p}`),e.push(` ${s.target.name}-->>-${s.source.name}: response`),{type:"sequence",title:s.name,content:e.join(`
|
|
7
|
+
`),relatedFiles:[]}}};var M=class{generateDocumentation(s){let e=new Map;e.set("index.md",this.generateIndex(s));for(let n of s.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 s.repositories.length>1&&e.set("cross-repo.md",this.generateCrossRepoDoc(s)),e.set("diagrams.md",this.generateDiagramsDoc(s.diagrams)),e}generateIndex(s){let n=[`# ${s.repositories.length===1?`${s.repositories[0].displayName} Documentation`:"Project Documentation"}`,"",`Generated: ${s.generatedAt}`,"",s.repositories.length>1?"## Repositories":"## Overview",""];for(let o of s.repositories)n.push(`### [${o.displayName}](/docs/repos/${o.name}/index)`),n.push(""),n.push(`- **Version**: ${o.version}`),n.push(`- **Commit**: \`${o.commitHash.substring(0,7)}\``),n.push(`- **Pages**: ${o.summary.totalPages}`),n.push(`- **Components**: ${o.summary.totalComponents}`),n.push(`- **GraphQL Ops**: ${o.summary.totalGraphQLOperations}`),n.push("");return n.push("## Quick Links"),n.push(""),s.repositories.length>1&&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(s){return [`# ${s.displayName}`,"",`Version: ${s.version} | Commit: \`${s.commitHash.substring(0,7)}\``,"","## Overview","","| Metric | Count |","|--------|-------|",`| Pages | ${s.summary.totalPages} |`,`| Components | ${s.summary.totalComponents} |`,`| GraphQL Operations | ${s.summary.totalGraphQLOperations} |`,`| Data Flows | ${s.summary.totalDataFlows} |`,`| Auth Required | ${s.summary.authRequiredPages} |`,`| Public | ${s.summary.publicPages} |`,"","## Documentation","",`- [Pages](/docs/repos/${s.name}/pages)`,`- [Components](/docs/repos/${s.name}/components)`,`- [GraphQL](/docs/repos/${s.name}/graphql)`,`- [Data Flow](/docs/repos/${s.name}/dataflow)`,"","## Quick Access","","- [Page Map](/page-map)","- [Diagrams](/docs/diagrams)",""].join(`
|
|
9
|
+
`)}generatePagesDoc(s){let e=[`# ${s.displayName} - Pages`,""],n=s.analysis.pages.filter(a=>a.authentication.required).length,o=s.analysis.pages.filter(a=>a.dataFetching.some(i=>!i.type.includes("Mutation"))).length,p=s.analysis.pages.filter(a=>a.dataFetching.some(i=>i.type.includes("Mutation"))).length;e.push("| Metric | Value |"),e.push("|--------|-------|"),e.push(`| Total | **${s.analysis.pages.length}** |`),e.push(`| Auth Required | ${n} |`),e.push(`| With Queries | ${o} |`),e.push(`| With Mutations | ${p} |`),e.push("");let t=new Map;for(let a of s.analysis.pages){let i=a.path.split("/")[1]||"root",r=t.get(i)||[];r.push(a),t.set(i,r);}for(let[a,i]of t){e.push(`## /${a}`),e.push(""),e.push("| Page | Auth | Layout | Data |"),e.push("|------|------|--------|------|");for(let r of i){let h=r.path.replace(`/${a}`,"")||"/",u=r.authentication.required?"Required":"Public",l=r.layout||"-",m=[],c=new Set,f=r.dataFetching,g=f.filter($=>!$.type.includes("Mutation")),y=f.filter($=>$.type.includes("Mutation")),C=[];for(let $ of g){let q=$.operationName||"";if(!q||q.trim().length<2)continue;let N=q.startsWith("\u2192")||q.startsWith("->"),D=q.replace(/^[→\->\s]+/,"").trim();if(!D||D.length<2)continue;let R=C.find(P=>P.cleanName===D);if(R){!N&&R.isRef&&(R.isRef=false);continue}c.has(D)||(c.add(D),C.push({cleanName:D,isRef:N}));}let d=[];for(let $ of y){let q=$.operationName||"";if(!q||q.trim().length<2)continue;let N=q.startsWith("\u2192")||q.startsWith("->"),D=q.replace(/^[→\->\s]+/,"").trim();if(!D||D.length<2)continue;let R=d.find(P=>P.cleanName===D);if(R){!N&&R.isRef&&(R.isRef=false);continue}c.has(D)||(c.add(D),d.push({cleanName:D,isRef:N}));}for(let $ of C.slice(0,2))$.isRef?m.push(`<span class="gql-ref" data-ref="${$.cleanName}" title="Component">${$.cleanName}</span>`):m.push(`<span class="gql-op" data-op="${$.cleanName}">${$.cleanName}</span>`);for(let $ of d.slice(0,2))$.isRef?m.push(`<span class="gql-ref mutation" data-ref="${$.cleanName}" title="Component">${$.cleanName}</span>`):m.push(`<span class="gql-op mutation" data-op="${$.cleanName}">${$.cleanName}</span>`);let F=C.length+d.length-Math.min(C.length,2)-Math.min(d.length,2);F>0&&m.push(`<span class="gql-more" data-type="all" data-page="${r.path}">+${F} more</span>`);let w=m.length>0?m.join(" "):"-";e.push(`| \`${h}\` | ${u} | ${l} | ${w} |`);}e.push("");for(let r of i){let h=r.dataFetching.filter(l=>!l.type.includes("Mutation")),u=r.dataFetching.filter(l=>l.type.includes("Mutation"));if(h.length>0||u.length>0){let l=new Set,m=[];for(let g of h){let y=g.operationName||"";if(!y||y.trim().length<2)continue;let C=y.startsWith("\u2192")||y.startsWith("->"),d=y.replace(/^[→\->\s]+/,"").trim();if(!d||d.length<2)continue;let F=m.find(w=>w.cleanName===d);if(F){!C&&F.isRef&&(F.isRef=false);continue}l.has(d)||(l.add(d),m.push({cleanName:d,isRef:C}));}let c=new Set,f=[];for(let g of u){let y=g.operationName||"";if(!y||y.trim().length<2)continue;let C=y.startsWith("\u2192")||y.startsWith("->"),d=y.replace(/^[→\->\s]+/,"").trim();if(!d||d.length<2)continue;let F=f.find(w=>w.cleanName===d);if(F){!C&&F.isRef&&(F.isRef=false);continue}c.has(d)||(c.add(d),f.push({cleanName:d,isRef:C}));}if(m.length===0&&f.length===0)continue;if(e.push(`### ${r.path}`),e.push(""),e.push(`> ${r.filePath}`),e.push(""),m.length>0){e.push(`**Queries (${m.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let g of m)g.isRef?e.push(`<span class="gql-ref" data-ref="${g.cleanName}" title="Component">${g.cleanName}</span>`):e.push(`<span class="gql-op" data-op="${g.cleanName}">${g.cleanName}</span>`);e.push("</div>"),e.push("");}if(f.length>0){e.push(`**Mutations (${f.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let g of f)g.isRef?e.push(`<span class="gql-ref mutation" data-ref="${g.cleanName}" title="Component">${g.cleanName}</span>`):e.push(`<span class="gql-op mutation" data-op="${g.cleanName}">${g.cleanName}</span>`);e.push("</div>"),e.push("");}e.push("");}}}return e.join(`
|
|
10
|
+
`)}generateComponentsDoc(s){let e=[`# ${s.displayName} - Components`,""],n=new Map;for(let p of s.analysis.components){let t=n.get(p.type)||[];t.push(p),n.set(p.type,t);}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** | **${s.analysis.components.length}** |`),e.push("");let o=new Map;for(let p of s.analysis.pages)o.set(p.path,[]);for(let p of s.analysis.components)for(let t of s.analysis.pages){let a=this.extractFeatureFromPage(t.filePath),i=this.extractFeatureFromComponent(p.filePath);a&&i&&a===i&&o.get(t.path)?.push(p);}e.push("## By Page"),e.push("");for(let[p,t]of o){if(t.length===0)continue;let a=t.filter(h=>h.type==="container"),i=t.filter(h=>h.type==="presentational"),r=t.filter(h=>h.type==="hook");e.push(`### ${p}`),e.push(""),e.push("| Component | Type | Data |"),e.push("|-----------|------|------|");for(let h of a){let u=this.formatComponentDataOps(h);e.push(`| ${h.name} | Container | ${u||"-"} |`);}for(let h of i.slice(0,10)){let u=this.formatComponentDataOps(h);e.push(`| ${h.name} | UI | ${u||"-"} |`);}for(let h of r){let u=this.formatComponentDataOps(h);e.push(`| ${h.name} | Hook | ${u||"-"} |`);}if(e.push(""),i.length>10){let h=i.slice(10),u=`more-ui-${p.replace(/[^a-zA-Z0-9]/g,"-")}`;e.push(`<details id="${u}">`),e.push(`<summary style="cursor:pointer;color:var(--accent);padding:8px 0">\u25B8 Show ${h.length} more UI components</summary>`),e.push(""),e.push("| Component | Type | Data |"),e.push("|-----------|------|------|");for(let l of h){let m=this.formatComponentDataOps(l);e.push(`| ${l.name} | UI | ${m||"-"} |`);}e.push(""),e.push("</details>"),e.push("");}}e.push("## By Type"),e.push("");for(let[p,t]of n){e.push(`### ${p.charAt(0).toUpperCase()+p.slice(1)} (${t.length})`),e.push(""),e.push("| Name | File | Data |"),e.push("|------|------|------|");for(let a of t.slice(0,25)){let i=a.filePath.replace("src/features/","").replace("src/",""),r=this.formatComponentDataOps(a);e.push(`| ${a.name} | ${i} | ${r||"-"} |`);}if(e.push(""),t.length>25){let a=t.slice(25),i=`more-${p}-components`;e.push(`<details id="${i}">`),e.push(`<summary style="cursor:pointer;color:var(--accent);padding:8px 0">\u25B8 Show ${a.length} more ${p} components</summary>`),e.push(""),e.push("| Name | File | Data |"),e.push("|------|------|------|");for(let r of a){let h=r.filePath.replace("src/features/","").replace("src/",""),u=this.formatComponentDataOps(r);e.push(`| ${r.name} | ${h} | ${u||"-"} |`);}e.push(""),e.push("</details>"),e.push("");}}return e.join(`
|
|
11
|
+
`)}extractFeatureFromPage(s){let e=s.split("/");return e.length>1?e[0]:null}extractFeatureFromComponent(s){let e=s.match(/src\/features\/([^/]+)/);return e?e[1]:null}formatComponentDataOps(s){let e=[],n=[];for(let c of s.hooks){let f=c.match(/(?:useQuery|Query):\s*(\w+)/),g=c.match(/(?:useMutation|Mutation):\s*(\w+)/);f&&f[1]&&f[1].trim().length>=2?e.push(f[1]):g&&g[1]&&g[1].trim().length>=2&&n.push(g[1]);}let o=e.filter(c=>c&&c.trim().length>=2),p=n.filter(c=>c&&c.trim().length>=2);if(o.length===0&&p.length===0)return "";let t=[],a=2,i=2,r=o.slice(0,a);for(let c of r)t.push(`<span class="gql-op" data-op="${c}">${c}</span>`);let h=p.slice(0,i);for(let c of h)t.push(`<span class="gql-op mutation" data-op="${c}">${c}</span>`);let u=o.slice(a),l=p.slice(i),m=u.length+l.length;if(m>0){let c=JSON.stringify(o).replace(/"/g,"""),f=JSON.stringify(p).replace(/"/g,""");t.push(`<span class="gql-ref" data-ref="${s.name}" data-queries="${c}" data-mutations="${f}" title="View all ${o.length} queries and ${p.length} mutations">+${m} more</span>`);}return `<div class="gql-ops-inline">${t.join(" ")}</div>`}generateGraphQLDoc(s){let e=[`# ${s.displayName} - GraphQL`,""],n=s.analysis.graphqlOperations.filter(t=>t.type==="query"),o=s.analysis.graphqlOperations.filter(t=>t.type==="mutation"),p=s.analysis.graphqlOperations.filter(t=>t.type==="fragment");if(e.push("| Type | Count |"),e.push("|------|-------|"),e.push(`| Query | ${n.length} |`),e.push(`| Mutation | ${o.length} |`),e.push(`| Fragment | ${p.length} |`),e.push(`| **Total** | **${s.analysis.graphqlOperations.length}** |`),e.push(""),n.length>0){e.push("## Queries"),e.push("");for(let t of n.slice(0,80)){e.push(`### ${t.name}`),e.push("");let a=t.returnType||"unknown",i=t.variables.length,r=t.usedIn.length;if(e.push(`> Return: \`${a}\` | Variables: ${i} | Used: ${r} files`),e.push(""),t.variables.length>0){e.push("| Variable | Type |"),e.push("|----------|------|");for(let h of t.variables)e.push(`| ${h.name} | \`${h.type}\` |`);e.push("");}t.fields&&t.fields.length>0&&(e.push("```graphql"),e.push(this.formatGraphQLFields(t.fields,0)),e.push("```"),e.push(""));}n.length>80&&e.push(`*+${n.length-80} more queries*
|
|
12
|
+
`);}if(o.length>0){e.push("## Mutations"),e.push("");for(let t of o.slice(0,80)){e.push(`### ${t.name}`),e.push("");let a=t.variables.length,i=t.usedIn.length;if(e.push(`> Variables: ${a} | Used: ${i} files`),e.push(""),t.variables.length>0){e.push("| Variable | Type |"),e.push("|----------|------|");for(let r of t.variables)e.push(`| ${r.name} | \`${r.type}\` |`);e.push("");}t.fields&&t.fields.length>0&&(e.push("```graphql"),e.push(this.formatGraphQLFields(t.fields,0)),e.push("```"),e.push(""));}o.length>80&&e.push(`*+${o.length-80} more mutations*
|
|
13
|
+
`);}if(p.length>0){e.push("## Fragments"),e.push(""),e.push("| Name | Type | Fields |"),e.push("|------|------|--------|");for(let t of p.slice(0,50)){let a=t.fields?.length||0;e.push(`| ${t.name} | ${t.returnType||"-"} | ${a} |`);}p.length>50&&e.push(`| *+${p.length-50} more* | | |`),e.push("");}return e.join(`
|
|
14
|
+
`)}formatGraphQLFields(s,e){if(!s||s.length===0)return "";let n=[];for(let o of s){let p=" ".repeat(e);o.fields&&o.fields.length>0?(n.push(`${p}${o.name} {`),n.push(this.formatGraphQLFields(o.fields,e+1)),n.push(`${p}}`)):n.push(`${p}${o.name}`);}return n.join(`
|
|
15
|
+
`)}generateDataFlowDoc(s){let e=[`# ${s.displayName} - Data Flow`,""],n=s.analysis.dataFlows.filter(a=>a.name.includes("\u{1F4E1}")||a.operations.some(i=>i.includes("Query"))),o=s.analysis.dataFlows.filter(a=>a.name.includes("\u270F\uFE0F")||a.operations.some(i=>i.includes("Mutation"))),p=s.analysis.dataFlows.filter(a=>a.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\` | ${o.length} | Component \u2192 Server |`),e.push(`| \`CONTEXT\` | ${p.length} | Provider \u2192 Consumer |`),e.push(`| **Total** | **${s.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 a of s.analysis.pages){let i=this.extractFeatureFromPage(a.filePath),r=s.analysis.components.filter(c=>this.extractFeatureFromComponent(c.filePath)===i);if(!(a.dataFetching.length>0||r.some(c=>c.stateManagement.some(f=>f.includes("Apollo")||f.includes("Context")))))continue;e.push(`### ${a.path}`),e.push(""),e.push(`\`FILE: ${a.filePath}\``),e.push("");let u=this.getPageOperations(a,r,s.analysis.graphqlOperations),l=u.queries.filter(c=>c&&c.trim().length>0),m=u.mutations.filter(c=>c&&c.trim().length>0);if(l.length>0||m.length>0){e.push("```mermaid"),e.push("flowchart LR");let c=a.path.replace(/[^a-zA-Z0-9]/g,"_"),f=a.path.replace(/"/g,"'");e.push(` Page${c}["${f}"]`),l.slice(0,5).forEach((g,y)=>{let C=`Q${c}_${y}`,d=g.replace(/"/g,"'").replace(/[<>]/g,"");e.push(` ${C}["${d}"]:::query --> Page${c}`);}),m.slice(0,5).forEach((g,y)=>{let C=`M${c}_${y}`,d=g.replace(/"/g,"'").replace(/[<>]/g,"");e.push(` Page${c} --> ${C}["${d}"]:::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(u.queries.length>0||u.mutations.length>0){if(l.length>0){e.push(`**Queries (${l.length})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let c of l){let f=c.startsWith("\u2192")||c.startsWith("->"),g=c.replace(/^[→\->\s]+/,"");g&&g.trim().length>0&&(f?e.push(`<span class="gql-ref" data-ref="${g}" title="Component: ${g}">${g}</span>`):e.push(`<span class="gql-op" data-op="${g}">${g}</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 c of m){let f=c.startsWith("\u2192")||c.startsWith("->"),g=c.replace(/^[→\->\s]+/,"");g&&g.trim().length>0&&(f?e.push(`<span class="gql-ref mutation" data-ref="${g}" title="Component: ${g}">${g}</span>`):e.push(`<span class="gql-op mutation" data-op="${g}">${g}</span>`));}e.push("</div>"),e.push("");}}e.push("---"),e.push("");}let t=new Set;for(let a of p)t.add(a.source.name);if(t.size>0){e.push("## Context Providers"),e.push(""),e.push("| Provider | Description |"),e.push("|----------|-------------|");for(let a of t)e.push(`| \`${a}\` | Provides shared state |`);e.push("");}return e.join(`
|
|
16
|
+
`)}getPageOperations(s,e,n){let o=new Set,p=new Set,t=a=>{if(!a)return false;let i=a.trim();return i.length>=2&&/[a-zA-Z]/.test(i)};for(let a of s.dataFetching){let r=(a.operationName?.replace(/^[→\->\s]+/,"")||"").replace(/Document$/g,"");t(r)&&(a.type?.includes("Mutation")?p.add(r):o.add(r));}for(let a of e)for(let i of a.hooks){if(i.includes("Query")){let r=i.match(/:\s*(.+)$/);r&&t(r[1])&&o.add(r[1].trim());}if(i.includes("Mutation")){let r=i.match(/:\s*(.+)$/);r&&t(r[1])&&p.add(r[1].trim());}}return {queries:Array.from(o).filter(t),mutations:Array.from(p).filter(t)}}generateCrossRepoDoc(s){let e=["# Cross Repository Analysis","","## Architecture Overview","","```mermaid","flowchart TB"];for(let n of s.repositories){let o=n.name.replace(/[^a-zA-Z0-9]/g,"_");e.push(` subgraph ${o}["${n.displayName}"]`),e.push(` ${o}_core["Core"]`),e.push(" end");}e.push("```"),e.push(""),e.push("## API Connections"),e.push("");for(let n of s.crossRepoAnalysis.apiConnections)e.push(`- **${n.frontend}** \u2192 **${n.backend}**: \`${n.endpoint}\``);e.push(""),e.push("## Shared Types"),e.push("");for(let n of s.crossRepoAnalysis.sharedTypes)e.push(`- \`${n}\``);return e.push(""),e.join(`
|
|
17
|
+
`)}createPageDataFlowDiagram(s,e,n){let o=[],p=[],t=[],a=[];for(let i of e){i.type==="container"&&a.push(i.name);for(let r of i.hooks){if(r.includes("Query")||r.includes("\u{1F4E1}")){let h=r.includes(":")?r.split(":")[1].trim():r;p.includes(h)||p.push(h);}if(r.includes("Mutation")||r.includes("\u270F\uFE0F")){let h=r.includes(":")?r.split(":")[1].trim():r;t.includes(h)||t.push(h);}}}for(let i of s.dataFetching){let r=i.operationName.replace(/^→\s*/,"");i.type.includes("Query")&&!p.includes(r)?p.push(r):i.type.includes("Mutation")&&!t.includes(r)&&t.push(r);}if(o.push(`[Page: ${s.path}]`),o.push("\u2502"),p.length>0||t.length>0){o.push("\u251C\u2500 \u{1F4E1} Data Fetching (Query)");for(let i of p.slice(0,5))o.push(`\u2502 \u251C\u2500 ${i.substring(0,40)}`),o.push("\u2502 \u2502 \u2514\u2500 GraphQL Server \u2192 Apollo Cache \u2192 Component");if(p.length>5&&o.push(`\u2502 \u2514\u2500 ... and ${p.length-5} more`),t.length>0){o.push("\u2502"),o.push("\u251C\u2500 \u270F\uFE0F Data Mutation (Mutation)");for(let i of t.slice(0,5))o.push(`\u2502 \u251C\u2500 ${i.substring(0,40)}`),o.push("\u2502 \u2502 \u2514\u2500 Component \u2192 GraphQL Server \u2192 Apollo Cache");t.length>5&&o.push(`\u2502 \u2514\u2500 ... and ${t.length-5} more`);}}if(a.length>0){o.push("\u2502"),o.push("\u251C\u2500 \u{1F4E6} Container Components");for(let i of a.slice(0,5))o.push(`\u2502 \u2514\u2500 ${i}`);a.length>5&&o.push(`\u2502 \u2514\u2500 ... and ${a.length-5} more`);}return o.push("\u2502"),o.push("\u2514\u2500 [Render]"),o.join(`
|
|
18
|
+
`)}generateDiagramsDoc(s){let e=["# Diagrams",""];e.push("## Overview"),e.push(""),e.push("| Diagram | Type | Description |"),e.push("|---------|------|-------------|");for(let n of s)e.push(`| ${n.title} | \`${n.type.toUpperCase()}\` | Auto-generated |`);e.push("");for(let n of s)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{v as a,M as b};
|