@wtdlee/repomap 0.7.0 → 0.8.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 +17 -1
- package/dist/cli.js +16 -14
- package/package.json +1 -5
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
|
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
|
|
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 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
|
|
5
|
-
`)),
|
|
6
|
-
|
|
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-3GO6GL2P.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-CAQZUBI6.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
|
|
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: "${
|
|
15
|
+
title: "${p} Documentation",
|
|
14
16
|
description: "Auto-generated documentation",
|
|
15
17
|
baseUrl: "/docs",
|
|
16
18
|
},
|
|
17
19
|
repositories: [
|
|
18
20
|
{
|
|
19
|
-
name: "${
|
|
20
|
-
displayName: "${
|
|
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: "${
|
|
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(
|
|
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-CAQZUBI6.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
|
|
60
|
-
\u{1F504} Change detected: ${i.filename}`)),await e.generate();},t.watch.debounce));}}function
|
|
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
|
|
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
|
|
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();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtdlee/repomap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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",
|