@wtdlee/repomap 0.7.0 → 0.9.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 CHANGED
@@ -101,13 +101,16 @@ npx @wtdlee/repomap serve
101
101
  repomap serve [options]
102
102
  -p, --port <number> Server port (default: 3030)
103
103
  -c, --config <path> Path to config file
104
+ -o, --output <path> Output directory (default: .repomap)
104
105
  --path <path> Path to repository to analyze
106
+ --temp Use OS temp directory (no files in repository)
105
107
  --no-open Don't open browser automatically
106
108
 
107
109
  # generate command options
108
110
  repomap generate [options]
109
111
  -c, --config <path> Path to config file
110
- -o, --output <path> Output directory
112
+ -o, --output <path> Output directory (default: .repomap)
113
+ --temp Use OS temp directory (no files in repository)
111
114
  --repo <name> Analyze specific repository only
112
115
  --watch Watch for changes and regenerate
113
116
  --static Generate standalone HTML files (for GitHub Pages)
@@ -120,6 +123,19 @@ repomap rails [options]
120
123
  -o, --output <path> Output HTML file path
121
124
  ```
122
125
 
126
+ ### Output Directory Options
127
+
128
+ ```bash
129
+ # Default: creates .repomap in current directory
130
+ repomap serve
131
+
132
+ # Custom output directory
133
+ repomap serve -o ./docs
134
+
135
+ # Temporary directory (auto-cleaned on exit)
136
+ repomap serve --temp
137
+ ```
138
+
123
139
  ## CI/CD Integration
124
140
 
125
141
  ### Deploy to GitHub Pages
@@ -1,4 +1,4 @@
1
- import {a as a$2}from'./chunk-OQAXO3X2.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-GCIRJGW3.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-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=`
2
2
  <h1>Page not found</h1>
3
3
  <p>The requested path <code>${s}</code> does not exist.</p>
4
4
  ${r.length>0?`
@@ -1,4 +1,4 @@
1
- import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';var o=class{constructor(t){this.rootPath=t;}result=null;async generate(t={}){if(!this.rootPath)throw new Error("Root path required for analysis");let{title:e="Rails Application Map"}=t;this.result=await k(this.rootPath);let s=this.generateHTML(e);return t.outputPath&&(d.writeFileSync(t.outputPath,s),console.log(`
1
+ import {k}from'./chunk-H7VVRHQZ.js';import*as r from'fs';import*as c from'path';var n=class{constructor(t){this.rootPath=t;}result=null;async generate(t={}){if(!this.rootPath)throw new Error("Root path required for analysis");let{title:e="Rails Application Map"}=t;this.result=await k(this.rootPath);let s=this.generateHTML(e);return t.outputPath&&(r.writeFileSync(t.outputPath,s),console.log(`
2
2
  \u{1F4C4} Generated: ${t.outputPath}`)),s}generateFromResult(t,e="Rails Application Map"){return this.result=t,this.generateHTML(e)}generateHTML(t){if(!this.result)throw new Error("Analysis not run");let{routes:e,controllers:s,models:a,grpc:l,summary:i}=this.result;return `<!DOCTYPE html>
3
3
  <html lang="en">
4
4
  <head>
@@ -524,10 +524,112 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
524
524
  detailPanel.classList.add('open');
525
525
  };
526
526
 
527
- function renderDiagramView() {
528
- const topModels = [...models]
527
+ // Diagram state
528
+ let diagramModelCount = 15;
529
+ let diagramNamespace = 'all';
530
+ let diagramFocusModel = '';
531
+ let diagramDepth = 2;
532
+
533
+ function getNamespaces() {
534
+ const ns = new Set();
535
+ const prefixes = new Map(); // Count common prefixes
536
+
537
+ models.forEach(m => {
538
+ const name = m.name || m.className || '';
539
+ // Check for Ruby namespace (::)
540
+ if (name.includes('::')) {
541
+ ns.add(name.split('::')[0]);
542
+ }
543
+ // Also try to find common prefixes (e.g., User, UserProfile, UserSetting -> User)
544
+ const match = name.match(/^([A-Z][a-z]+)/);
545
+ if (match) {
546
+ const prefix = match[1];
547
+ prefixes.set(prefix, (prefixes.get(prefix) || 0) + 1);
548
+ }
549
+ });
550
+
551
+ // Add prefixes that have 3+ models as pseudo-namespaces
552
+ prefixes.forEach((count, prefix) => {
553
+ if (count >= 3 && !ns.has(prefix)) {
554
+ ns.add(prefix + '*'); // Mark as prefix-based filter
555
+ }
556
+ });
557
+
558
+ return ['all', ...Array.from(ns).sort()];
559
+ }
560
+
561
+ function getModelNames() {
562
+ return models.map(m => m.name || m.className).sort();
563
+ }
564
+
565
+ // Get related models up to specified depth
566
+ function getRelatedModels(centerModel, depth) {
567
+ const related = new Set([centerModel]);
568
+ const modelMap = new Map();
569
+ models.forEach(m => {
570
+ const name = m.name || m.className;
571
+ modelMap.set(name, m);
572
+ });
573
+
574
+ for (let d = 0; d < depth; d++) {
575
+ const currentModels = [...related];
576
+ currentModels.forEach(modelName => {
577
+ const model = modelMap.get(modelName);
578
+ if (!model) return;
579
+
580
+ model.associations.forEach(assoc => {
581
+ const targetName = assoc.className || capitalize(singularize(assoc.name));
582
+ if (modelMap.has(targetName)) {
583
+ related.add(targetName);
584
+ }
585
+ });
586
+
587
+ // Also find models that reference this model
588
+ models.forEach(m => {
589
+ const mName = m.name || m.className;
590
+ m.associations.forEach(assoc => {
591
+ const targetName = assoc.className || capitalize(singularize(assoc.name));
592
+ if (targetName === modelName) {
593
+ related.add(mName);
594
+ }
595
+ });
596
+ });
597
+ });
598
+ }
599
+
600
+ return related;
601
+ }
602
+
603
+ function generateMermaidCode(modelCount, namespace, focusModel, depth) {
604
+ let filteredModels = [...models];
605
+
606
+ // Filter by focus model (takes priority)
607
+ if (focusModel && focusModel !== '') {
608
+ const relatedNames = getRelatedModels(focusModel, depth);
609
+ filteredModels = filteredModels.filter(m => {
610
+ const name = m.name || m.className;
611
+ return relatedNames.has(name);
612
+ });
613
+ }
614
+ // Filter by namespace
615
+ else if (namespace !== 'all') {
616
+ filteredModels = filteredModels.filter(m => {
617
+ const name = m.name || m.className || '';
618
+ // Handle prefix-based filter (ends with *)
619
+ if (namespace.endsWith('*')) {
620
+ const prefix = namespace.slice(0, -1);
621
+ return name.startsWith(prefix);
622
+ }
623
+ // Handle Ruby namespace (::)
624
+ return name.startsWith(namespace + '::') || name === namespace;
625
+ });
626
+ }
627
+
628
+ // Sort and limit
629
+ const count = modelCount === 'all' ? filteredModels.length : parseInt(modelCount) || 15;
630
+ const topModels = filteredModels
529
631
  .sort((a, b) => b.associations.length - a.associations.length)
530
- .slice(0, 15);
632
+ .slice(0, count);
531
633
 
532
634
  const modelNames = new Set(topModels.map(m => m.name || m.className));
533
635
  let mermaidCode = 'erDiagram\\n';
@@ -560,12 +662,163 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
560
662
  });
561
663
  }
562
664
 
665
+ return { mermaidCode, modelCount: topModels.length, totalModels: filteredModels.length };
666
+ }
667
+
668
+ window.toggleCustomInput = function() {
669
+ const countSelect = document.getElementById('model-count-select');
670
+ const customWrapper = document.getElementById('custom-input-wrapper');
671
+ if (countSelect.value === 'custom') {
672
+ customWrapper.style.display = 'flex';
673
+ document.getElementById('model-count-input').focus();
674
+ } else {
675
+ customWrapper.style.display = 'none';
676
+ document.getElementById('model-count-input').value = '';
677
+ updateDiagram();
678
+ }
679
+ };
680
+
681
+ window.clearFocusModel = function() {
682
+ document.getElementById('focus-model-select').value = '';
683
+ diagramFocusModel = '';
684
+ updateDiagram();
685
+ };
686
+
687
+ window.updateDiagram = function() {
688
+ const countInput = document.getElementById('model-count-input');
689
+ const countSelect = document.getElementById('model-count-select');
690
+ const nsSelect = document.getElementById('namespace-select');
691
+ const focusSelect = document.getElementById('focus-model-select');
692
+ const depthSelect = document.getElementById('depth-select');
693
+
694
+ // Get count from input or select
695
+ let count;
696
+ if (countSelect && countSelect.value === 'custom') {
697
+ count = countInput ? countInput.value.trim() || '15' : '15';
698
+ } else {
699
+ count = countSelect ? countSelect.value : '15';
700
+ }
701
+ diagramModelCount = count;
702
+ diagramNamespace = nsSelect ? nsSelect.value : 'all';
703
+ diagramFocusModel = focusSelect ? focusSelect.value : '';
704
+ diagramDepth = depthSelect ? parseInt(depthSelect.value) || 2 : 2;
705
+
706
+ // If focus model is set, disable namespace filter and enable depth
707
+ if (nsSelect) {
708
+ nsSelect.disabled = diagramFocusModel !== '';
709
+ nsSelect.style.opacity = diagramFocusModel !== '' ? '0.5' : '1';
710
+ }
711
+ if (depthSelect) {
712
+ depthSelect.disabled = diagramFocusModel === '';
713
+ depthSelect.style.opacity = diagramFocusModel !== '' ? '1' : '0.5';
714
+ const depthLabel = depthSelect.parentElement?.querySelector('span');
715
+ if (depthLabel) {
716
+ depthLabel.style.opacity = diagramFocusModel !== '' ? '1' : '0.5';
717
+ }
718
+ }
719
+
720
+ const { mermaidCode, modelCount, totalModels } = generateMermaidCode(count, diagramNamespace, diagramFocusModel, diagramDepth);
721
+
722
+ // Update diagram - need to recreate SVG
723
+ const container = document.getElementById('mermaid-container');
724
+ const diagram = document.getElementById('mermaid-diagram');
725
+ if (diagram && window.mermaid) {
726
+ // Remove old SVG
727
+ const oldSvg = container.querySelector('svg');
728
+ if (oldSvg) oldSvg.remove();
729
+
730
+ // Update mermaid code
731
+ diagram.textContent = mermaidCode;
732
+ diagram.removeAttribute('data-processed');
733
+ diagram.style.display = 'block';
734
+
735
+ // Re-render
736
+ window.mermaid.init(undefined, diagram);
737
+ setTimeout(() => {
738
+ initDiagramPanZoom();
739
+ }, 200);
740
+ }
741
+
742
+ // Update title
743
+ const title = document.querySelector('.diagram-title-text');
744
+ if (title) {
745
+ let filterText = '';
746
+ if (diagramFocusModel) {
747
+ filterText = \` around \${diagramFocusModel} (depth \${diagramDepth})\`;
748
+ } else if (diagramNamespace !== 'all') {
749
+ filterText = \` in \${diagramNamespace}\`;
750
+ }
751
+ title.textContent = \`Model Relationships (\${modelCount}/\${totalModels} models\${filterText})\`;
752
+ }
753
+ };
754
+
755
+ function renderDiagramView() {
756
+ const namespaces = getNamespaces();
757
+ const modelNames = getModelNames();
758
+ const { mermaidCode, modelCount, totalModels } = generateMermaidCode(diagramModelCount, diagramNamespace, diagramFocusModel, diagramDepth);
759
+
760
+ let filterText = '';
761
+ if (diagramFocusModel) {
762
+ filterText = \` around \${diagramFocusModel} (depth \${diagramDepth})\`;
763
+ } else if (diagramNamespace !== 'all') {
764
+ filterText = \` in \${diagramNamespace}\`;
765
+ }
766
+
767
+ const isCustom = !['15', '30', '50', '100', 'all'].includes(String(diagramModelCount));
768
+
563
769
  return \`
564
- <div class="panel-header">
565
- <div class="panel-title">Model Relationships (Top 15 by associations)</div>
566
- </div>
567
- <div class="mermaid-container" id="mermaid-container">
568
- <pre class="mermaid" id="mermaid-diagram">\${mermaidCode}</pre>
770
+ <div class="diagram-view-wrapper" style="display:flex;flex-direction:column;height:100%;min-height:0;">
771
+ <div class="panel-header" style="flex-wrap:wrap;gap:8px;flex-shrink:0;">
772
+ <div class="panel-title diagram-title-text">Model Relationships (\${modelCount}/\${totalModels} models\${filterText})</div>
773
+ <div class="diagram-filters" style="display:flex;gap:12px;align-items:center;flex-wrap:wrap;font-size:12px;">
774
+ <label style="display:flex;align-items:center;gap:6px;">
775
+ <span>Limit:</span>
776
+ <select id="model-count-select" onchange="toggleCustomInput()" style="padding:6px 10px;border-radius:4px;background:#2d2d2d;color:#fff;border:1px solid #444;min-width:80px;">
777
+ <option value="15" \${diagramModelCount == 15 ? 'selected' : ''}>15</option>
778
+ <option value="30" \${diagramModelCount == 30 ? 'selected' : ''}>30</option>
779
+ <option value="50" \${diagramModelCount == 50 ? 'selected' : ''}>50</option>
780
+ <option value="100" \${diagramModelCount == 100 ? 'selected' : ''}>100</option>
781
+ <option value="all" \${diagramModelCount === 'all' ? 'selected' : ''}>All (\${models.length})</option>
782
+ <option value="custom" \${isCustom ? 'selected' : ''}>Custom...</option>
783
+ </select>
784
+ <div id="custom-input-wrapper" style="display:\${isCustom ? 'flex' : 'none'};align-items:center;gap:4px;">
785
+ <input type="number" id="model-count-input" placeholder="Enter number" min="1" max="\${models.length}"
786
+ value="\${isCustom ? diagramModelCount : ''}"
787
+ style="width:100px;padding:6px 10px;border-radius:4px;background:#2d2d2d;color:#fff;border:1px solid #444;"
788
+ onchange="updateDiagram()" onkeyup="if(event.key==='Enter')updateDiagram()">
789
+ <button onclick="updateDiagram()" style="padding:6px 12px;border-radius:4px;background:#3b82f6;color:#fff;border:none;cursor:pointer;">Apply</button>
790
+ </div>
791
+ </label>
792
+ <label style="display:flex;align-items:center;gap:6px;">
793
+ <span>Namespace:</span>
794
+ <select id="namespace-select" onchange="updateDiagram()" style="padding:6px 10px;border-radius:4px;background:#2d2d2d;color:#fff;border:1px solid #444;\${diagramFocusModel ? 'opacity:0.5;' : ''}" \${diagramFocusModel ? 'disabled' : ''}>
795
+ <option value="all" \${diagramNamespace === 'all' ? 'selected' : ''}>All</option>
796
+ \${namespaces.filter(ns => ns !== 'all').map(ns => \`<option value="\${ns}" \${diagramNamespace === ns ? 'selected' : ''}>\${ns}</option>\`).join('')}
797
+ </select>
798
+ </label>
799
+ <label style="display:flex;align-items:center;gap:6px;">
800
+ <span>Focus:</span>
801
+ <select id="focus-model-select" onchange="updateDiagram()" style="padding:6px 10px;border-radius:4px;background:#2d2d2d;color:#fff;border:1px solid #444;max-width:150px;">
802
+ <option value="">None</option>
803
+ \${modelNames.map(name => \`<option value="\${name}" \${diagramFocusModel === name ? 'selected' : ''}>\${name}</option>\`).join('')}
804
+ </select>
805
+ \${diagramFocusModel ? \`<button onclick="clearFocusModel()" style="padding:4px 8px;border-radius:4px;background:#666;color:#fff;border:none;cursor:pointer;" title="Clear focus">\u2715</button>\` : ''}
806
+ </label>
807
+ <label style="display:flex;align-items:center;gap:6px;">
808
+ <span style="opacity:\${diagramFocusModel ? 1 : 0.5}">Depth:</span>
809
+ <select id="depth-select" onchange="updateDiagram()" \${diagramFocusModel ? '' : 'disabled'} style="padding:6px 10px;border-radius:4px;background:#2d2d2d;color:#fff;border:1px solid #444;opacity:\${diagramFocusModel ? 1 : 0.5}">
810
+ <option value="1" \${diagramDepth === 1 ? 'selected' : ''}>1</option>
811
+ <option value="2" \${diagramDepth === 2 ? 'selected' : ''}>2</option>
812
+ <option value="3" \${diagramDepth === 3 ? 'selected' : ''}>3</option>
813
+ <option value="4" \${diagramDepth === 4 ? 'selected' : ''}>4</option>
814
+ <option value="5" \${diagramDepth === 5 ? 'selected' : ''}>5</option>
815
+ </select>
816
+ </label>
817
+ </div>
818
+ </div>
819
+ <div class="mermaid-container" id="mermaid-container" style="flex:1;min-height:0;">
820
+ <pre class="mermaid" id="mermaid-diagram">\${mermaidCode}</pre>
821
+ </div>
569
822
  </div>
570
823
  \`;
571
824
  }
@@ -609,6 +862,20 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
609
862
  const svg = container?.querySelector('svg');
610
863
  if (!svg) return;
611
864
 
865
+ // Calculate dynamic max zoom based on SVG size
866
+ const svgRect = svg.getBoundingClientRect();
867
+ const containerRect = container.getBoundingClientRect();
868
+ const svgWidth = svgRect.width || 1000;
869
+ const svgHeight = svgRect.height || 500;
870
+
871
+ // Max zoom: allow reading small text clearly
872
+ // For very wide diagrams (many models), need much higher zoom
873
+ const minZoom = 0.01;
874
+ const maxZoom = Math.max(100, Math.ceil(svgWidth / 20)); // Very aggressive zoom
875
+ window.diagramMaxZoom = maxZoom;
876
+ window.diagramMinZoom = minZoom;
877
+ console.log('Diagram zoom range:', minZoom, '-', maxZoom, 'x (SVG width:', svgWidth, 'px)');
878
+
612
879
  let scale = 1;
613
880
  let translateX = 0;
614
881
  let translateY = 0;
@@ -803,11 +1070,13 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
803
1070
  svg.style.transform = \`translate(\${translateX}px, \${translateY}px) scale(\${scale})\`;
804
1071
  }
805
1072
 
806
- // Mouse wheel zoom
1073
+ // Mouse wheel zoom (extended range: 0.3x to 10x)
807
1074
  container.addEventListener('wheel', (e) => {
808
1075
  e.preventDefault();
809
- const delta = e.deltaY > 0 ? -0.1 : 0.1;
810
- scale = Math.max(0.3, Math.min(3, scale + delta));
1076
+ // Dynamic step: larger steps at higher zoom levels for faster navigation
1077
+ const step = Math.max(0.1, scale * 0.15);
1078
+ const delta = e.deltaY > 0 ? -step : step;
1079
+ scale = Math.max(minZoom, Math.min(maxZoom, scale + delta));
811
1080
  updateTransform();
812
1081
  }, { passive: false });
813
1082
 
@@ -834,7 +1103,7 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
834
1103
  e.touches[0].clientY - e.touches[1].clientY
835
1104
  );
836
1105
  const delta = (dist - lastTouchDist) * 0.01;
837
- scale = Math.max(0.3, Math.min(3, scale + delta));
1106
+ scale = Math.max(minZoom, Math.min(maxZoom, scale + delta));
838
1107
  lastTouchDist = dist;
839
1108
  updateTransform();
840
1109
  } else if (e.touches.length === 1 && isDragging) {
@@ -873,7 +1142,10 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
873
1142
 
874
1143
  // Global functions for controls
875
1144
  window.diagramZoom = (delta) => {
876
- scale = Math.max(0.3, Math.min(3, scale + delta));
1145
+ // Dynamic step based on current scale
1146
+ const step = Math.max(0.2, scale * 0.2);
1147
+ const actualDelta = delta > 0 ? step : -step;
1148
+ scale = Math.max(minZoom, Math.min(maxZoom, scale + actualDelta));
877
1149
  updateTransform();
878
1150
  };
879
1151
 
@@ -1147,5 +1419,5 @@ import {k}from'./chunk-H7VVRHQZ.js';import*as d from'fs';import*as c from'path';
1147
1419
  `).join("")}
1148
1420
  </tbody>
1149
1421
  </table>
1150
- `}highlightParams(t){return t.replace(/:([a-zA-Z_]+)/g,'<span class="param">:$1</span>')}};async function m(){let n=process.argv[2]||process.cwd(),t=process.argv[3]||c.join(n,"rails-map.html");await new o(n).generate({title:"Rails Application Map",outputPath:t});}var p=import.meta.url===`file://${process.argv[1]}`;p&&m().catch(console.error);
1151
- export{o as a};
1422
+ `}highlightParams(t){return t.replace(/:([a-zA-Z_]+)/g,'<span class="param">:$1</span>')}};async function m(){let o=process.argv[2]||process.cwd(),t=process.argv[3]||c.join(o,"rails-map.html");await new n(o).generate({title:"Rails Application Map",outputPath:t});}var p=import.meta.url===`file://${process.argv[1]}`;p&&m().catch(console.error);
1423
+ export{n as a};
@@ -2208,7 +2208,7 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
2208
2208
  visited.add(comp.name);
2209
2209
 
2210
2210
  // Check hooks for GraphQL queries (only match "Query: X" or "Mutation: X" format)
2211
- if (comp.hooks && comp.hooks.some(h =>
2211
+ if (comp.hooks && comp.hooks.some(h =>
2212
2212
  h.startsWith('Query: ') || h.startsWith('Mutation: ') || h.startsWith('Subscription: ')
2213
2213
  )) {
2214
2214
  return true;
@@ -2294,9 +2294,9 @@ var P=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,n){let
2294
2294
  ]);
2295
2295
 
2296
2296
  // Debug: log pagesWithGraphQL count
2297
- console.log('\u{1F4CA} GraphQL Stats: totalComponents=' + components.length +
2297
+ console.log('\u{1F4CA} GraphQL Stats: totalComponents=' + components.length +
2298
2298
  ', componentsWithGraphQL=' + components.filter(c => c.hooks && c.hooks.some(h => h.startsWith('Query: ') || h.startsWith('Mutation: '))).length +
2299
- ', pagesWithGraphQL=' + pagesWithGraphQL.size +
2299
+ ', pagesWithGraphQL=' + pagesWithGraphQL.size +
2300
2300
  ', totalPages=' + pages.length);
2301
2301
 
2302
2302
  const pagesWithRestApi = new Set(pages.filter(p => {
package/dist/cli.js CHANGED
@@ -1,23 +1,25 @@
1
1
  #!/usr/bin/env node
2
- import {a,b}from'./chunk-JDM7Y7PX.js';import'./chunk-OQAXO3X2.js';import'./chunk-VV3A3UE3.js';import'./chunk-TNUKDIO7.js';import'./chunk-HPBPEGHS.js';import'./chunk-GCIRJGW3.js';import'./chunk-H7VVRHQZ.js';import {Command}from'commander';import s from'chalk';import*as p from'path';import*as n from'fs/promises';var d=new Command;d.name("repomap").description("Interactive documentation generator for code repositories").version("0.6.0");async function $(e){let t=p.basename(e),a=false,o=p.join(e,"Gemfile"),c=p.join(e,"config","routes.rb");try{await n.access(o),await n.access(c);let u=await n.readFile(o,"utf-8");a=u.includes("gem 'rails'")||u.includes('gem "rails"');}catch{}let r=p.join(e,"package.json"),i=false,l=false,f={};try{let u=JSON.parse(await n.readFile(r,"utf-8")),y={...u.dependencies,...u.devDependencies};i=!!y.react,l=!!y.next;let m=["src/pages","pages","app","src/app","frontend/src"];for(let g of m)try{await n.access(p.join(e,g)),f.pagesDir=g;break}catch{}let b=["src/features","features","src/modules","modules","frontend/src"];for(let g of b)try{await n.access(p.join(e,g)),f.featuresDir=g;break}catch{}let D=["src/components","components","src/common/components","frontend/src"];for(let g of D)try{await n.access(p.join(e,g)),f.componentsDir=g;break}catch{}}catch{}let h=[];(i||l)&&h.push("pages","graphql","dataflow","rest-api");let w="generic";return l?w="nextjs":a&&(w="rails"),!a&&!i&&!l?null:{name:t,displayName:t,description:a&&i?"Rails + React application":a?"Rails application":"",path:e,branch:"main",type:w,analyzers:h,settings:f}}async function x(e){let t=await $(e);if(!t)throw new Error("Could not detect project. Please create a repomap.config.ts file or run 'repomap init'.");return {outputDir:"./.repomap",site:{title:`${t.displayName} Documentation`,description:"Auto-generated documentation",baseUrl:"/docs"},repositories:[t],analysis:{include:["**/*.tsx","**/*.ts"],exclude:["**/node_modules/**","**/__tests__/**","**/*.test.*","**/*.spec.*","**/dist/**","**/.next/**"],maxDepth:5},diagrams:{enabled:true,types:["flowchart","sequence"],theme:"default"},watch:{enabled:false,debounce:1e3},integrations:{github:{enabled:false,organization:""},slack:{enabled:false}}}}async function P(e,t){let a=e?[e]:["repomap.config.ts","repomap.config.js","repomap.config.mjs"];for(let o of a){let c=p.resolve(t,o);try{await n.access(c);let r=await import(c);return r.config||r.default}catch{}}return x(t)}d.command("generate").description("Generate documentation from source code").option("-c, --config <path>","Path to config file").option("-o, --output <path>","Output directory").option("--repo <name>","Analyze specific repository only").option("--watch","Watch for changes and regenerate").option("--format <type>","Output format: json, html, markdown (default: all)","all").option("--ci","CI mode: minimal output, exit codes for errors").option("--static","Generate standalone HTML files (for GitHub Pages)").action(async e=>{let t=e.ci||process.env.CI==="true";t||console.log(s.blue.bold(`
2
+ import {a,b}from'./chunk-LDX6WPHR.js';import'./chunk-P7MX3M5U.js';import'./chunk-VV3A3UE3.js';import'./chunk-TNUKDIO7.js';import'./chunk-HPBPEGHS.js';import'./chunk-SMN6XFMS.js';import'./chunk-H7VVRHQZ.js';import {Command}from'commander';import s from'chalk';import*as c from'path';import*as n from'fs/promises';import*as v from'os';function P(){let e=v.tmpdir();return c.join(e,`repomap-${Date.now()}`)}function C(e){let t=async()=>{try{await n.rm(e,{recursive:!0,force:!0});}catch{}process.exit(0);};process.on("SIGINT",t),process.on("SIGTERM",t);}var d=new Command;d.name("repomap").description("Interactive documentation generator for code repositories").version("0.6.0");async function x(e){let t=c.basename(e),a=false,o=c.join(e,"Gemfile"),p=c.join(e,"config","routes.rb");try{await n.access(o),await n.access(p);let g=await n.readFile(o,"utf-8");a=g.includes("gem 'rails'")||g.includes('gem "rails"');}catch{}let r=c.join(e,"package.json"),i=false,l=false,m={};try{let g=JSON.parse(await n.readFile(r,"utf-8")),w={...g.dependencies,...g.devDependencies};i=!!w.react,l=!!w.next;let f=["src/pages","pages","app","src/app","frontend/src"];for(let u of f)try{await n.access(c.join(e,u)),m.pagesDir=u;break}catch{}let b=["src/features","features","src/modules","modules","frontend/src"];for(let u of b)try{await n.access(c.join(e,u)),m.featuresDir=u;break}catch{}let D=["src/components","components","src/common/components","frontend/src"];for(let u of D)try{await n.access(c.join(e,u)),m.componentsDir=u;break}catch{}}catch{}let h=[];(i||l)&&h.push("pages","graphql","dataflow","rest-api");let y="generic";return l?y="nextjs":a&&(y="rails"),!a&&!i&&!l?null:{name:t,displayName:t,description:a&&i?"Rails + React application":a?"Rails application":"",path:e,branch:"main",type:y,analyzers:h,settings:m}}async function E(e){let t=await x(e);if(!t)throw new Error("Could not detect project. Please create a repomap.config.ts file or run 'repomap init'.");return {outputDir:"./.repomap",site:{title:`${t.displayName} Documentation`,description:"Auto-generated documentation",baseUrl:"/docs"},repositories:[t],analysis:{include:["**/*.tsx","**/*.ts"],exclude:["**/node_modules/**","**/__tests__/**","**/*.test.*","**/*.spec.*","**/dist/**","**/.next/**"],maxDepth:5},diagrams:{enabled:true,types:["flowchart","sequence"],theme:"default"},watch:{enabled:false,debounce:1e3},integrations:{github:{enabled:false,organization:""},slack:{enabled:false}}}}async function $(e,t){let a=e?[e]:["repomap.config.ts","repomap.config.js","repomap.config.mjs"];for(let o of a){let p=c.resolve(t,o);try{await n.access(p);let r=await import(p);return r.config||r.default}catch{}}return E(t)}d.command("generate").description("Generate documentation from source code").option("-c, --config <path>","Path to config file").option("-o, --output <path>","Output directory").option("--temp","Use temporary directory (no files in repository)").option("--repo <name>","Analyze specific repository only").option("--watch","Watch for changes and regenerate").option("--format <type>","Output format: json, html, markdown (default: all)","all").option("--ci","CI mode: minimal output, exit codes for errors").option("--static","Generate standalone HTML files (for GitHub Pages)").action(async e=>{let t=e.ci||process.env.CI==="true";t||console.log(s.blue.bold(`
3
3
  \u{1F4DA} Repomap
4
- `));try{let a$1=process.cwd(),o=await P(e.config,a$1);e.output&&(o.outputDir=e.output),e.repo&&(o.repositories=o.repositories.filter(r=>r.name===e.repo),o.repositories.length===0&&(console.error(s.red(`Repository "${e.repo}" not found in config`)),process.exit(1)));let c=new a(o);if(e.watch)console.log(s.yellow(`\u{1F440} Watch mode enabled. Press Ctrl+C to stop.
5
- `)),await G(c,o);else {let r=await c.generate();if(e.format==="json"||e.static){let i=p.join(o.outputDir,"report.json");await n.mkdir(o.outputDir,{recursive:!0}),await n.writeFile(i,JSON.stringify(r,null,2)),t||console.log(s.gray(` \u2192 ${i}`));}if(e.static&&await C(o,r,t),!t)E(r);else {let i=r.repositories.reduce((l,f)=>l+f.summary.totalPages,0);console.log(`\u2705 Generated: ${i} pages, ${r.repositories.length} repos`);}}}catch(a){console.error(t?`Error: ${a.message}`:s.red("Error:"),a.message),process.exit(1);}});async function C(e,t,a){let{PageMapGenerator:o}=await import('./page-map-generator-3GO6GL2P.js'),{detectEnvironments:c}=await import('./env-detector-BIWJ7OYF.js'),r=e.outputDir;await n.mkdir(r,{recursive:true});let i=e.repositories[0]?.path||process.cwd(),l=await c(i),f=null;if(l.hasRails){let{analyzeRailsApp:m}=await import('./rails-3HNUFTQV.js');f=await m(i);}let w=new o().generatePageMapHtml(t,{envResult:l,railsAnalysis:f,staticMode:true});if(await n.writeFile(p.join(r,"index.html"),w),a||console.log(s.gray(` \u2192 ${p.join(r,"index.html")}`)),f){let{RailsMapGenerator:m}=await import('./rails-map-generator-CAQZUBI6.js'),D=new m().generateFromResult(f);await n.writeFile(p.join(r,"rails-map.html"),D),a||console.log(s.gray(` \u2192 ${p.join(r,"rails-map.html")}`));}let u=["common.css","page-map.css","docs.css","rails-map.css"],y=p.join(r,"assets");await n.mkdir(y,{recursive:true});for(let m of u)try{let b=new URL(`./generators/assets/${m}`,import.meta.url),D=await n.readFile(b,"utf-8");await n.writeFile(p.join(y,m),D);}catch{}a||console.log(s.green(`
6
- \u2705 Static site generated: ${r}`));}d.command("serve").description("Start local documentation server with live reload").option("-c, --config <path>","Path to config file").option("--path <path>","Path to repository to analyze (auto-detect if no config)").option("-p, --port <number>","Server port","3030").option("--no-open","Don't open browser automatically").action(async e=>{console.log(s.blue.bold(`
4
+ `));try{let a$1=process.cwd(),o=await $(e.config,a$1);e.temp&&(o.outputDir=P(),t||console.log(s.cyan(`\u{1F4C1} Using temp directory: ${o.outputDir}
5
+ `))),e.output&&(o.outputDir=e.output),e.repo&&(o.repositories=o.repositories.filter(r=>r.name===e.repo),o.repositories.length===0&&(console.error(s.red(`Repository "${e.repo}" not found in config`)),process.exit(1)));let p=new a(o);if(e.watch)console.log(s.yellow(`\u{1F440} Watch mode enabled. Press Ctrl+C to stop.
6
+ `)),await F(p,o);else {let r=await p.generate();if(e.format==="json"||e.static){let i=c.join(o.outputDir,"report.json");await n.mkdir(o.outputDir,{recursive:!0}),await n.writeFile(i,JSON.stringify(r,null,2)),t||console.log(s.gray(` \u2192 ${i}`));}if(e.static&&await N(o,r,t),!t)S(r);else {let i=r.repositories.reduce((l,m)=>l+m.summary.totalPages,0);console.log(`\u2705 Generated: ${i} pages, ${r.repositories.length} repos`);}}}catch(a){console.error(t?`Error: ${a.message}`:s.red("Error:"),a.message),process.exit(1);}});async function N(e,t,a){let{PageMapGenerator:o}=await import('./page-map-generator-2XQB7RWO.js'),{detectEnvironments:p}=await import('./env-detector-BIWJ7OYF.js'),r=e.outputDir;await n.mkdir(r,{recursive:true});let i=e.repositories[0]?.path||process.cwd(),l=await p(i),m=null;if(l.hasRails){let{analyzeRailsApp:f}=await import('./rails-3HNUFTQV.js');m=await f(i);}let y=new o().generatePageMapHtml(t,{envResult:l,railsAnalysis:m,staticMode:true});if(await n.writeFile(c.join(r,"index.html"),y),a||console.log(s.gray(` \u2192 ${c.join(r,"index.html")}`)),m){let{RailsMapGenerator:f}=await import('./rails-map-generator-77ATUFMP.js'),D=new f().generateFromResult(m);await n.writeFile(c.join(r,"rails-map.html"),D),a||console.log(s.gray(` \u2192 ${c.join(r,"rails-map.html")}`));}let g=["common.css","page-map.css","docs.css","rails-map.css"],w=c.join(r,"assets");await n.mkdir(w,{recursive:true});for(let f of g)try{let b=new URL(`./generators/assets/${f}`,import.meta.url),D=await n.readFile(b,"utf-8");await n.writeFile(c.join(w,f),D);}catch{}a||console.log(s.green(`
7
+ \u2705 Static site generated: ${r}`));}d.command("serve").description("Start local documentation server with live reload").option("-c, --config <path>","Path to config file").option("--path <path>","Path to repository to analyze (auto-detect if no config)").option("-o, --output <path>","Output directory (default: .repomap in target path)").option("-p, --port <number>","Server port","3030").option("--temp","Use temporary directory (no files in repository)").option("--no-open","Don't open browser automatically").action(async e=>{console.log(s.blue.bold(`
7
8
  \u{1F310} Repomap
8
- `));try{let t=e.path||process.cwd(),a=await P(e.config,t);await new b(a,parseInt(e.port)).start(!e.open);}catch(t){console.error(s.red("Error:"),t.message),process.exit(1);}});d.command("init").description("Initialize repomap configuration").option("-f, --force","Overwrite existing config").action(async e=>{let t="./repomap.config.ts";try{if(await n.access(t).then(()=>!0).catch(()=>!1)&&!e.force){console.log(s.yellow("Config file already exists. Use --force to overwrite."));return}let o=await $(process.cwd()),c=o?.name||"my-project",r=o?.type||"nextjs",i=o?.settings.pagesDir||"src/pages",l=o?.settings.featuresDir||"src/features",f=o?.settings.componentsDir||"src/components",h=`import type { DocGeneratorConfig } from "repomap";
9
+ `));try{let t=e.path||process.cwd(),a=await $(e.config,t);e.temp&&(a.outputDir=P(),console.log(s.cyan(`\u{1F4C1} Using temp directory: ${a.outputDir}
10
+ `)),C(a.outputDir)),e.output&&(a.outputDir=c.resolve(e.output)),await new b(a,parseInt(e.port)).start(!e.open);}catch(t){console.error(s.red("Error:"),t.message),process.exit(1);}});d.command("init").description("Initialize repomap configuration").option("-f, --force","Overwrite existing config").action(async e=>{let t="./repomap.config.ts";try{if(await n.access(t).then(()=>!0).catch(()=>!1)&&!e.force){console.log(s.yellow("Config file already exists. Use --force to overwrite."));return}let o=await x(process.cwd()),p=o?.name||"my-project",r=o?.type||"nextjs",i=o?.settings.pagesDir||"src/pages",l=o?.settings.featuresDir||"src/features",m=o?.settings.componentsDir||"src/components",h=`import type { DocGeneratorConfig } from "repomap";
9
11
 
10
12
  export const config: DocGeneratorConfig = {
11
13
  outputDir: "./.repomap",
12
14
  site: {
13
- title: "${c} Documentation",
15
+ title: "${p} Documentation",
14
16
  description: "Auto-generated documentation",
15
17
  baseUrl: "/docs",
16
18
  },
17
19
  repositories: [
18
20
  {
19
- name: "${c}",
20
- displayName: "${c}",
21
+ name: "${p}",
22
+ displayName: "${p}",
21
23
  description: "Main repository",
22
24
  path: ".",
23
25
  branch: "main",
@@ -26,7 +28,7 @@ export const config: DocGeneratorConfig = {
26
28
  settings: {
27
29
  pagesDir: "${i}",
28
30
  featuresDir: "${l}",
29
- componentsDir: "${f}",
31
+ componentsDir: "${m}",
30
32
  },
31
33
  },
32
34
  ],
@@ -54,10 +56,10 @@ export default config;
54
56
  `;await n.writeFile(t,h,"utf-8"),console.log(s.green(`\u2705 Created ${t}`)),console.log(s.gray(`
55
57
  Run 'npx repomap serve' to start the documentation server.`));}catch(a){console.error(s.red("Failed to create config:"),a.message);}});d.command("rails").description("Analyze a Rails application and generate interactive map").option("--path <path>","Path to Rails application").option("-o, --output <path>","Output HTML file path").action(async e=>{console.log(s.blue.bold(`
56
58
  \u{1F6E4}\uFE0F Repomap Rails
57
- `));try{let t=e.path||process.cwd();try{await n.access(p.join(t,"config","routes.rb"));}catch{console.error(s.red("Not a Rails project (config/routes.rb not found)")),process.exit(1);}let{RailsMapGenerator:a}=await import('./rails-map-generator-CAQZUBI6.js'),o=e.output||p.join(t,"rails-map.html");await new a(t).generate({title:`${p.basename(t)} - Rails Map`,outputPath:o}),console.log(s.green(`\u2705 Rails map generated: ${o}`));let{exec:r}=await import('child_process');r(`open "${o}"`);}catch(t){console.error(s.red("Error:"),t.message),process.exit(1);}});d.command("diff").description("Show documentation changes since last generation").option("-c, --config <path>","Path to config file").action(async e=>{console.log(s.blue.bold(`
59
+ `));try{let t=e.path||process.cwd();try{await n.access(c.join(t,"config","routes.rb"));}catch{console.error(s.red("Not a Rails project (config/routes.rb not found)")),process.exit(1);}let{RailsMapGenerator:a}=await import('./rails-map-generator-77ATUFMP.js'),o=e.output||c.join(t,"rails-map.html");await new a(t).generate({title:`${c.basename(t)} - Rails Map`,outputPath:o}),console.log(s.green(`\u2705 Rails map generated: ${o}`));let{exec:r}=await import('child_process');r(`open "${o}"`);}catch(t){console.error(s.red("Error:"),t.message),process.exit(1);}});d.command("diff").description("Show documentation changes since last generation").option("-c, --config <path>","Path to config file").action(async e=>{console.log(s.blue.bold(`
58
60
  \u{1F4CA} Documentation Diff
59
- `));try{let t=process.cwd(),a$1=await P(e.config,t),o=p.join(a$1.outputDir,"report.json");if(!await n.access(o).then(()=>!0).catch(()=>!1)){console.log(s.yellow("No previous report found. Run 'generate' first."));return}let r=JSON.parse(await n.readFile(o,"utf-8")),l=await new a(a$1).generate();F(r,l);}catch(t){console.error(s.red("Failed to generate diff:"),t.message);}});async function G(e,t){await e.generate();let a=t.repositories.map(o=>o.path);for(let o of a){let c=n.watch(o,{recursive:true}),r=null;for await(let i of c)i.filename&&(i.filename.endsWith(".ts")||i.filename.endsWith(".tsx"))&&(r&&clearTimeout(r),r=setTimeout(async()=>{console.log(s.yellow(`
60
- \u{1F504} Change detected: ${i.filename}`)),await e.generate();},t.watch.debounce));}}function E(e){console.log(s.green.bold(`
61
+ `));try{let t=process.cwd(),a$1=await $(e.config,t),o=c.join(a$1.outputDir,"report.json");if(!await n.access(o).then(()=>!0).catch(()=>!1)){console.log(s.yellow("No previous report found. Run 'generate' first."));return}let r=JSON.parse(await n.readFile(o,"utf-8")),l=await new a(a$1).generate();k(r,l);}catch(t){console.error(s.red("Failed to generate diff:"),t.message);}});async function F(e,t){await e.generate();let a=t.repositories.map(o=>o.path);for(let o of a){let p=n.watch(o,{recursive:true}),r=null;for await(let i of p)i.filename&&(i.filename.endsWith(".ts")||i.filename.endsWith(".tsx"))&&(r&&clearTimeout(r),r=setTimeout(async()=>{console.log(s.yellow(`
62
+ \u{1F504} Change detected: ${i.filename}`)),await e.generate();},t.watch.debounce));}}function S(e){console.log(s.green.bold(`
61
63
  \u2705 Complete
62
- `));for(let t of e.repositories)console.log(s.white(` ${t.displayName}`)),console.log(s.gray(` ${t.summary.totalPages} pages \xB7 ${t.summary.totalComponents} components \xB7 ${t.summary.totalGraphQLOperations} GraphQL ops`));console.log();}function F(e,t){console.log(s.cyan(`Changes detected:
63
- `));for(let a of t.repositories){let o=e.repositories.find(l=>l.name===a.name);if(!o){console.log(s.green(` + New repository: ${a.displayName}`));continue}let c=a.summary.totalPages-o.summary.totalPages,r=a.summary.totalComponents-o.summary.totalComponents,i=a.summary.totalGraphQLOperations-o.summary.totalGraphQLOperations;(c!==0||r!==0||i!==0)&&(console.log(s.yellow(` ~ ${a.displayName}:`)),c!==0&&console.log(` Pages: ${c>0?"+":""}${c}`),r!==0&&console.log(` Components: ${r>0?"+":""}${r}`),i!==0&&console.log(` GraphQL Ops: ${i>0?"+":""}${i}`));}}d.parse();
64
+ `));for(let t of e.repositories)console.log(s.white(` ${t.displayName}`)),console.log(s.gray(` ${t.summary.totalPages} pages \xB7 ${t.summary.totalComponents} components \xB7 ${t.summary.totalGraphQLOperations} GraphQL ops`));console.log();}function k(e,t){console.log(s.cyan(`Changes detected:
65
+ `));for(let a of t.repositories){let o=e.repositories.find(l=>l.name===a.name);if(!o){console.log(s.green(` + New repository: ${a.displayName}`));continue}let p=a.summary.totalPages-o.summary.totalPages,r=a.summary.totalComponents-o.summary.totalComponents,i=a.summary.totalGraphQLOperations-o.summary.totalGraphQLOperations;(p!==0||r!==0||i!==0)&&(console.log(s.yellow(` ~ ${a.displayName}:`)),p!==0&&console.log(` Pages: ${p>0?"+":""}${p}`),r!==0&&console.log(` Components: ${r>0?"+":""}${r}`),i!==0&&console.log(` GraphQL Ops: ${i>0?"+":""}${i}`));}}d.parse();
@@ -241,6 +241,8 @@ header h1 {
241
241
  .main-panel {
242
242
  overflow-y: auto;
243
243
  padding: 20px;
244
+ display: flex;
245
+ flex-direction: column;
244
246
  }
245
247
 
246
248
  .panel-header {
@@ -572,6 +574,10 @@ header h1 {
572
574
  position: relative;
573
575
  min-height: 300px;
574
576
  cursor: grab;
577
+ flex: 1;
578
+ display: flex;
579
+ align-items: center;
580
+ justify-content: center;
575
581
  }
576
582
 
577
583
  .mermaid-container:active {
@@ -1 +1 @@
1
- export{b as MarkdownGenerator,a as MermaidGenerator}from'../chunk-HPBPEGHS.js';export{a as PageMapGenerator}from'../chunk-GCIRJGW3.js';
1
+ export{b as MarkdownGenerator,a as MermaidGenerator}from'../chunk-HPBPEGHS.js';export{a as PageMapGenerator}from'../chunk-SMN6XFMS.js';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import'./chunk-6F4PWJZI.js';export{a as DocGeneratorEngine,b as DocServer}from'./chunk-JDM7Y7PX.js';import'./chunk-OQAXO3X2.js';import'./chunk-VV3A3UE3.js';export{a as BaseAnalyzer,A as DataFlowAnalyzer,z as GraphQLAnalyzer,y as PagesAnalyzer}from'./chunk-TNUKDIO7.js';export{b as MarkdownGenerator,a as MermaidGenerator}from'./chunk-HPBPEGHS.js';export{a as PageMapGenerator}from'./chunk-GCIRJGW3.js';import'./chunk-H7VVRHQZ.js';
1
+ import'./chunk-6F4PWJZI.js';export{a as DocGeneratorEngine,b as DocServer}from'./chunk-LDX6WPHR.js';import'./chunk-P7MX3M5U.js';import'./chunk-VV3A3UE3.js';export{a as BaseAnalyzer,A as DataFlowAnalyzer,z as GraphQLAnalyzer,y as PagesAnalyzer}from'./chunk-TNUKDIO7.js';export{b as MarkdownGenerator,a as MermaidGenerator}from'./chunk-HPBPEGHS.js';export{a as PageMapGenerator}from'./chunk-SMN6XFMS.js';import'./chunk-H7VVRHQZ.js';
@@ -0,0 +1 @@
1
+ export{a as PageMapGenerator}from'./chunk-SMN6XFMS.js';
@@ -0,0 +1 @@
1
+ export{a as RailsMapGenerator}from'./chunk-P7MX3M5U.js';import'./chunk-H7VVRHQZ.js';
@@ -1 +1 @@
1
- export{b as DocServer}from'../chunk-JDM7Y7PX.js';import'../chunk-OQAXO3X2.js';import'../chunk-VV3A3UE3.js';import'../chunk-TNUKDIO7.js';import'../chunk-HPBPEGHS.js';import'../chunk-GCIRJGW3.js';import'../chunk-H7VVRHQZ.js';
1
+ export{b as DocServer}from'../chunk-LDX6WPHR.js';import'../chunk-P7MX3M5U.js';import'../chunk-VV3A3UE3.js';import'../chunk-TNUKDIO7.js';import'../chunk-HPBPEGHS.js';import'../chunk-SMN6XFMS.js';import'../chunk-H7VVRHQZ.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wtdlee/repomap",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Interactive documentation generator for code repositories - visualize pages, components, GraphQL operations, and data flows",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -75,8 +75,6 @@
75
75
  "node": ">=18.0.0"
76
76
  },
77
77
  "dependencies": {
78
- "@babel/parser": "^7.23.0",
79
- "@babel/traverse": "^7.23.0",
80
78
  "@swc/core": "^1.15.3",
81
79
  "chalk": "^5.3.0",
82
80
  "commander": "^14.0.2",
@@ -89,14 +87,12 @@
89
87
  "simple-git": "^3.21.0",
90
88
  "socket.io": "^4.7.2",
91
89
  "tree-sitter-wasms": "^0.1.13",
92
- "ts-morph": "^27.0.2",
93
90
  "web-tree-sitter": "^0.25.10",
94
91
  "yaml": "^2.3.4"
95
92
  },
96
93
  "devDependencies": {
97
94
  "@changesets/cli": "^2.27.0",
98
95
  "@eslint/js": "^9.39.1",
99
- "@types/babel__traverse": "^7.20.4",
100
96
  "@types/express": "^5.0.6",
101
97
  "@types/node": "^25.0.1",
102
98
  "eslint": "^9.39.1",
@@ -1 +0,0 @@
1
- export{a as PageMapGenerator}from'./chunk-GCIRJGW3.js';
@@ -1 +0,0 @@
1
- export{a as RailsMapGenerator}from'./chunk-OQAXO3X2.js';import'./chunk-H7VVRHQZ.js';