@wtdlee/repomap 0.9.0 → 0.9.1

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.
@@ -1 +1 @@
1
- export{e as ALL_GRAPHQL_HOOKS,a as BaseAnalyzer,A as DataFlowAnalyzer,g as GRAPHQL_INDICATORS,c as GRAPHQL_MUTATION_HOOKS,d as GRAPHQL_OTHER_HOOKS,b as GRAPHQL_QUERY_HOOKS,z as GraphQLAnalyzer,f as HOOK_TYPE_MAP,y as PagesAnalyzer,B as RestApiAnalyzer,n as cleanOperationName,r as extractGraphQLContext,w as extractGraphQLOperationsFromFile,s as extractOperationNameFromGqlCall,t as extractOperationNameFromTemplate,p as getCalleeName,x as getHookInfoString,l as getHookType,u as hasGraphQLArgument,m as hasGraphQLIndicators,k as isGraphQLHook,i as isMutationHook,h as isQueryHook,j as isSubscriptionHook,o as parseToAst,v as resolveOperationName,q as traverseAst}from'../chunk-TNUKDIO7.js';
1
+ export{e as ALL_GRAPHQL_HOOKS,a as BaseAnalyzer,A as DataFlowAnalyzer,g as GRAPHQL_INDICATORS,c as GRAPHQL_MUTATION_HOOKS,d as GRAPHQL_OTHER_HOOKS,b as GRAPHQL_QUERY_HOOKS,z as GraphQLAnalyzer,f as HOOK_TYPE_MAP,y as PagesAnalyzer,B as RestApiAnalyzer,n as cleanOperationName,r as extractGraphQLContext,w as extractGraphQLOperationsFromFile,s as extractOperationNameFromGqlCall,t as extractOperationNameFromTemplate,p as getCalleeName,x as getHookInfoString,l as getHookType,u as hasGraphQLArgument,m as hasGraphQLIndicators,k as isGraphQLHook,i as isMutationHook,h as isQueryHook,j as isSubscriptionHook,o as parseToAst,v as resolveOperationName,q as traverseAst}from'../chunk-QDVE7MT3.js';
@@ -0,0 +1,20 @@
1
+ var v=class{generateAll(s,e){let n=[];for(let r of s)n.push(this.generateNavigationDiagram(r)),n.push(this.generateDataFlowDiagram(r)),n.push(this.generateComponentDiagram(r)),n.push(this.generateGraphQLDiagram(r));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,r=0,i=new Map;for(let a of s.pages){let c=a.path.split("/").filter(Boolean)[0]||"root",p=i.get(c)||[];p.push(a),i.set(c,p);}for(let[a,u]of i){let c=a.replace(/[^a-zA-Z0-9]/g,"_"),p=a==="root"?"Root Pages":`/${a}`;e.push(""),e.push(` subgraph ${c}["${p}"]`),e.push(" direction TB");for(let l of u){let d=`P${r++}`;n.set(l.path,d);let D=l.path.split("/").filter(Boolean),m=D.length>1?D.slice(1).join("/"):l.path,f=l.authentication.required?" AUTH":"";e.push(` ${d}["${m}${f}"]`);}e.push(" end");}let t=0,o=30;e.push(""),e.push(" %% Navigation Links");for(let a of s.pages){if(t>=o)break;let u=n.get(a.path);for(let c of a.linkedPages.slice(0,2)){if(t>=o)break;let p=n.get(c);u&&p&&u!==p&&(e.push(` ${u} --> ${p}`),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 a of s.pages){let u=n.get(a.path);u&&(a.authentication.required?e.push(` class ${u} authRequired`):e.push(` class ${u} public`));}return {type:"flowchart",title:`${s.repository} - Page Navigation`,content:e.join(`
2
+ `),relatedFiles:s.pages.map(a=>a.filePath)}}generateDataFlowDiagram(s){let e=["flowchart LR"," %% Data Flow Diagram"],n=new Map,r=0,i=p=>{let l=`${p.type}:${p.name}`;if(!n.has(l)){let d=p.type.charAt(0).toUpperCase();n.set(l,`${d}${r++}`);}return n.get(l)??`N${r++}`},o=p=>p.replace(/[\u{1F4E1}\u{270F}\u{FE0F}\u{1F504}\u{1F4E6}]/gu,"").trim().substring(0,40),a=s.dataFlows.filter(p=>p.name.includes("\u{1F4E1}")||p.operations.some(l=>l.includes("Query"))),u=s.dataFlows.filter(p=>p.name.includes("\u270F\uFE0F")||p.operations.some(l=>l.includes("Mutation"))),c=s.dataFlows.filter(p=>p.name.includes("\u{1F504}")||p.source.type==="context"||p.operations.some(l=>l.includes("Context")));if(a.length>0){e.push(""),e.push(" subgraph Queries[\u{1F4E1} Queries]"),e.push(" direction TB");for(let p of a.slice(0,20)){let l=i(p.source),d=i(p.target),D=o(p.source.name),m=o(p.target.name);e.push(` ${l}(("${D}"))`),e.push(` ${d}["${m}"]`),e.push(` ${l} --> ${d}`);}e.push(" end");}if(u.length>0){e.push(""),e.push(" subgraph Mutations[\u270F\uFE0F Mutations]"),e.push(" direction TB");for(let p of u.slice(0,20)){let l=i(p.source),d=i(p.target),D=o(p.source.name),m=o(p.target.name);e.push(` ${l}["${D}"]`),e.push(` ${d}(("${m}"))`),e.push(` ${l} --> ${d}`);}e.push(" end");}if(c.length>0){e.push(""),e.push(" subgraph Context[\u{1F504} Context]"),e.push(" direction TB");for(let p of c.slice(0,15)){let l=i(p.source),d=i(p.target),D=o(p.source.name),m=o(p.target.name);e.push(` ${l}{{"${D}"}}`),e.push(` ${d}["${m}"]`),e.push(` ${l} -.-> ${d}`);}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(p=>p.source.name)}}generateComponentDiagram(s){let e=["flowchart TB"," %% Component Hierarchy"],n=new Map;for(let t of s.components){let o=n.get(t.type)||[];o.push(t),n.set(t.type,o);}for(let[t,o]of n){e.push(` subgraph ${t.charAt(0).toUpperCase()+t.slice(1)}s`);for(let a of o.slice(0,20)){let u=a.name.replace(/[^a-zA-Z0-9]/g,"_");e.push(` ${u}["${a.name}"]`);}e.push(" end");}let r=0,i=50;for(let t of s.components){if(r>=i)break;let o=t.name.replace(/[^a-zA-Z0-9]/g,"_");for(let a of t.dependencies.slice(0,3)){if(r>=i)break;let u=a.replace(/[^a-zA-Z0-9]/g,"_");e.push(` ${o} --> ${u}`),r++;}}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"),r=s.graphqlOperations.filter(t=>t.type==="mutation"),i=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 o=`Q_${t.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${o}["${t.name}"]`),e.push(` ${o} --> API`);}e.push(" end");}if(r.length>0){e.push(" subgraph Mutations");for(let t of r.slice(0,15)){let o=`M_${t.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${o}["${t.name}"]`),e.push(` ${o} --> API`);}e.push(" end");}if(i.length>0){e.push(" subgraph Fragments");for(let t of i.slice(0,10)){let o=`F_${t.name.replace(/[^a-zA-Z0-9]/g,"_")}`;e.push(` ${o}[/"${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 r of s){let i=r.repository.replace(/[^a-zA-Z0-9]/g,"_");n.push(` subgraph ${i}["${r.repository}"]`),n.push(` ${i}_pages["\u{1F4C4} ${r.pages.length} Pages"]`),n.push(` ${i}_gql["\u{1F537} ${r.graphqlOperations.length} GraphQL Ops"]`),n.push(` ${i}_comp["\u{1F9E9} ${r.components.length} Components"]`),n.push(" end");}for(let r of e){let i=r.sourceRepo.replace(/[^a-zA-Z0-9]/g,"_"),t=r.targetRepo.replace(/[^a-zA-Z0-9]/g,"_"),o="-->";r.linkType==="api-call"?o="==>":r.linkType==="graphql-operation"&&(o="-..->"),n.push(` ${i}_gql ${o}|"${r.linkType}"| ${t}_gql`);}return {type:"flowchart",title:"Cross-Repository Architecture",content:n.join(`
6
+ `),relatedFiles:s.map(r=>r.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 r=s.source;for(let t=0;t<s.via.length;t++){let o=s.via[t],a=s.operations[t]||"data";e.push(` ${r.name}->>+${o.name}: ${a}`),r=o;}let i=s.operations[s.operations.length-1]||"data";return e.push(` ${r.name}->>+${s.target.name}: ${i}`),e.push(` ${s.target.name}-->>-${s.source.name}: response`),{type:"sequence",title:s.name,content:e.join(`
7
+ `),relatedFiles:[]}}};var A=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 r of s.repositories)n.push(`### [${r.displayName}](/docs/repos/${r.name}/index)`),n.push(""),n.push(`- **Version**: ${r.version}`),n.push(`- **Commit**: \`${r.commitHash.substring(0,7)}\``),n.push(`- **Pages**: ${r.summary.totalPages}`),n.push(`- **Components**: ${r.summary.totalComponents}`),n.push(`- **GraphQL Ops**: ${r.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(o=>o.authentication.required).length,r=s.analysis.pages.filter(o=>o.dataFetching.some(a=>!a.type.includes("Mutation"))).length,i=s.analysis.pages.filter(o=>o.dataFetching.some(a=>a.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 | ${r} |`),e.push(`| With Mutations | ${i} |`),e.push("");let t=new Map;for(let o of s.analysis.pages){let a=o.path.split("/")[1]||"root",u=t.get(a)||[];u.push(o),t.set(a,u);}for(let[o,a]of t){e.push(`## /${o}`),e.push(""),e.push("| Page | Auth | Layout |"),e.push("|------|------|--------|");for(let u of a){let c=u.path.replace(`/${o}`,"")||"/",p=u.authentication.required?"Required":"Public",l=u.layout||"-";e.push(`| \`${c}\` | ${p} | ${l} |`);}e.push("");for(let u of a){let c=u.dataFetching||[];if(c.length===0)continue;let p=new Map,l=(m,f,h)=>{p.has(m)||p.set(m,{label:f,open:h,queries:new Set,mutations:new Set});let g=p.get(m);if(!g){let $={label:f,open:h,queries:new Set,mutations:new Set};return p.set(m,$),$}return g};for(let m of c){let h=(m.operationName||"").replace(/^[→\->\s]+/,"").trim();if(!h||h.length<2)continue;let g=m.type.includes("Mutation"),$=m.source||"",q="direct",C="Direct (this page)",y=true;$.startsWith("close:")?(q="close",C="Close (related)",y=true):$.startsWith("indirect:")||$.startsWith("usedIn:")||$.startsWith("import:")?(q="indirect",C="Indirect",y=false):$.startsWith("common:")?(q="common",C="Common (shared)",y=false):$.startsWith("hook:")?(q="hook",C="Hook",y=false):$.startsWith("component:")&&(q="component",C="Component",y=false);let P=l(q,C,y);g?P.mutations.add(h):P.queries.add(h);}let d=Array.from(p.values()).reduce((m,f)=>m+f.queries.size+f.mutations.size,0);if(d===0)continue;let D=["direct","close","component","hook","indirect","common"];e.push(`### ${u.path}`),e.push(""),e.push(`> ${u.filePath}`),e.push(""),e.push(`**Data Operations (${d})**`),e.push("");for(let m of D){let f=p.get(m);if(!f)continue;let h=f.queries.size+f.mutations.size;if(h!==0){if(e.push(`<details class="ops-group${f.open?" is-open":""}"${f.open?" open":""}>`),e.push(`<summary class="ops-group__summary"><span class="ops-group__title">${f.label}</span><span class="ops-group__count">${h}</span></summary>`),e.push(""),f.queries.size>0){e.push(`**Queries (${f.queries.size})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let g of Array.from(f.queries).sort())e.push(`<span class="gql-op" data-op="${g}">${g}</span>`);e.push("</div>"),e.push("");}if(f.mutations.size>0){e.push(`**Mutations (${f.mutations.size})**`),e.push(""),e.push('<div class="gql-ops-list">');for(let g of Array.from(f.mutations).sort())e.push(`<span class="gql-op mutation" data-op="${g}">${g}</span>`);e.push("</div>"),e.push("");}e.push("</details>"),e.push("");}}e.push("");}}return e.join(`
10
+ `)}generateComponentsDoc(s){let e=[`# ${s.displayName} - Components`,""],n=new Map;for(let i of s.analysis.components){let t=n.get(i.type)||[];t.push(i),n.set(i.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 r=new Map;for(let i of s.analysis.pages)r.set(i.path,[]);for(let i of s.analysis.components)for(let t of s.analysis.pages){let o=this.extractFeatureFromPage(t.filePath),a=this.extractFeatureFromComponent(i.filePath);o&&a&&o===a&&r.get(t.path)?.push(i);}e.push("## By Page"),e.push("");for(let[i,t]of r){if(t.length===0)continue;let o=t.filter(c=>c.type==="container"),a=t.filter(c=>c.type==="presentational"),u=t.filter(c=>c.type==="hook");e.push(`### ${i}`),e.push(""),e.push("| Component | Type | Data |"),e.push("|-----------|------|------|");for(let c of o){let p=this.formatComponentDataOps(c,s.analysis.graphqlOperations);e.push(`| ${c.name} | Container | ${p||"-"} |`);}for(let c of a.slice(0,10)){let p=this.formatComponentDataOps(c,s.analysis.graphqlOperations);e.push(`| ${c.name} | UI | ${p||"-"} |`);}for(let c of u){let p=this.formatComponentDataOps(c,s.analysis.graphqlOperations);e.push(`| ${c.name} | Hook | ${p||"-"} |`);}if(e.push(""),a.length>10){let c=a.slice(10),p=`more-ui-${i.replace(/[^a-zA-Z0-9]/g,"-")}`;e.push(`<details id="${p}">`),e.push(`<summary style="cursor:pointer;color:var(--accent);padding:8px 0">Show ${c.length} more UI components</summary>`),e.push(""),e.push("| Component | Type | Data |"),e.push("|-----------|------|------|");for(let l of c){let d=this.formatComponentDataOps(l,s.analysis.graphqlOperations);e.push(`| ${l.name} | UI | ${d||"-"} |`);}e.push(""),e.push("</details>"),e.push("");}}e.push("## By Type"),e.push("");for(let[i,t]of n){e.push(`### ${i.charAt(0).toUpperCase()+i.slice(1)} (${t.length})`),e.push(""),e.push("| Name | File | Data |"),e.push("|------|------|------|");for(let o of t.slice(0,25)){let a=o.filePath.replace("src/features/","").replace("src/",""),u=this.formatComponentDataOps(o,s.analysis.graphqlOperations);e.push(`| ${o.name} | ${a} | ${u||"-"} |`);}if(e.push(""),t.length>25){let o=t.slice(25),a=`more-${i}-components`;e.push(`<details id="${a}">`),e.push(`<summary style="cursor:pointer;color:var(--accent);padding:8px 0">Show ${o.length} more ${i} components</summary>`),e.push(""),e.push("| Name | File | Data |"),e.push("|------|------|------|");for(let u of o){let c=u.filePath.replace("src/features/","").replace("src/",""),p=this.formatComponentDataOps(u,s.analysis.graphqlOperations);e.push(`| ${u.name} | ${c} | ${p||"-"} |`);}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,e){let n=[],r=[];if(e&&s.filePath)for(let a of e)a.type!=="query"&&a.type!=="mutation"||!(a.filePath===s.filePath||a.usedIn&&a.usedIn.includes(s.filePath))||(a.type==="mutation"?r.push(a.name):n.push(a.name));for(let a of s.hooks){let u=a.match(/(?:useQuery|Query):\s*(\w+)/),c=a.match(/(?:useMutation|Mutation):\s*(\w+)/);u&&u[1]&&u[1].trim().length>=2?n.push(u[1]):c&&c[1]&&c[1].trim().length>=2&&r.push(c[1]);}let i=Array.from(new Set(n.filter(a=>a&&a.trim().length>=2))),t=Array.from(new Set(r.filter(a=>a&&a.trim().length>=2)));if(i.length===0&&t.length===0)return "";let o=[];for(let a of i.sort())o.push(`<span class="gql-op" data-op="${a}">${a}</span>`);for(let a of t.sort())o.push(`<span class="gql-op mutation" data-op="${a}">${a}</span>`);return `<div class="gql-ops-inline">${o.join(" ")}</div>`}generateGraphQLDoc(s){let e=[`# ${s.displayName} - GraphQL`,""],n=s.analysis.graphqlOperations.filter(t=>t.type==="query"),r=s.analysis.graphqlOperations.filter(t=>t.type==="mutation"),i=s.analysis.graphqlOperations.filter(t=>t.type==="fragment");if(e.push("| Type | Count |"),e.push("|------|-------|"),e.push(`| Query | ${n.length} |`),e.push(`| Mutation | ${r.length} |`),e.push(`| Fragment | ${i.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 o=t.returnType||"unknown",a=t.variables.length,u=t.usedIn.length;if(e.push(`> Return: \`${o}\` | Variables: ${a} | Used: ${u} files`),e.push(""),t.variables.length>0){e.push("| Variable | Type |"),e.push("|----------|------|");for(let c of t.variables)e.push(`| ${c.name} | \`${c.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(r.length>0){e.push("## Mutations"),e.push("");for(let t of r.slice(0,80)){e.push(`### ${t.name}`),e.push("");let o=t.variables.length,a=t.usedIn.length;if(e.push(`> Variables: ${o} | Used: ${a} files`),e.push(""),t.variables.length>0){e.push("| Variable | Type |"),e.push("|----------|------|");for(let u of t.variables)e.push(`| ${u.name} | \`${u.type}\` |`);e.push("");}t.fields&&t.fields.length>0&&(e.push("```graphql"),e.push(this.formatGraphQLFields(t.fields,0)),e.push("```"),e.push(""));}r.length>80&&e.push(`*+${r.length-80} more mutations*
13
+ `);}if(i.length>0){e.push("## Fragments"),e.push(""),e.push("| Name | Type | Fields |"),e.push("|------|------|--------|");for(let t of i.slice(0,50)){let o=t.fields?.length||0;e.push(`| ${t.name} | ${t.returnType||"-"} | ${o} |`);}i.length>50&&e.push(`| *+${i.length-50} more* | | |`),e.push("");}return e.join(`
14
+ `)}formatGraphQLFields(s,e){if(!s||s.length===0)return "";let n=[];for(let r of s){let i=" ".repeat(e);r.fields&&r.fields.length>0?(n.push(`${i}${r.name} {`),n.push(this.formatGraphQLFields(r.fields,e+1)),n.push(`${i}}`)):n.push(`${i}${r.name}`);}return n.join(`
15
+ `)}generateDataFlowDoc(s){let e=[`# ${s.displayName} - Data Flow`,""],n=s.analysis.dataFlows.filter(o=>o.name.includes("\u{1F4E1}")||o.operations.some(a=>a.includes("Query"))),r=s.analysis.dataFlows.filter(o=>o.name.includes("\u270F\uFE0F")||o.operations.some(a=>a.includes("Mutation"))),i=s.analysis.dataFlows.filter(o=>o.source.type==="context");e.push("## Overview"),e.push(""),e.push("| Type | Count | Direction |"),e.push("|------|-------|-----------|"),e.push(`| \`QUERY\` | ${n.length} | Server \u2192 Component |`),e.push(`| \`MUTATION\` | ${r.length} | Component \u2192 Server |`),e.push(`| \`CONTEXT\` | ${i.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(""),e.push('<div class="dataflow-page-flows">'),e.push(['<div class="ops-filters" data-filter-scope="dataflow">',' <span class="ops-filters__label">Show:</span>',' <label class="ops-toggle"><input type="checkbox" data-filter="direct" checked> Direct</label>',' <label class="ops-toggle"><input type="checkbox" data-filter="close" checked> Close</label>',' <label class="ops-toggle"><input type="checkbox" data-filter="indirect" checked> Indirect</label>',' <label class="ops-toggle"><input type="checkbox" data-filter="common"> Common</label>',"</div>"].join(`
16
+ `)),e.push("");for(let o of s.analysis.pages){let a=this.extractFeatureFromPage(o.filePath),u=s.analysis.components.filter(h=>this.extractFeatureFromComponent(h.filePath)===a);if(!(o.dataFetching.length>0||u.some(h=>h.stateManagement.some(g=>g.includes("Apollo")||g.includes("Context")))))continue;e.push(`### ${o.path}`),e.push(""),e.push(`\`FILE: ${o.filePath}\``),e.push("");let p=this.getPageOperationGroups(o),l=this.flattenGroups(p,"queries"),d=this.flattenGroups(p,"mutations");if(l.length>0||d.length>0){let h=o.path.replace(/[^a-zA-Z0-9]/g,"_"),g=o.path.replace(/"/g,"'");e.push(`<pre class="mermaid" data-mermaid-scope="dataflow" data-mermaid-page="${h}">`),e.push("flowchart LR"),e.push(` Page${h}["${g}"]`),e.push("");let $=10,q=["direct","close","indirect","common"];for(let C of q){let y=p[C];y.queries.length===0&&y.mutations.length===0||(e.push(`%%DFG_GROUP:${C}:start%%`),y.queries.slice(0,$).forEach((P,w)=>{let b=`Q${h}_${C}_${w}`,F=P.replace(/"/g,"'").replace(/[<>]/g,"");e.push(` ${b}["${F}"]:::query --> Page${h}`);}),y.mutations.slice(0,$).forEach((P,w)=>{let b=`M${h}_${C}_${w}`,F=P.replace(/"/g,"'").replace(/[<>]/g,"");e.push(` Page${h} --> ${b}["${F}"]:::mutation`);}),e.push(`%%DFG_GROUP:${C}:end%%`),e.push(""));}e.push(" classDef query fill:#dbeafe,stroke:#1d4ed8,color:#1e40af"),e.push(" classDef mutation fill:#fce7f3,stroke:#be185d,color:#9d174d"),e.push("</pre>"),e.push("");}let D=["direct","close","indirect","common"],m={direct:{label:"Direct (this page)",open:true,defaultVisible:true},close:{label:"Close (related)",open:true,defaultVisible:true},indirect:{label:"Indirect (via imports)",open:false,defaultVisible:true},common:{label:"Common (shared)",open:false,defaultVisible:false}};if(D.some(h=>p[h].queries.length>0||p[h].mutations.length>0))for(let h of D){let g=p[h],$=m[h];if(g.queries.length===0&&g.mutations.length===0)continue;let q=$.open?" open":"",C=$.defaultVisible?"":' style="display:none"';if(e.push(`<details class="ops-group" data-ops-scope="dataflow" data-ops-group="${h}"${q}${C}>`),e.push(`<summary class="ops-group__summary"><span class="ops-group__title">${$.label}</span><span class="ops-group__count">${g.queries.length+g.mutations.length}</span></summary>`),g.queries.length>0){e.push(`<p><strong>Queries (${g.queries.length})</strong></p>`),e.push('<div class="gql-ops-list">');for(let y of g.queries)e.push(`<span class="gql-op" data-op="${y}">${y}</span>`);e.push("</div>");}if(g.mutations.length>0){e.push(`<p><strong>Mutations (${g.mutations.length})</strong></p>`),e.push('<div class="gql-ops-list">');for(let y of g.mutations)e.push(`<span class="gql-op mutation" data-op="${y}">${y}</span>`);e.push("</div>");}e.push("</details>"),e.push("");}e.push("---"),e.push("");}e.push("</div>");let t=new Set;for(let o of i)t.add(o.source.name);if(t.size>0){e.push("## Context Providers"),e.push(""),e.push("| Provider | Description |"),e.push("|----------|-------------|");for(let o of t)e.push(`| \`${o}\` | Provides shared state |`);e.push("");}return e.join(`
17
+ `)}getPageOperationGroups(s){let e={direct:{queries:new Set,mutations:new Set},close:{queries:new Set,mutations:new Set},indirect:{queries:new Set,mutations:new Set},common:{queries:new Set,mutations:new Set}},n=t=>{if(!t)return false;let o=t.trim();return o.length>=2&&/[a-zA-Z]/.test(o)},r=t=>{if(!t)return "direct";let o=t.trim();return o.startsWith("common:")?"common":o.startsWith("close:")?"close":o.startsWith("indirect:")?"indirect":"direct"};for(let t of s.dataFetching||[]){let a=(t.operationName?.replace(/^[→\->\s]+/,"")||"").replace(/Document$/g,"").trim();if(!n(a))continue;let u=r(t.source);t.type?.includes("Mutation")??false?e[u].mutations.add(a):e[u].queries.add(a);}let i=t=>Array.from(t).filter(n).sort((o,a)=>o.localeCompare(a));return {direct:{queries:i(e.direct.queries),mutations:i(e.direct.mutations)},close:{queries:i(e.close.queries),mutations:i(e.close.mutations)},indirect:{queries:i(e.indirect.queries),mutations:i(e.indirect.mutations)},common:{queries:i(e.common.queries),mutations:i(e.common.mutations)}}}flattenGroups(s,e){let n=new Set;for(let r of Object.values(s))for(let i of r[e])n.add(i);return Array.from(n).sort((r,i)=>r.localeCompare(i))}generateCrossRepoDoc(s){let e=["# Cross Repository Analysis","","## Architecture Overview","","```mermaid","flowchart TB"];for(let n of s.repositories){let r=n.name.replace(/[^a-zA-Z0-9]/g,"_");e.push(` subgraph ${r}["${n.displayName}"]`),e.push(` ${r}_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(`
18
+ `)}createPageDataFlowDiagram(s,e,n){let r=[],i=[],t=[],o=[];for(let a of e){a.type==="container"&&o.push(a.name);for(let u of a.hooks){if(u.includes("Query")||u.includes("\u{1F4E1}")){let c=u.includes(":")?u.split(":")[1].trim():u;i.includes(c)||i.push(c);}if(u.includes("Mutation")||u.includes("\u270F\uFE0F")){let c=u.includes(":")?u.split(":")[1].trim():u;t.includes(c)||t.push(c);}}}for(let a of s.dataFetching){let u=a.operationName.replace(/^→\s*/,"");a.type.includes("Query")&&!i.includes(u)?i.push(u):a.type.includes("Mutation")&&!t.includes(u)&&t.push(u);}if(r.push(`[Page: ${s.path}]`),r.push("\u2502"),i.length>0||t.length>0){r.push("\u251C\u2500 \u{1F4E1} Data Fetching (Query)");for(let a of i.slice(0,5))r.push(`\u2502 \u251C\u2500 ${a.substring(0,40)}`),r.push("\u2502 \u2502 \u2514\u2500 GraphQL Server \u2192 Apollo Cache \u2192 Component");if(i.length>5&&r.push(`\u2502 \u2514\u2500 ... and ${i.length-5} more`),t.length>0){r.push("\u2502"),r.push("\u251C\u2500 \u270F\uFE0F Data Mutation (Mutation)");for(let a of t.slice(0,5))r.push(`\u2502 \u251C\u2500 ${a.substring(0,40)}`),r.push("\u2502 \u2502 \u2514\u2500 Component \u2192 GraphQL Server \u2192 Apollo Cache");t.length>5&&r.push(`\u2502 \u2514\u2500 ... and ${t.length-5} more`);}}if(o.length>0){r.push("\u2502"),r.push("\u251C\u2500 \u{1F4E6} Container Components");for(let a of o.slice(0,5))r.push(`\u2502 \u2514\u2500 ${a}`);o.length>5&&r.push(`\u2502 \u2514\u2500 ... and ${o.length-5} more`);}return r.push("\u2502"),r.push("\u2514\u2500 [Render]"),r.join(`
19
+ `)}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(`
20
+ `)}};export{v as a,A as b};
@@ -1,12 +1,12 @@
1
- import {a as a$2}from'./chunk-P7MX3M5U.js';import {a as a$3}from'./chunk-VV3A3UE3.js';import {B,A as A$1,z,y}from'./chunk-TNUKDIO7.js';import {a,b}from'./chunk-HPBPEGHS.js';import {a as a$1}from'./chunk-SMN6XFMS.js';import {k}from'./chunk-H7VVRHQZ.js';import {simpleGit}from'simple-git';import*as u from'fs/promises';import*as d from'path';import E from'express';import {Server}from'socket.io';import*as O from'http';import {marked}from'marked';import*as C from'net';var v=class{config;mermaidGenerator;markdownGenerator;constructor(a$1){this.config=a$1,this.mermaidGenerator=new a,this.markdownGenerator=new b;}async generate(){let a=[];for(let r of this.config.repositories)try{let i=await this.analyzeRepository(r);a.push(i);}catch(i){console.error(`\u274C ${r.name}: ${i.message}`);}let s=this.analyzeCrossRepo(a),e=a.map(r=>r.analysis),n=this.extractCrossRepoLinks(e),t=this.mermaidGenerator.generateAll(e,n),o={generatedAt:new Date().toISOString(),repositories:a,crossRepoAnalysis:s,diagrams:t};return await this.writeDocumentation(o),o}async analyzeRepository(a){let{version:s,commitHash:e}=await this.getRepoInfo(a),n=a.analyzers.map(p=>this.createAnalyzer(p,a)).filter(p=>p!==null),t=Date.now(),o=await Promise.all(n.map(p=>p.analyze())),r=((Date.now()-t)/1e3).toFixed(1);console.log(` Analyzed ${a.displayName} in ${r}s`);let i=this.mergeAnalysisResults(o,a.name,s,e);this.enrichPagesWithHookGraphQL(i);let l={totalPages:i.pages.length,totalComponents:i.components.length,totalGraphQLOperations:i.graphqlOperations.length,totalDataFlows:i.dataFlows.length,authRequiredPages:i.pages.filter(p=>p.authentication.required).length,publicPages:i.pages.filter(p=>!p.authentication.required).length};return {name:a.name,displayName:a.displayName,version:s,commitHash:e,analysis:i,summary:l}}async getRepoInfo(a){try{let n=(await simpleGit(a.path).log({n:1})).latest?.hash||"unknown",t="unknown";try{let o=d.join(a.path,"package.json");t=JSON.parse(await u.readFile(o,"utf-8")).version||"unknown";}catch{}return {version:t,commitHash:n}}catch{return {version:"unknown",commitHash:"unknown"}}}createAnalyzer(a,s){switch(a){case "pages":if(s.type==="nextjs"||s.type==="rails"||s.type==="generic")return new y(s);break;case "graphql":return new z(s);case "dataflow":case "components":return new A$1(s);case "rest-api":case "api":return new B(s)}return null}mergeAnalysisResults(a,s,e,n){let t={repository:s,timestamp:new Date().toISOString(),version:e,commitHash:n,pages:[],graphqlOperations:[],apiCalls:[],components:[],dataFlows:[],apiEndpoints:[],models:[],crossRepoLinks:[]};for(let o of a)o.pages&&t.pages.push(...o.pages),o.graphqlOperations&&t.graphqlOperations.push(...o.graphqlOperations),o.apiCalls&&t.apiCalls.push(...o.apiCalls),o.components&&t.components.push(...o.components),o.dataFlows&&t.dataFlows.push(...o.dataFlows),o.apiEndpoints&&t.apiEndpoints.push(...o.apiEndpoints),o.models&&t.models.push(...o.models),o.crossRepoLinks&&t.crossRepoLinks.push(...o.crossRepoLinks);return t}analyzeCrossRepo(a){let s=[],e=[],n=[],t=[],o=new Map;for(let l of a)for(let p of l.analysis.graphqlOperations){let c=o.get(p.name)||[];c.push(l.name),o.set(p.name,c);}for(let[l,p]of o)p.length>1&&s.push(l);let r=a.filter(l=>l.analysis.pages.length>0),i=a.filter(l=>l.analysis.apiEndpoints.length>0);for(let l of r)for(let p of i)for(let c of p.analysis.apiEndpoints)e.push({frontend:l.name,backend:p.name,endpoint:c.path,operations:l.analysis.graphqlOperations.filter(m=>m.usedIn.length>0).map(m=>m.name)});return {sharedTypes:s,apiConnections:e,navigationFlows:n,dataFlowAcrossRepos:t}}extractCrossRepoLinks(a){let s=[],e=new Map;for(let n of a)for(let t of n.graphqlOperations){let o=e.get(t.name)||[];o.push(n),e.set(t.name,o);}for(let[n,t]of e)t.length>1&&s.push({sourceRepo:t[0].repository,sourcePath:`graphql/${n}`,targetRepo:t[1].repository,targetPath:`graphql/${n}`,linkType:"graphql-operation",description:`Shared GraphQL operation: ${n}`});return s}enrichPagesWithHookGraphQL(a){let s=new Map;for(let t of a.graphqlOperations){if(!t.filePath)continue;let r=(t.filePath.split("/").pop()||"").replace(/\.(ts|tsx|js|jsx)$/,"");r.startsWith("use")&&(s.has(r)||s.set(r,new Set),s.get(r).add(t.name));}for(let t of a.components){if(t.type!=="hook")continue;let o=[];for(let r of t.hooks){let i=r.match(/^(Query|Mutation|Subscription):\s*(.+)$/);i&&o.push(i[2]);}if(o.length>0){s.has(t.name)||s.set(t.name,new Set);for(let r of o)s.get(t.name).add(r);}}let e=new Map;for(let t of a.graphqlOperations){if(t.type!=="query"&&t.type!=="mutation"&&t.type!=="subscription"||!t.filePath)continue;let o=t.filePath.replace(/\.(ts|tsx|js|jsx)$/,"");e.has(o)||e.set(o,[]),e.get(o).push({opName:t.name,opType:t.type});}let n=new Map;for(let t of a.graphqlOperations)(t.type==="query"||t.type==="mutation"||t.type==="subscription")&&n.set(t.name,t.type);for(let t of a.pages){let o=new Set(t.dataFetching.map(l=>l.operationName?.replace(/^[→\->\s]+/,"")||"")),r=a.components.find(l=>l.filePath===`src/pages/${t.filePath}`);if(!r)continue;let i=[];i.push(...r.hooks.filter(l=>l.startsWith("use")));for(let l of r.dependencies)l.startsWith("use")&&i.push(l);for(let l of i){let p=s.get(l);if(p)for(let c of p){if(o.has(c))continue;o.add(c);let m=n.get(c)||"query";t.dataFetching.push({type:m==="mutation"?"useMutation":"useQuery",operationName:c,source:`hook:${l}`});}}if(r.imports)for(let l of r.imports){let p=d.dirname(r.filePath),c=l.path;l.path.startsWith(".")?(c=d.join(p,l.path),c=d.normalize(c)):l.path.startsWith("@/")&&(c=l.path.replace("@/","src/")),c=c.replace(/\.(ts|tsx|js|jsx)$/,"");let m=e.get(c);if(m)for(let y of m)o.has(y.opName)||(o.add(y.opName),t.dataFetching.push({type:y.opType==="mutation"?"useMutation":"useQuery",operationName:y.opName,source:`import:${l.path}`}));}}for(let t of a.components){if(t.type!=="container"&&t.type!=="page")continue;let o=a.pages.find(i=>i.component===t.name||i.filePath?.includes(t.name));if(!o)continue;let r=new Set(o.dataFetching.map(i=>i.operationName?.replace(/^[→\->\s]+/,"")||""));for(let i of t.hooks){if(!i.startsWith("use"))continue;let l=s.get(i);if(l)for(let p of l){if(r.has(p))continue;r.add(p);let c=n.get(p)||"query";o.dataFetching.push({type:c==="mutation"?"useMutation":"useQuery",operationName:p,source:`component:${t.name}`});}}for(let i of t.dependencies){if(!i.startsWith("use"))continue;let l=s.get(i);if(l)for(let p of l){if(r.has(p))continue;r.add(p);let c=n.get(p)||"query";o.dataFetching.push({type:c==="mutation"?"useMutation":"useQuery",operationName:p,source:`component:${t.name}`});}}if(t.imports)for(let i of t.imports){let l=d.dirname(t.filePath),p=i.path;i.path.startsWith(".")?p=d.normalize(d.join(l,i.path)):i.path.startsWith("@/")&&(p=i.path.replace("@/","src/")),p=p.replace(/\.(ts|tsx|js|jsx)$/,"");let c=e.get(p);if(c)for(let m of c)r.has(m.opName)||(r.add(m.opName),o.dataFetching.push({type:m.opType==="mutation"?"useMutation":"useQuery",operationName:m.opName,source:`component:${t.name}`}));}}}async writeDocumentation(a){let s=this.config.outputDir;await u.mkdir(s,{recursive:true});let e=this.markdownGenerator.generateDocumentation(a);for(let[t,o]of e){let r=d.join(s,t),i=d.dirname(r);await u.mkdir(i,{recursive:true}),await u.writeFile(r,o,"utf-8");}let n=d.join(s,"report.json");await u.writeFile(n,JSON.stringify(a,null,2),"utf-8");}};function A(f){return new Promise(a=>{let s=C.createServer();s.once("error",e=>{e.code,a(false);}),s.once("listening",()=>{s.close(),a(true);}),s.listen(f);})}async function L(f,a=10){for(let s=0;s<a;s++){let e=f+s;if(await A(e))return e}throw new Error(`No available port found between ${f} and ${f+a-1}`)}var P=class{config;port;app;server;io;engine;currentReport=null;envResult=null;railsAnalysis=null;constructor(a,s=3030){this.config=a,this.port=s,this.app=E(),this.server=O.createServer(this.app),this.io=new Server(this.server),this.engine=new v(a),this.setupRoutes(),this.setupSocketIO();}setupRoutes(){this.app.use("/assets",E.static(d.join(this.config.outputDir,"assets"))),["common.css","page-map.css","docs.css","rails-map.css"].forEach(e=>{this.app.get(`/${e}`,async(n,t)=>{let o=[d.join(d.dirname(new URL(import.meta.url).pathname),"generators","assets",e),d.join(d.dirname(new URL(import.meta.url).pathname),"..","generators","assets",e),d.join(process.cwd(),"dist","generators","assets",e),d.join(process.cwd(),"src","generators","assets",e)];for(let r of o)try{let i=await u.readFile(r,"utf-8");t.type("text/css").send(i);return}catch{}t.status(404).send("CSS not found");});}),["favicon.ico","favicon.svg","favicon-96x96.png","apple-touch-icon.png","site.webmanifest","web-app-manifest-192x192.png","web-app-manifest-512x512.png"].forEach(e=>{(e==="favicon.ico"?[`/${e}`,`/favicon/${e}`]:[`/favicon/${e}`]).forEach(t=>{this.app.get(t,async(o,r)=>{let i=[d.join(d.dirname(new URL(import.meta.url).pathname),"generators","assets","favicon",e),d.join(d.dirname(new URL(import.meta.url).pathname),"..","generators","assets","favicon",e),d.join(process.cwd(),"dist","generators","assets","favicon",e),d.join(process.cwd(),"src","generators","assets","favicon",e)];for(let l of i)try{let p=await u.readFile(l),c=e.split(".").pop(),m={ico:"image/x-icon",svg:"image/svg+xml",png:"image/png",webmanifest:"application/manifest+json"};r.type(m[c||""]||"application/octet-stream").send(p);return}catch{}r.status(404).send("File not found");});});}),this.app.get("/",(e,n)=>{n.redirect("/page-map");}),this.app.get("/page-map",(e,n)=>{if(!this.currentReport){n.status(503).send("Documentation not ready yet");return}let t=new a$1;n.send(t.generatePageMapHtml(this.currentReport,{envResult:this.envResult,railsAnalysis:this.railsAnalysis}));}),this.app.get("/rails-map",(e,n)=>{if(!this.railsAnalysis){n.status(404).send("No Rails environment detected");return}let t=new a$2;n.send(t.generateFromResult(this.railsAnalysis));}),this.app.get("/docs",async(e,n)=>{n.send(await this.renderPage("index"));}),this.app.get("/docs/*path",async(e,n)=>{let t=e.params.path,o=Array.isArray(t)?t.join("/"):t||"index";n.send(await this.renderPage(o));}),this.app.get("/api/report",(e,n)=>{n.json(this.currentReport);}),this.app.get("/api/env",(e,n)=>{n.json(this.envResult);}),this.app.get("/api/rails",(e,n)=>{this.railsAnalysis?n.json(this.railsAnalysis):n.status(404).json({error:"No Rails analysis available"});}),this.app.get("/api/diagram/:name",(e,n)=>{let t=this.currentReport?.diagrams.find(o=>o.title.toLowerCase().replace(/\s+/g,"-")===e.params.name);t?n.json(t):n.status(404).json({error:"Diagram not found"});}),this.app.post("/api/regenerate",async(e,n)=>{try{await this.regenerate(),n.json({success:!0});}catch(t){n.status(500).json({error:t.message});}});}setupSocketIO(){this.io.on("connection",a=>{a.on("disconnect",()=>{});});}async renderPage(a){let s=a.replace(/\.md$/,""),e=d.join(this.config.outputDir,`${s}.md`),n="";try{let t=await u.readFile(e,"utf-8"),o=await marked.parse(t);o=o.replace(/<pre><code class="language-mermaid">([\s\S]*?)<\/code><\/pre>/g,'<div class="mermaid">$1</div>'),o=o.replace(/<table>/g,'<div class="table-wrapper"><table>'),o=o.replace(/<\/table>/g,"</table></div>"),n=o;}catch(t){let o=t;if(o.code==="ENOENT"){let r=this.currentReport?.repositories.map(i=>i.name)||[];n=`
1
+ import {a as a$2}from'./chunk-NQMJ3QRX.js';import {a as a$3}from'./chunk-VV3A3UE3.js';import {B,A,z,y}from'./chunk-QDVE7MT3.js';import {a,b}from'./chunk-2XZSFAJF.js';import {a as a$1}from'./chunk-WZAAA7DS.js';import {k}from'./chunk-H7VVRHQZ.js';import {simpleGit}from'simple-git';import*as T from'fs/promises';import*as R from'path';import {parseSync}from'@swc/core';import me from'express';import {Server}from'socket.io';import*as fe from'http';import {marked}from'marked';import*as ce from'net';var U=class{config;mermaidGenerator;markdownGenerator;constructor(t){this.config=t,this.mermaidGenerator=new a,this.markdownGenerator=new b;}async generate(){let t=[];for(let w of this.config.repositories)try{let g=await this.analyzeRepository(w);t.push(g);}catch(g){console.error(`\u274C ${w.name}: ${g.message}`);}let r=this.analyzeCrossRepo(t),e=t.map(w=>w.analysis),n=this.extractCrossRepoLinks(e),s=this.mermaidGenerator.generateAll(e,n),i={generatedAt:new Date().toISOString(),repositories:t,crossRepoAnalysis:r,diagrams:s};return await this.writeDocumentation(i),i}async analyzeRepository(t){let{version:r,commitHash:e}=await this.getRepoInfo(t),n=t.analyzers.map(y=>this.createAnalyzer(y,t)).filter(y=>y!==null),s=Date.now(),i=await Promise.all(n.map(y=>y.analyze())),w=((Date.now()-s)/1e3).toFixed(1);console.log(` Analyzed ${t.displayName} in ${w}s`);let g=this.mergeAnalysisResults(i,t.name,r,e);await this.enrichPagesWithHookGraphQL(g,t.path);let k={totalPages:g.pages.length,totalComponents:g.components.length,totalGraphQLOperations:g.graphqlOperations.length,totalDataFlows:g.dataFlows.length,authRequiredPages:g.pages.filter(y=>y.authentication.required).length,publicPages:g.pages.filter(y=>!y.authentication.required).length};return {name:t.name,displayName:t.displayName,version:r,commitHash:e,analysis:g,summary:k}}async getRepoInfo(t){try{let n=(await simpleGit(t.path).log({n:1})).latest?.hash||"unknown",s="unknown";try{let i=R.join(t.path,"package.json");s=JSON.parse(await T.readFile(i,"utf-8")).version||"unknown";}catch{}return {version:s,commitHash:n}}catch{return {version:"unknown",commitHash:"unknown"}}}createAnalyzer(t,r){switch(t){case "pages":if(r.type==="nextjs"||r.type==="rails"||r.type==="generic")return new y(r);break;case "graphql":return new z(r);case "dataflow":case "components":return new A(r);case "rest-api":case "api":return new B(r)}return null}mergeAnalysisResults(t,r,e,n){let s={repository:r,timestamp:new Date().toISOString(),version:e,commitHash:n,pages:[],graphqlOperations:[],apiCalls:[],components:[],dataFlows:[],apiEndpoints:[],models:[],crossRepoLinks:[]};for(let i of t)i.pages&&s.pages.push(...i.pages),i.graphqlOperations&&s.graphqlOperations.push(...i.graphqlOperations),i.apiCalls&&s.apiCalls.push(...i.apiCalls),i.components&&s.components.push(...i.components),i.dataFlows&&s.dataFlows.push(...i.dataFlows),i.apiEndpoints&&s.apiEndpoints.push(...i.apiEndpoints),i.models&&s.models.push(...i.models),i.crossRepoLinks&&s.crossRepoLinks.push(...i.crossRepoLinks);return s}analyzeCrossRepo(t){let r=[],e=[],n=[],s=[],i=new Map;for(let k of t)for(let y of k.analysis.graphqlOperations){let $=i.get(y.name)||[];$.push(k.name),i.set(y.name,$);}for(let[k,y]of i)y.length>1&&r.push(k);let w=t.filter(k=>k.analysis.pages.length>0),g=t.filter(k=>k.analysis.apiEndpoints.length>0);for(let k of w)for(let y of g)for(let $ of y.analysis.apiEndpoints)e.push({frontend:k.name,backend:y.name,endpoint:$.path,operations:k.analysis.graphqlOperations.filter(A=>A.usedIn.length>0).map(A=>A.name)});return {sharedTypes:r,apiConnections:e,navigationFlows:n,dataFlowAcrossRepos:s}}extractCrossRepoLinks(t){let r=[],e=new Map;for(let n of t)for(let s of n.graphqlOperations){let i=e.get(s.name)||[];i.push(n),e.set(s.name,i);}for(let[n,s]of e)s.length>1&&r.push({sourceRepo:s[0].repository,sourcePath:`graphql/${n}`,targetRepo:s[1].repository,targetPath:`graphql/${n}`,linkType:"graphql-operation",description:`Shared GraphQL operation: ${n}`});return r}async enrichPagesWithHookGraphQL(t,r){let e=t.graphqlOperations.filter(a=>a.type==="query"||a.type==="mutation"||a.type==="subscription"),n=/\.(ts|tsx|js|jsx)$/,s=a=>R.normalize(a).replace(/\\/g,"/"),i=(this.config.analysis?.include||["**/*.ts","**/*.tsx"]).map(String),w=(this.config.analysis?.exclude||[]).map(String),g=(await import('fast-glob')).default,k=await g(i,{cwd:r,ignore:["**/node_modules/**","**/.next/**","**/dist/**","**/build/**","**/coverage/**",...w],onlyFiles:true,unique:true,dot:false}),y=new Set(k.map(s)),$=new Map;for(let a of y){let o=a.replace(n,"");$.has(o)||$.set(o,a);}let A=new Set(["src/"]);for(let a of y){let o=a.indexOf("/src/");o!==-1&&A.add(a.slice(0,o+5));}let N=a=>{let o=s(a).replace(n,""),c=$.get(o);if(c)return c;let l=$.get(o+"/index");return l||null},he=async()=>{let a=["tsconfig.json","jsconfig.json"];for(let o of a)try{let c=await T.readFile(R.join(r,o),"utf-8"),p=JSON.parse(c)?.compilerOptions||{},f=typeof p.baseUrl=="string"?p.baseUrl:void 0,q=typeof p.paths=="object"&&p.paths?p.paths:void 0;return {baseUrl:f,paths:q}}catch{}return {}},{baseUrl:O,paths:X}=await he(),ge=a=>{if(!X)return [];let o=[];for(let[c,l]of Object.entries(X)){if(!c.includes("*")){a===c&&o.push(...l);continue}let[p,f]=c.split("*");if(!a.startsWith(p)||!a.endsWith(f))continue;let q=a.slice(p.length,a.length-f.length);for(let d of l)d.includes("*")?o.push(d.replace("*",q)):o.push(d);}return o},B=(a,o)=>{if(!o)return null;if(o.startsWith(".")){let l=R.dirname(a);return N(R.join(l,o))}if(o.startsWith("@/")){let l=o.replace("@/","");if(O){let p=N(R.join(O,l));if(p)return p}for(let p of A){let f=N(p+l);if(f)return f}return null}let c=ge(o);if(c.length>0)for(let l of c){let p=N(O?R.join(O,l):l);if(p)return p}if(O){let l=N(R.join(O,o));if(l)return l}return null},j=new Map,W=new Map,Z=async a=>{let o=s(a),c=W.get(o);if(c!==void 0)return c;try{let l=R.join(r,o),p=await T.readFile(l,"utf-8");return W.set(o,p),p}catch{return W.set(o,""),null}},ye=async a=>{let o=s(a),c=j.get(o);if(c)return c.map(m=>({spec:m,names:null}));let l=await Z(o);if(!l)return j.set(o,[]),[];let p;try{let m=o.endsWith(".ts")||o.endsWith(".tsx"),h=o.endsWith(".tsx")||o.endsWith(".jsx");p=parseSync(l,{syntax:m?"typescript":"ecmascript",tsx:h,jsx:h,comments:!1});}catch{return j.set(o,[]),[]}let f=new Set,q=[],d=(m,h)=>{typeof m!="string"||m.length===0||(f.add(m),q.push({spec:m,names:h}));},b=m=>{if(!m||typeof m!="object")return;let h=m,v=h;if(v.type==="ImportDeclaration"){if(!v.typeOnly){let x=v.source?.value,u=[],E=v.specifiers||[];for(let S of E){let C=S,I=C.type;if(I==="ImportDefaultSpecifier"||I==="ImportNamespaceSpecifier"){u=null;break}if(I==="ImportSpecifier"){let G=C.imported?.value,P=C.local?.value,z=G||P;z&&u.push(z);}}Array.isArray(u)&&u.length===0&&(u=null),d(x,u);}}else if(v.type==="ExportAllDeclaration")d(v.source?.value,null);else if(v.type==="ExportNamedDeclaration"){let x=v.source?.value,u=v.specifiers||[],E=[];for(let S of u){let C=S;if(C.type==="ExportSpecifier"){let G=C.exported?.value,P=C.orig?.value,z=G||P;z&&E.push(z);}}d(x,E.length>0?E:null);}else if(v.type==="CallExpression"){let x=v.callee||null;if(x?.type==="Identifier"&&x.value==="require"){let u=v.arguments?.[0]?.expression;u?.type==="StringLiteral"&&d(u.value,null);}if(x?.type==="Import"){let u=v.arguments?.[0]?.expression;u?.type==="StringLiteral"&&d(u.value,null);}}for(let x of Object.keys(h)){let u=h[x];if(Array.isArray(u))for(let E of u)b(E);else u&&typeof u=="object"&&b(u);}};b(p);let D=Array.from(f);return j.set(o,D),q.filter(m=>typeof m.spec=="string"&&m.spec.length>0)},Q=new Map,_=async a=>{let o=s(a),c=Q.get(o);if(c)return c;let l=await Z(o);if(!l){let m={named:new Map,stars:[],isBarrel:false};return Q.set(o,m),m}let p;try{let m=o.endsWith(".ts")||o.endsWith(".tsx"),h=o.endsWith(".tsx")||o.endsWith(".jsx");p=parseSync(l,{syntax:m?"typescript":"ecmascript",tsx:h,jsx:h,comments:!1});}catch{let m={named:new Map,stars:[],isBarrel:false};return Q.set(o,m),m}let f=new Map,q=[],d=true,b=p?.body;if(Array.isArray(b))for(let m of b){let h=m,v=h.type;if(v&&v!=="ImportDeclaration"){if(v==="ExportAllDeclaration"){let x=h.source?.value;typeof x=="string"&&q.push(x);continue}if(v==="ExportNamedDeclaration"){let x=h.source?.value,u=h.specifiers||[];if(typeof x=="string"&&Array.isArray(u))for(let E of u){let S=E;if(S.type!=="ExportSpecifier")continue;let I=S.exported?.value,G=S.orig?.value,P=I||G;P&&f.set(P,x);}continue}d=false;}}else d=false;let D={named:f,stars:q,isBarrel:d};return Q.set(o,D),D},V=async(a,o,c)=>{let l=s(a);if(c.has(l))return null;c.add(l);let p=await _(l),f=p.named.get(o);if(f)return B(l,f);for(let q of p.stars){let d=B(l,q);if(!d)continue;let b=await V(d,o,c);if(b)return b}return null},Y=new Map;for(let a of e){let o=new Set;a.filePath&&o.add(a.filePath);for(let c of a.usedIn||[])o.add(c);for(let c of o){let l=Y.get(c)||[];l.push({opName:a.name,opType:a.type}),Y.set(c,l);}}let ve=a=>{if(!a)return null;let o=[`src/pages/${a}`,`pages/${a}`,`src/app/${a}`,`app/${a}`,`frontend/src/pages/${a}`,`frontend/src/app/${a}`,`app/javascript/pages/${a}`,`app/javascript/app/${a}`];for(let p of o){if(y.has(p))return p;let f=N(p);if(f)return f}let c=[],l=[`/pages/${a}`,`/app/${a}`,`/${a}`];for(let p of y)for(let f of l)if(p.endsWith(f)&&!(f.startsWith("/pages/")&&!p.includes("/pages/"))&&!(f.startsWith("/app/")&&!p.includes("/app/"))){c.push(p);break}return c.length===0?null:(c.sort((p,f)=>p.length-f.length),c[0])},J=new Map,H=new Map;for(let a of t.pages){let o=ve(a.filePath);if(!o)continue;let c=new Map,l=new Set,p=[{f:o,depth:0}],f=30,q=2e4;for(;p.length>0;){let d=p.shift();if(!d)break;if(l.has(d.f))continue;if(l.add(d.f),l.size>=q)break;let b=Y.get(d.f);if(b)for(let m of b){let h=c.get(m.opName);(!h||d.depth<h.distance)&&c.set(m.opName,{opName:m.opName,opType:m.opType,sourceFile:d.f,distance:d.depth});}if(d.depth>=f)continue;let D=await ye(d.f);for(let m of D){let h=B(d.f,m.spec);if(h){if(l.has(h)||p.push({f:h,depth:d.depth+1}),Array.isArray(m.names)&&m.names.length>0){if((await _(h)).isBarrel)for(let x of m.names){let u=await V(h,x,new Set);u&&!l.has(u)&&p.push({f:u,depth:d.depth+2});}}else if(m.names===null){let v=await _(h);if(v.isBarrel){for(let x of v.stars){let u=B(h,x);u&&!l.has(u)&&p.push({f:u,depth:d.depth+2});}for(let x of v.named.values()){let u=B(h,x);u&&!l.has(u)&&p.push({f:u,depth:d.depth+2});}}}}}}J.set(a.path,{page:a,entryFile:o,bestByOp:c});for(let d of l)H.set(d,(H.get(d)||0)+1);}let we=J.size,xe=Array.from(H.values()).sort((a,o)=>a-o),be=((a,o)=>{if(a.length===0)return 0;let c=Math.min(a.length-1,Math.max(0,Math.floor(a.length*o)));return a[c]})(xe,.9),ke=Math.max(10,be),qe=Math.max(2,Math.floor(we*.05));for(let{page:a,bestByOp:o}of J.values()){let c=new Set((a.dataFetching||[]).map(l=>l.operationName?.replace(/^[→\->\s]+/,"")||""));for(let{opName:l,opType:p,sourceFile:f,distance:q}of o.values()){if(c.has(l))continue;c.add(l);let d=H.get(f)||0,b;q===0?b=void 0:d>=ke?b=`common:${f}`:q<=2||d<=qe?b=`close:${f}`:b=`indirect:${f}`,a.dataFetching.push({type:p==="mutation"?"useMutation":p==="subscription"?"useSubscription":"useQuery",operationName:l,source:b});}}}async writeDocumentation(t){let r=this.config.outputDir;await T.mkdir(r,{recursive:true});let e=this.markdownGenerator.generateDocumentation(t);for(let[s,i]of e){let w=R.join(r,s),g=R.dirname(w);await T.mkdir(g,{recursive:true}),await T.writeFile(w,i,"utf-8");}let n=R.join(r,"report.json");await T.writeFile(n,JSON.stringify(t,null,2),"utf-8");}};function Me(L){return new Promise(t=>{let r=ce.createServer();r.once("error",e=>{e.code,t(false);}),r.once("listening",()=>{r.close(),t(true);}),r.listen(L);})}async function de(L,t=10){for(let r=0;r<t;r++){let e=L+r;if(await Me(e))return e}throw new Error(`No available port found between ${L} and ${L+t-1}`)}var ue=class{config;port;app;server;io;engine;currentReport=null;envResult=null;railsAnalysis=null;constructor(t,r=3030){this.config=t,this.port=r,this.app=me(),this.server=fe.createServer(this.app),this.io=new Server(this.server),this.engine=new U(t),this.setupRoutes(),this.setupSocketIO();}setupRoutes(){this.app.use("/assets",me.static(R.join(this.config.outputDir,"assets"))),["common.css","page-map.css","docs.css","rails-map.css"].forEach(e=>{this.app.get(`/${e}`,async(n,s)=>{let i=[R.join(R.dirname(new URL(import.meta.url).pathname),"generators","assets",e),R.join(R.dirname(new URL(import.meta.url).pathname),"..","generators","assets",e),R.join(process.cwd(),"dist","generators","assets",e),R.join(process.cwd(),"src","generators","assets",e)];for(let w of i)try{let g=await T.readFile(w,"utf-8");s.type("text/css").send(g);return}catch{}s.status(404).send("CSS not found");});}),["favicon.ico","favicon.svg","favicon-96x96.png","apple-touch-icon.png","site.webmanifest","web-app-manifest-192x192.png","web-app-manifest-512x512.png"].forEach(e=>{(e==="favicon.ico"?[`/${e}`,`/favicon/${e}`]:[`/favicon/${e}`]).forEach(s=>{this.app.get(s,async(i,w)=>{let g=[R.join(R.dirname(new URL(import.meta.url).pathname),"generators","assets","favicon",e),R.join(R.dirname(new URL(import.meta.url).pathname),"..","generators","assets","favicon",e),R.join(process.cwd(),"dist","generators","assets","favicon",e),R.join(process.cwd(),"src","generators","assets","favicon",e)];for(let k of g)try{let y=await T.readFile(k),$=e.split(".").pop(),A={ico:"image/x-icon",svg:"image/svg+xml",png:"image/png",webmanifest:"application/manifest+json"};w.type(A[$||""]||"application/octet-stream").send(y);return}catch{}w.status(404).send("File not found");});});}),this.app.get("/",(e,n)=>{n.redirect("/page-map");}),this.app.get("/page-map",(e,n)=>{if(!this.currentReport){n.status(503).send("Documentation not ready yet");return}let s=new a$1;n.send(s.generatePageMapHtml(this.currentReport,{envResult:this.envResult,railsAnalysis:this.railsAnalysis}));}),this.app.get("/rails-map",(e,n)=>{if(!this.railsAnalysis){n.status(404).send("No Rails environment detected");return}let s=new a$2;n.send(s.generateFromResult(this.railsAnalysis));}),this.app.get("/docs",async(e,n)=>{n.send(await this.renderPage("index"));}),this.app.get("/docs/*path",async(e,n)=>{let s=e.params.path,i=Array.isArray(s)?s.join("/"):s||"index";n.send(await this.renderPage(i));}),this.app.get("/api/report",(e,n)=>{n.json(this.currentReport);}),this.app.get("/api/env",(e,n)=>{n.json(this.envResult);}),this.app.get("/api/rails",(e,n)=>{this.railsAnalysis?n.json(this.railsAnalysis):n.status(404).json({error:"No Rails analysis available"});}),this.app.get("/api/diagram/:name",(e,n)=>{let s=this.currentReport?.diagrams.find(i=>i.title.toLowerCase().replace(/\s+/g,"-")===e.params.name);s?n.json(s):n.status(404).json({error:"Diagram not found"});}),this.app.post("/api/regenerate",async(e,n)=>{try{await this.regenerate(),n.json({success:!0});}catch(s){n.status(500).json({error:s.message});}});}setupSocketIO(){this.io.on("connection",t=>{t.on("disconnect",()=>{});});}async renderPage(t){let r=t.replace(/\.md$/,""),e=R.join(this.config.outputDir,`${r}.md`),n="";try{let s=await T.readFile(e,"utf-8"),i=await marked.parse(s);i=i.replace(/<pre><code class="language-mermaid">([\s\S]*?)<\/code><\/pre>/g,'<div class="mermaid">$1</div>'),i=i.replace(/<table>/g,'<div class="table-wrapper"><table>'),i=i.replace(/<\/table>/g,"</table></div>"),n=i;}catch(s){let i=s;if(i.code==="ENOENT"){let w=this.currentReport?.repositories.map(g=>g.name)||[];n=`
2
2
  <h1>Page not found</h1>
3
- <p>The requested path <code>${s}</code> does not exist.</p>
4
- ${r.length>0?`
3
+ <p>The requested path <code>${r}</code> does not exist.</p>
4
+ ${w.length>0?`
5
5
  <p>Available repositories:</p>
6
- <ul>${r.map(i=>`<li><a href="/docs/repos/${i}">${i}</a></li>`).join("")}</ul>
6
+ <ul>${w.map(g=>`<li><a href="/docs/repos/${g}">${g}</a></li>`).join("")}</ul>
7
7
  `:""}
8
8
  <p><a href="/">\u2190 Back to home</a></p>
9
- `;}else console.error(`\u26A0\uFE0F Error reading ${e}: ${o.message}`),n=`<h1>Error</h1><p>Failed to load page: ${o.message}</p>`;}return this.getHtmlTemplate(n)}getGraphQLData(){if(!this.currentReport)return "[]";let a=[];for(let s of this.currentReport.repositories)for(let e of s.analysis?.graphqlOperations||[])a.push({name:e.name,type:e.type,returnType:e.returnType,variables:e.variables,fields:e.fields,usedIn:e.usedIn});return JSON.stringify(a)}getApiCallsData(){if(!this.currentReport)return "[]";let a=[];for(let s of this.currentReport.repositories)for(let e of s.analysis?.apiCalls||[])a.push({id:e.id,method:e.method,url:e.url,callType:e.callType,filePath:e.filePath,line:e.line,containingFunction:e.containingFunction,requiresAuth:e.requiresAuth});return JSON.stringify(a)}getHtmlTemplate(a){let s=this.getGraphQLData(),e=this.getApiCallsData();return `<!DOCTYPE html>
9
+ `;}else console.error(`\u26A0\uFE0F Error reading ${e}: ${i.message}`),n=`<h1>Error</h1><p>Failed to load page: ${i.message}</p>`;}return this.getHtmlTemplate(n)}getGraphQLData(){if(!this.currentReport)return "[]";let t=[];for(let r of this.currentReport.repositories)for(let e of r.analysis?.graphqlOperations||[])t.push({name:e.name,type:e.type,returnType:e.returnType,variables:e.variables,fields:e.fields,usedIn:e.usedIn});return JSON.stringify(t)}getApiCallsData(){if(!this.currentReport)return "[]";let t=[];for(let r of this.currentReport.repositories)for(let e of r.analysis?.apiCalls||[])t.push({id:e.id,method:e.method,url:e.url,callType:e.callType,filePath:e.filePath,line:e.line,containingFunction:e.containingFunction,requiresAuth:e.requiresAuth});return JSON.stringify(t)}getHtmlTemplate(t){let r=this.getGraphQLData(),e=this.getApiCallsData();return `<!DOCTYPE html>
10
10
  <html lang="en">
11
11
  <head>
12
12
  <meta charset="UTF-8">
@@ -20,7 +20,7 @@ import {a as a$2}from'./chunk-P7MX3M5U.js';import {a as a$3}from'./chunk-VV3A3UE
20
20
  <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
21
21
  <script src="/socket.io/socket.io.js"></script>
22
22
  <script>
23
- window.graphqlOps = ${s};
23
+ window.graphqlOps = ${r};
24
24
  window.apiCalls = ${e};
25
25
  // Create multiple lookup maps for different naming conventions
26
26
  window.gqlMap = new Map();
@@ -124,7 +124,7 @@ import {a as a$2}from'./chunk-P7MX3M5U.js';import {a as a$3}from'./chunk-VV3A3UE
124
124
  </aside>
125
125
  <div class="content-area">
126
126
  <div class="content">
127
- ${a}
127
+ ${t}
128
128
  </div>
129
129
  </div>
130
130
  </div>
@@ -158,6 +158,13 @@ import {a as a$2}from'./chunk-P7MX3M5U.js';import {a as a$3}from'./chunk-VV3A3UE
158
158
 
159
159
  // Render all mermaid diagrams on page load
160
160
  document.addEventListener('DOMContentLoaded', async () => {
161
+ // Snapshot raw dataflow mermaid source BEFORE first render (needed for filtering rerenders)
162
+ document.querySelectorAll('.mermaid[data-mermaid-scope="dataflow"]').forEach((el) => {
163
+ if (!el.dataset.mermaidRaw) {
164
+ el.dataset.mermaidRaw = el.textContent || '';
165
+ }
166
+ });
167
+
161
168
  // Wrap mermaid divs with container and controls
162
169
  document.querySelectorAll('.mermaid').forEach((el, idx) => {
163
170
  const container = document.createElement('div');
@@ -183,21 +190,146 @@ import {a as a$2}from'./chunk-P7MX3M5U.js';import {a as a$3}from'./chunk-VV3A3UE
183
190
  });
184
191
 
185
192
  try {
186
- await mermaid.run({ querySelector: '.mermaid' });
187
-
188
- // Add click handlers to nodes
189
- document.querySelectorAll('.mermaid .node').forEach(node => {
190
- node.addEventListener('click', (e) => {
191
- e.stopPropagation();
192
- const text = node.querySelector('span, text, .nodeLabel')?.textContent || '';
193
- showNodeDetail(text, node);
194
- });
195
- });
193
+ await renderMermaidElements(document.querySelectorAll('.mermaid'));
194
+
195
+ attachMermaidNodeHandlers();
196
+
197
+ // Init toggle filters AFTER mermaid is ready (prevents double-run issues)
198
+ initOpsFilters();
196
199
  } catch (e) {
197
200
  console.error('Mermaid rendering error:', e);
198
201
  }
199
202
  });
200
203
 
204
+ function initOpsFilters() {
205
+ document.querySelectorAll('.ops-filters').forEach((container) => {
206
+ const scope = container.getAttribute('data-filter-scope') || 'default';
207
+ const inputs = Array.from(
208
+ container.querySelectorAll('input[type="checkbox"][data-filter]')
209
+ );
210
+ if (inputs.length === 0) return;
211
+
212
+ const apply = async () => {
213
+ const enabled = new Set(
214
+ inputs
215
+ .filter((i) => i.checked)
216
+ .map((i) => i.getAttribute('data-filter'))
217
+ .filter(Boolean)
218
+ );
219
+ document
220
+ .querySelectorAll('[data-ops-scope="' + scope + '"][data-ops-group]')
221
+ .forEach((el) => {
222
+ const key = el.getAttribute('data-ops-group');
223
+ // If key is missing, do nothing
224
+ if (!key) return;
225
+ el.style.display = enabled.has(key) ? '' : 'none';
226
+ });
227
+
228
+ // Update UI state for pill toggles
229
+ inputs.forEach((i) => {
230
+ const wrap = i.closest('.ops-toggle');
231
+ if (wrap) wrap.classList.toggle('is-on', i.checked);
232
+ });
233
+
234
+ // Apply to dataflow mermaid charts by re-rendering with filtered groups
235
+ if (scope === 'dataflow') {
236
+ await applyDataflowMermaidFilter(enabled);
237
+ }
238
+ };
239
+
240
+ inputs.forEach((i) => i.addEventListener('change', () => void apply()));
241
+ void apply();
242
+ });
243
+ }
244
+
245
+ async function applyDataflowMermaidFilter(enabledGroups) {
246
+ const els = Array.from(document.querySelectorAll('.mermaid[data-mermaid-scope="dataflow"]'));
247
+ if (els.length === 0) return;
248
+
249
+ // Store original source before the first render (or first filter)
250
+ els.forEach((el) => {
251
+ if (!el.dataset.mermaidRaw) {
252
+ el.dataset.mermaidRaw = el.textContent || '';
253
+ }
254
+ });
255
+
256
+ const buildFiltered = (raw) => {
257
+ // NOTE: This code is embedded inside an HTML template literal.
258
+ // Avoid using quotes/backslashes in comments here (they can be mangled by the outer template).
259
+ const lines = raw.split('\\n');
260
+ const out = [];
261
+ let current = null; // 'direct'|'close'|'indirect'|'common'|null
262
+
263
+ for (const line of lines) {
264
+ const start = line.match(/^%%DFG_GROUP:(direct|close|indirect|common):start%%$/);
265
+ if (start) {
266
+ current = start[1];
267
+ continue;
268
+ }
269
+ const end = line.match(/^%%DFG_GROUP:(direct|close|indirect|common):end%%$/);
270
+ if (end) {
271
+ current = null;
272
+ continue;
273
+ }
274
+
275
+ if (!current) {
276
+ out.push(line);
277
+ continue;
278
+ }
279
+ if (enabledGroups.has(current)) out.push(line);
280
+ }
281
+
282
+ return out.join('\\n').trim();
283
+ };
284
+
285
+ // Update the mermaid source text and re-run mermaid renderer
286
+ for (const el of els) {
287
+ const raw = el.dataset.mermaidRaw || '';
288
+ const filtered = buildFiltered(raw);
289
+ el.removeAttribute('data-processed');
290
+ el.textContent = filtered;
291
+ }
292
+
293
+ try {
294
+ await renderMermaidElements(
295
+ document.querySelectorAll('.mermaid[data-mermaid-scope="dataflow"]')
296
+ );
297
+ attachMermaidNodeHandlers();
298
+ } catch (e) {
299
+ console.error('Mermaid rendering error (dataflow filter):', e);
300
+ }
301
+ }
302
+
303
+ async function renderMermaidElements(nodeList) {
304
+ const elements = Array.from(nodeList || []);
305
+ for (let idx = 0; idx < elements.length; idx++) {
306
+ const el = elements[idx];
307
+ const marker = 'mermaid-single-run';
308
+ const unique = marker + '-' + idx;
309
+ el.classList.add(marker, unique);
310
+ try {
311
+ await mermaid.run({ querySelector: '.' + unique });
312
+ } catch (e) {
313
+ const page = el.getAttribute('data-mermaid-page') || '';
314
+ const scope = el.getAttribute('data-mermaid-scope') || '';
315
+ const preview = (el.textContent || '').slice(0, 260);
316
+ console.error('Mermaid rendering error (element)', { idx, scope, page, preview }, e);
317
+ } finally {
318
+ el.classList.remove(marker, unique);
319
+ }
320
+ }
321
+ }
322
+
323
+ function attachMermaidNodeHandlers() {
324
+ document.querySelectorAll('.mermaid .node').forEach(node => {
325
+ node.addEventListener('click', (e) => {
326
+ e.stopPropagation();
327
+ const text = node.querySelector('span, text, .nodeLabel')?.textContent || '';
328
+ showNodeDetail(text, node);
329
+ });
330
+ });
331
+ }
332
+
201
333
  function setupDragHandlers(idx) {
202
334
  const wrapper = document.getElementById(\`wrapper-\${idx}\`);
203
335
  const inner = document.getElementById(\`inner-\${idx}\`);
@@ -953,11 +1085,11 @@ import {a as a$2}from'./chunk-P7MX3M5U.js';import {a as a$3}from'./chunk-VV3A3UE
953
1085
  }
954
1086
  </script>
955
1087
  </body>
956
- </html>`}async start(a=true){let s=this.config.repositories[0]?.path||process.cwd();this.envResult=await a$3(s),this.currentReport=await this.engine.generate(),console.log();for(let e of this.currentReport.repositories){let n=e.summary;console.log(` \u2705 ${e.displayName}`),console.log(` ${n.totalPages} pages \xB7 ${n.totalComponents} components \xB7 ${n.totalGraphQLOperations} GraphQL \xB7 ${n.totalDataFlows} data flows`);}if(this.envResult.hasRails){console.log(`
957
- Rails...`);try{this.railsAnalysis=await k(s);let e=this.railsAnalysis.summary;console.log(` ${e.totalRoutes} routes \xB7 ${e.totalControllers} controllers \xB7 ${e.totalModels} models \xB7 ${e.totalGrpcServices} gRPC`);}catch(e){console.error(" \u26A0\uFE0F Rails analysis failed:",e.message);}}try{let e=await L(this.port);e!==this.port&&console.log(`
1088
+ </html>`}async start(t=true){let r=this.config.repositories[0]?.path||process.cwd();this.envResult=await a$3(r),this.currentReport=await this.engine.generate(),console.log();for(let e of this.currentReport.repositories){let n=e.summary;console.log(` \u2705 ${e.displayName}`),console.log(` ${n.totalPages} pages \xB7 ${n.totalComponents} components \xB7 ${n.totalGraphQLOperations} GraphQL \xB7 ${n.totalDataFlows} data flows`);}if(this.envResult.hasRails){console.log(`
1089
+ Rails...`);try{this.railsAnalysis=await k(r);let e=this.railsAnalysis.summary;console.log(` ${e.totalRoutes} routes \xB7 ${e.totalControllers} controllers \xB7 ${e.totalModels} models \xB7 ${e.totalGrpcServices} gRPC`);}catch(e){console.error(" \u26A0\uFE0F Rails analysis failed:",e.message);}}try{let e=await de(this.port);e!==this.port&&console.log(`
958
1090
  \u26A0\uFE0F Port ${this.port} is in use, using port ${e} instead`),this.port=e;}catch(e){console.error(`
959
1091
  \u274C Failed to find available port: ${e.message}`),process.exit(1);}if(this.server.listen(this.port,()=>{console.log(`
960
1092
  \u{1F310} Documentation server running at http://localhost:${this.port}`),this.envResult?.hasRails&&this.envResult?.hasNextjs&&console.log(" \u{1F4CA} Multiple environments detected - use tabs to switch views"),console.log(` Press Ctrl+C to stop
961
- `);}),a){let e=(await import('open')).default;await e(`http://localhost:${this.port}`);}this.config.watch.enabled&&this.watchForChanges();}async regenerate(){if(console.log(`
962
- \u{1F504} Regenerating...`),this.currentReport=await this.engine.generate(),this.envResult?.hasRails){let a=this.config.repositories[0]?.path||process.cwd();try{this.railsAnalysis=await k(a);}catch(s){console.error("\u26A0\uFE0F Rails re-analysis failed:",s.message);}}for(let a of this.currentReport.repositories)console.log(` ${a.displayName}: ${a.summary.totalPages} pages \xB7 ${a.summary.totalComponents} components \xB7 ${a.summary.totalGraphQLOperations} GraphQL`);this.io.emit("reload"),console.log("\u2705 Done");}async watchForChanges(){let a=this.config.repositories.map(e=>e.path),s=null;for(let e of a)try{let n=u.watch(e,{recursive:!0});(async()=>{for await(let t of n)t.filename&&(t.filename.endsWith(".ts")||t.filename.endsWith(".tsx"))&&(s&&clearTimeout(s),s=setTimeout(async()=>{await this.regenerate();},this.config.watch.debounce));})();}catch(n){console.warn(`Warning: Could not watch directory ${e}:`,n.message);}}stop(){this.server.close(),console.log(`
963
- \u{1F44B} Server stopped`);}};export{v as a,P as b};
1093
+ `);}),t){let e=(await import('open')).default;await e(`http://localhost:${this.port}`);}this.config.watch.enabled&&this.watchForChanges();}async regenerate(){if(console.log(`
1094
+ \u{1F504} Regenerating...`),this.currentReport=await this.engine.generate(),this.envResult?.hasRails){let t=this.config.repositories[0]?.path||process.cwd();try{this.railsAnalysis=await k(t);}catch(r){console.error("\u26A0\uFE0F Rails re-analysis failed:",r.message);}}for(let t of this.currentReport.repositories)console.log(` ${t.displayName}: ${t.summary.totalPages} pages \xB7 ${t.summary.totalComponents} components \xB7 ${t.summary.totalGraphQLOperations} GraphQL`);this.io.emit("reload"),console.log("\u2705 Done");}async watchForChanges(){let t=this.config.repositories.map(e=>e.path),r=null;for(let e of t)try{let n=T.watch(e,{recursive:!0});(async()=>{for await(let s of n)s.filename&&(s.filename.endsWith(".ts")||s.filename.endsWith(".tsx"))&&(r&&clearTimeout(r),r=setTimeout(async()=>{await this.regenerate();},this.config.watch.debounce));})();}catch(n){console.warn(`Warning: Could not watch directory ${e}:`,n.message);}}stop(){this.server.close(),console.log(`
1095
+ \u{1F44B} Server stopped`);}};export{U as a,ue as b};