@wtdlee/repomap 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/analyzers/index.d.ts +69 -5
  2. package/dist/analyzers/index.js +1 -5
  3. package/dist/{server/doc-server.js → chunk-4K4MGTPV.js} +41 -329
  4. package/dist/chunk-6F4PWJZI.js +0 -0
  5. package/dist/chunk-J2CM7T7U.js +1 -0
  6. package/dist/{generators/page-map-generator.js → chunk-MOEA75XK.js} +278 -503
  7. package/dist/{generators/rails-map-generator.js → chunk-SL2GMDBN.js} +48 -129
  8. package/dist/chunk-UJT5KTVK.js +36 -0
  9. package/dist/chunk-VV3A3UE3.js +1 -0
  10. package/dist/chunk-XWZH2RDG.js +19 -0
  11. package/dist/cli.d.ts +0 -1
  12. package/dist/cli.js +29 -499
  13. package/dist/dataflow-analyzer-BfAiqVUp.d.ts +180 -0
  14. package/dist/env-detector-BIWJ7OYF.js +1 -0
  15. package/dist/generators/assets/common.css +564 -23
  16. package/dist/generators/index.d.ts +431 -3
  17. package/dist/generators/index.js +1 -3
  18. package/dist/index.d.ts +53 -10
  19. package/dist/index.js +1 -11
  20. package/dist/page-map-generator-XNZ4TDJT.js +1 -0
  21. package/dist/rails-TJCDGBBF.js +1 -0
  22. package/dist/rails-map-generator-JL5PKHYP.js +1 -0
  23. package/dist/server/index.d.ts +33 -1
  24. package/dist/server/index.js +1 -1
  25. package/dist/types.d.ts +39 -37
  26. package/dist/types.js +1 -5
  27. package/package.json +4 -2
  28. package/dist/analyzers/base-analyzer.d.ts +0 -45
  29. package/dist/analyzers/base-analyzer.js +0 -47
  30. package/dist/analyzers/dataflow-analyzer.d.ts +0 -29
  31. package/dist/analyzers/dataflow-analyzer.js +0 -425
  32. package/dist/analyzers/graphql-analyzer.d.ts +0 -22
  33. package/dist/analyzers/graphql-analyzer.js +0 -386
  34. package/dist/analyzers/pages-analyzer.d.ts +0 -84
  35. package/dist/analyzers/pages-analyzer.js +0 -1695
  36. package/dist/analyzers/rails/index.d.ts +0 -46
  37. package/dist/analyzers/rails/index.js +0 -145
  38. package/dist/analyzers/rails/rails-controller-analyzer.d.ts +0 -82
  39. package/dist/analyzers/rails/rails-controller-analyzer.js +0 -478
  40. package/dist/analyzers/rails/rails-grpc-analyzer.d.ts +0 -44
  41. package/dist/analyzers/rails/rails-grpc-analyzer.js +0 -262
  42. package/dist/analyzers/rails/rails-model-analyzer.d.ts +0 -88
  43. package/dist/analyzers/rails/rails-model-analyzer.js +0 -493
  44. package/dist/analyzers/rails/rails-react-analyzer.d.ts +0 -41
  45. package/dist/analyzers/rails/rails-react-analyzer.js +0 -529
  46. package/dist/analyzers/rails/rails-routes-analyzer.d.ts +0 -62
  47. package/dist/analyzers/rails/rails-routes-analyzer.js +0 -540
  48. package/dist/analyzers/rails/rails-view-analyzer.d.ts +0 -49
  49. package/dist/analyzers/rails/rails-view-analyzer.js +0 -386
  50. package/dist/analyzers/rails/ruby-parser.d.ts +0 -63
  51. package/dist/analyzers/rails/ruby-parser.js +0 -212
  52. package/dist/analyzers/rest-api-analyzer.d.ts +0 -65
  53. package/dist/analyzers/rest-api-analyzer.js +0 -479
  54. package/dist/core/cache.d.ts +0 -47
  55. package/dist/core/cache.js +0 -151
  56. package/dist/core/engine.d.ts +0 -46
  57. package/dist/core/engine.js +0 -319
  58. package/dist/core/index.d.ts +0 -2
  59. package/dist/core/index.js +0 -2
  60. package/dist/generators/markdown-generator.d.ts +0 -25
  61. package/dist/generators/markdown-generator.js +0 -782
  62. package/dist/generators/mermaid-generator.d.ts +0 -35
  63. package/dist/generators/mermaid-generator.js +0 -364
  64. package/dist/generators/page-map-generator.d.ts +0 -22
  65. package/dist/generators/rails-map-generator.d.ts +0 -21
  66. package/dist/server/doc-server.d.ts +0 -30
  67. package/dist/utils/env-detector.d.ts +0 -31
  68. package/dist/utils/env-detector.js +0 -188
  69. package/dist/utils/parallel.d.ts +0 -23
  70. package/dist/utils/parallel.js +0 -70
  71. package/dist/utils/port.d.ts +0 -15
  72. package/dist/utils/port.js +0 -41
package/dist/cli.js CHANGED
@@ -1,378 +1,35 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import chalk from 'chalk';
4
- import * as path from 'path';
5
- import * as fs from 'fs/promises';
6
- import { DocGeneratorEngine } from './core/engine.js';
7
- import { DocServer } from './server/doc-server.js';
8
- const program = new Command();
9
- program
10
- .name('repomap')
11
- .description('Interactive documentation generator for code repositories')
12
- .version('0.1.0');
13
- /**
14
- * Auto-detect project type and settings
15
- */
16
- async function detectProject(dir) {
17
- const dirName = path.basename(dir);
18
- let isRails = false;
19
- // Check for Rails project first
20
- const gemfilePath = path.join(dir, 'Gemfile');
21
- const routesPath = path.join(dir, 'config', 'routes.rb');
22
- try {
23
- await fs.access(gemfilePath);
24
- await fs.access(routesPath);
25
- // This is a Rails project
26
- const gemfile = await fs.readFile(gemfilePath, 'utf-8');
27
- isRails = gemfile.includes("gem 'rails'") || gemfile.includes('gem "rails"');
28
- }
29
- catch {
30
- // Not a Rails project, continue checking
31
- }
32
- const packageJsonPath = path.join(dir, 'package.json');
33
- let hasReact = false;
34
- let hasNextjs = false;
35
- const settings = {};
36
- try {
37
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
38
- // Detect project type
39
- const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
40
- hasReact = !!deps['react'];
41
- hasNextjs = !!deps['next'];
42
- // Check common Next.js structures
43
- const possiblePagesDirs = ['src/pages', 'pages', 'app', 'src/app', 'frontend/src'];
44
- for (const pagesDir of possiblePagesDirs) {
45
- try {
46
- await fs.access(path.join(dir, pagesDir));
47
- settings.pagesDir = pagesDir;
48
- break;
49
- }
50
- catch { }
51
- }
52
- // Check for features directory
53
- const possibleFeaturesDirs = [
54
- 'src/features',
55
- 'features',
56
- 'src/modules',
57
- 'modules',
58
- 'frontend/src',
59
- ];
60
- for (const featuresDir of possibleFeaturesDirs) {
61
- try {
62
- await fs.access(path.join(dir, featuresDir));
63
- settings.featuresDir = featuresDir;
64
- break;
65
- }
66
- catch { }
67
- }
68
- // Check for components directory
69
- const possibleComponentsDirs = [
70
- 'src/components',
71
- 'components',
72
- 'src/common/components',
73
- 'frontend/src',
74
- ];
75
- for (const componentsDir of possibleComponentsDirs) {
76
- try {
77
- await fs.access(path.join(dir, componentsDir));
78
- settings.componentsDir = componentsDir;
79
- break;
80
- }
81
- catch { }
82
- }
83
- }
84
- catch {
85
- // No package.json
86
- }
87
- // Build analyzers list based on detected environments
88
- const analyzers = [];
89
- // Add frontend analyzers if React/Next.js detected
90
- if (hasReact || hasNextjs) {
91
- analyzers.push('pages', 'graphql', 'dataflow', 'rest-api');
92
- }
93
- // Rails analyzers are handled separately via Rails analysis
94
- // Determine project type
95
- let type = 'generic';
96
- if (hasNextjs) {
97
- type = 'nextjs';
98
- }
99
- else if (isRails) {
100
- type = 'rails';
101
- }
102
- // If nothing detected, return null
103
- if (!isRails && !hasReact && !hasNextjs) {
104
- return null;
105
- }
106
- return {
107
- name: dirName,
108
- displayName: dirName,
109
- description: isRails && hasReact ? 'Rails + React application' : isRails ? 'Rails application' : '',
110
- path: dir,
111
- branch: 'main',
112
- type,
113
- analyzers,
114
- settings,
115
- };
116
- }
117
- /**
118
- * Create default config for current directory
119
- */
120
- async function createDefaultConfig(cwd) {
121
- const project = await detectProject(cwd);
122
- if (!project) {
123
- throw new Error("Could not detect project. Please create a repomap.config.ts file or run 'repomap init'.");
124
- }
125
- return {
126
- outputDir: './.repomap',
127
- site: {
128
- title: `${project.displayName} Documentation`,
129
- description: 'Auto-generated documentation',
130
- baseUrl: '/docs',
131
- },
132
- repositories: [project],
133
- analysis: {
134
- include: ['**/*.tsx', '**/*.ts'],
135
- exclude: [
136
- '**/node_modules/**',
137
- '**/__tests__/**',
138
- '**/*.test.*',
139
- '**/*.spec.*',
140
- '**/dist/**',
141
- '**/.next/**',
142
- ],
143
- maxDepth: 5,
144
- },
145
- diagrams: {
146
- enabled: true,
147
- types: ['flowchart', 'sequence'],
148
- theme: 'default',
149
- },
150
- watch: {
151
- enabled: false,
152
- debounce: 1000,
153
- },
154
- integrations: {
155
- github: { enabled: false, organization: '' },
156
- slack: { enabled: false },
157
- },
158
- };
159
- }
160
- /**
161
- * Load config from file or auto-detect
162
- */
163
- async function loadConfig(configPath, cwd) {
164
- // Try to load config file
165
- const configFiles = configPath
166
- ? [configPath]
167
- : ['repomap.config.ts', 'repomap.config.js', 'repomap.config.mjs'];
168
- for (const file of configFiles) {
169
- const fullPath = path.resolve(cwd, file);
170
- try {
171
- await fs.access(fullPath);
172
- console.log(chalk.gray(`Loading config from: ${fullPath}`));
173
- const module = await import(fullPath);
174
- return module.config || module.default;
175
- }
176
- catch { }
177
- }
178
- // No config file, auto-detect
179
- console.log(chalk.gray('No config file found, auto-detecting project...'));
180
- return createDefaultConfig(cwd);
181
- }
182
- /**
183
- * Generate command - generates documentation
184
- */
185
- program
186
- .command('generate')
187
- .description('Generate documentation from source code')
188
- .option('-c, --config <path>', 'Path to config file')
189
- .option('-o, --output <path>', 'Output directory')
190
- .option('--repo <name>', 'Analyze specific repository only')
191
- .option('--watch', 'Watch for changes and regenerate')
192
- .option('--no-cache', 'Disable caching (always analyze from scratch)')
193
- .option('--format <type>', 'Output format: json, html, markdown (default: all)', 'all')
194
- .option('--ci', 'CI mode: minimal output, exit codes for errors')
195
- .option('--static', 'Generate standalone HTML files (for GitHub Pages)')
196
- .action(async (options) => {
197
- const isCI = options.ci || process.env.CI === 'true';
198
- if (!isCI) {
199
- console.log(chalk.blue.bold('\n📚 Repomap - Documentation Generator\n'));
200
- }
201
- try {
202
- const cwd = process.cwd();
203
- const config = await loadConfig(options.config, cwd);
204
- // Override output if specified
205
- if (options.output) {
206
- config.outputDir = options.output;
207
- }
208
- // Filter repositories if specified
209
- if (options.repo) {
210
- config.repositories = config.repositories.filter((r) => r.name === options.repo);
211
- if (config.repositories.length === 0) {
212
- console.error(chalk.red(`Repository "${options.repo}" not found in config`));
213
- process.exit(1);
214
- }
215
- }
216
- // Create engine and generate
217
- const engine = new DocGeneratorEngine(config, { noCache: !options.cache });
218
- if (options.watch) {
219
- console.log(chalk.yellow('\n👀 Watch mode enabled. Press Ctrl+C to stop.\n'));
220
- await watchAndGenerate(engine, config);
221
- }
222
- else {
223
- const report = await engine.generate();
224
- // Handle different output formats
225
- if (options.format === 'json' || options.static) {
226
- const jsonPath = path.join(config.outputDir, 'report.json');
227
- await fs.mkdir(config.outputDir, { recursive: true });
228
- await fs.writeFile(jsonPath, JSON.stringify(report, null, 2));
229
- if (!isCI)
230
- console.log(chalk.green(`📄 JSON report: ${jsonPath}`));
231
- }
232
- // Generate static HTML files for GitHub Pages
233
- if (options.static) {
234
- await generateStaticSite(config, report, isCI);
235
- }
236
- if (!isCI) {
237
- printSummary(report);
238
- }
239
- else {
240
- // CI mode: minimal output
241
- const totalPages = report.repositories.reduce((sum, r) => sum + r.summary.totalPages, 0);
242
- console.log(`✅ Generated: ${totalPages} pages, ${report.repositories.length} repos`);
243
- }
244
- }
245
- }
246
- catch (error) {
247
- console.error(isCI ? `Error: ${error.message}` : chalk.red('\n❌ Error:'), error.message);
248
- process.exit(1);
249
- }
250
- });
251
- /**
252
- * Generate static HTML site for GitHub Pages deployment
253
- */
254
- async function generateStaticSite(config, report, isCI) {
255
- const { PageMapGenerator } = await import('./generators/page-map-generator.js');
256
- const { detectEnvironments } = await import('./utils/env-detector.js');
257
- const outputDir = config.outputDir;
258
- await fs.mkdir(outputDir, { recursive: true });
259
- // Detect environment for Rails support
260
- const rootPath = config.repositories[0]?.path || process.cwd();
261
- const envResult = await detectEnvironments(rootPath);
262
- let railsAnalysis = null;
263
- if (envResult.hasRails) {
264
- const { analyzeRailsApp } = await import('./analyzers/rails/index.js');
265
- railsAnalysis = await analyzeRailsApp(rootPath);
266
- }
267
- // Generate page-map.html
268
- const pageMapGenerator = new PageMapGenerator();
269
- const pageMapHtml = pageMapGenerator.generatePageMapHtml(report, {
270
- envResult,
271
- railsAnalysis,
272
- staticMode: true,
273
- });
274
- await fs.writeFile(path.join(outputDir, 'index.html'), pageMapHtml);
275
- if (!isCI)
276
- console.log(chalk.green(`📄 Static page map: ${path.join(outputDir, 'index.html')}`));
277
- // Generate rails-map.html if Rails detected
278
- if (railsAnalysis) {
279
- const { RailsMapGenerator } = await import('./generators/rails-map-generator.js');
280
- const railsGenerator = new RailsMapGenerator();
281
- const railsHtml = railsGenerator.generateFromResult(railsAnalysis);
282
- await fs.writeFile(path.join(outputDir, 'rails-map.html'), railsHtml);
283
- if (!isCI)
284
- console.log(chalk.green(`📄 Static Rails map: ${path.join(outputDir, 'rails-map.html')}`));
285
- }
286
- // Copy CSS assets
287
- const cssFiles = ['common.css', 'page-map.css', 'docs.css', 'rails-map.css'];
288
- const assetsDir = path.join(outputDir, 'assets');
289
- await fs.mkdir(assetsDir, { recursive: true });
290
- for (const cssFile of cssFiles) {
291
- try {
292
- const cssPath = new URL(`./generators/assets/${cssFile}`, import.meta.url);
293
- const css = await fs.readFile(cssPath, 'utf-8');
294
- await fs.writeFile(path.join(assetsDir, cssFile), css);
295
- }
296
- catch {
297
- // CSS file not found, skip
298
- }
299
- }
300
- if (!isCI) {
301
- console.log(chalk.green(`\n✅ Static site generated in: ${outputDir}`));
302
- console.log(chalk.gray(' Deploy to GitHub Pages or any static hosting'));
303
- }
304
- }
305
- /**
306
- * Serve command - starts documentation server
307
- */
308
- program
309
- .command('serve')
310
- .description('Start local documentation server with live reload')
311
- .option('-c, --config <path>', 'Path to config file')
312
- .option('--path <path>', 'Path to repository to analyze (auto-detect if no config)')
313
- .option('-p, --port <number>', 'Server port', '3030')
314
- .option('--no-open', "Don't open browser automatically")
315
- .option('--no-cache', 'Disable caching (always analyze from scratch)')
316
- .action(async (options) => {
317
- console.log(chalk.blue.bold('\n🌐 Repomap - Documentation Server\n'));
318
- try {
319
- const targetPath = options.path || process.cwd();
320
- const config = await loadConfig(options.config, targetPath);
321
- const server = new DocServer(config, parseInt(options.port), { noCache: !options.cache });
322
- await server.start(!options.open);
323
- }
324
- catch (error) {
325
- console.error(chalk.red('\n❌ Error:'), error.message);
326
- process.exit(1);
327
- }
328
- });
329
- /**
330
- * Init command - creates config file
331
- */
332
- program
333
- .command('init')
334
- .description('Initialize repomap configuration')
335
- .option('-f, --force', 'Overwrite existing config')
336
- .action(async (options) => {
337
- const configPath = './repomap.config.ts';
338
- try {
339
- const exists = await fs
340
- .access(configPath)
341
- .then(() => true)
342
- .catch(() => false);
343
- if (exists && !options.force) {
344
- console.log(chalk.yellow('Config file already exists. Use --force to overwrite.'));
345
- return;
346
- }
347
- // Detect current project
348
- const project = await detectProject(process.cwd());
349
- const projectName = project?.name || 'my-project';
350
- const projectType = project?.type || 'nextjs';
351
- const pagesDir = project?.settings.pagesDir || 'src/pages';
352
- const featuresDir = project?.settings.featuresDir || 'src/features';
353
- const componentsDir = project?.settings.componentsDir || 'src/components';
354
- const templateConfig = `import type { DocGeneratorConfig } from "repomap";
2
+ import {a,b}from'./chunk-4K4MGTPV.js';import'./chunk-SL2GMDBN.js';import'./chunk-VV3A3UE3.js';import'./chunk-J2CM7T7U.js';import'./chunk-XWZH2RDG.js';import'./chunk-MOEA75XK.js';import'./chunk-UJT5KTVK.js';import {Command}from'commander';import n from'chalk';import*as p from'path';import*as s from'fs/promises';var d=new Command;d.name("repomap").description("Interactive documentation generator for code repositories").version("0.1.0");async function $(e){let o=p.basename(e),a=false,t=p.join(e,"Gemfile"),c=p.join(e,"config","routes.rb");try{await s.access(t),await s.access(c);let u=await s.readFile(t,"utf-8");a=u.includes("gem 'rails'")||u.includes('gem "rails"');}catch{}let r=p.join(e,"package.json"),i=false,l=false,m={};try{let u=JSON.parse(await s.readFile(r,"utf-8")),w={...u.dependencies,...u.devDependencies};i=!!w.react,l=!!w.next;let f=["src/pages","pages","app","src/app","frontend/src"];for(let g of f)try{await s.access(p.join(e,g)),m.pagesDir=g;break}catch{}let b=["src/features","features","src/modules","modules","frontend/src"];for(let g of b)try{await s.access(p.join(e,g)),m.featuresDir=g;break}catch{}let D=["src/components","components","src/common/components","frontend/src"];for(let g of D)try{await s.access(p.join(e,g)),m.componentsDir=g;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:o,displayName:o,description:a&&i?"Rails + React application":a?"Rails application":"",path:e,branch:"main",type:y,analyzers:h,settings:m}}async function x(e){let o=await $(e);if(!o)throw new Error("Could not detect project. Please create a repomap.config.ts file or run 'repomap init'.");return {outputDir:"./.repomap",site:{title:`${o.displayName} Documentation`,description:"Auto-generated documentation",baseUrl:"/docs"},repositories:[o],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,o){let a=e?[e]:["repomap.config.ts","repomap.config.js","repomap.config.mjs"];for(let t of a){let c=p.resolve(o,t);try{await s.access(c),console.log(n.gray(`Loading config from: ${c}`));let r=await import(c);return r.config||r.default}catch{}}return console.log(n.gray("No config file found, auto-detecting project...")),x(o)}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("--no-cache","Disable caching (always analyze from scratch)").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 o=e.ci||process.env.CI==="true";o||console.log(n.blue.bold(`
3
+ \u{1F4DA} Repomap - Documentation Generator
4
+ `));try{let a$1=process.cwd(),t=await P(e.config,a$1);e.output&&(t.outputDir=e.output),e.repo&&(t.repositories=t.repositories.filter(r=>r.name===e.repo),t.repositories.length===0&&(console.error(n.red(`Repository "${e.repo}" not found in config`)),process.exit(1)));let c=new a(t,{noCache:!e.cache});if(e.watch)console.log(n.yellow(`
5
+ \u{1F440} Watch mode enabled. Press Ctrl+C to stop.
6
+ `)),await C(c,t);else {let r=await c.generate();if(e.format==="json"||e.static){let i=p.join(t.outputDir,"report.json");await s.mkdir(t.outputDir,{recursive:!0}),await s.writeFile(i,JSON.stringify(r,null,2)),o||console.log(n.green(`\u{1F4C4} JSON report: ${i}`));}if(e.static&&await G(t,r,o),!o)N(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(o?`Error: ${a.message}`:n.red(`
7
+ \u274C Error:`),a.message),process.exit(1);}});async function G(e,o,a){let{PageMapGenerator:t}=await import('./page-map-generator-XNZ4TDJT.js'),{detectEnvironments:c}=await import('./env-detector-BIWJ7OYF.js'),r=e.outputDir;await s.mkdir(r,{recursive:true});let i=e.repositories[0]?.path||process.cwd(),l=await c(i),m=null;if(l.hasRails){let{analyzeRailsApp:f}=await import('./rails-TJCDGBBF.js');m=await f(i);}let y=new t().generatePageMapHtml(o,{envResult:l,railsAnalysis:m,staticMode:true});if(await s.writeFile(p.join(r,"index.html"),y),a||console.log(n.green(`\u{1F4C4} Static page map: ${p.join(r,"index.html")}`)),m){let{RailsMapGenerator:f}=await import('./rails-map-generator-JL5PKHYP.js'),D=new f().generateFromResult(m);await s.writeFile(p.join(r,"rails-map.html"),D),a||console.log(n.green(`\u{1F4C4} Static Rails map: ${p.join(r,"rails-map.html")}`));}let u=["common.css","page-map.css","docs.css","rails-map.css"],w=p.join(r,"assets");await s.mkdir(w,{recursive:true});for(let f of u)try{let b=new URL(`./generators/assets/${f}`,import.meta.url),D=await s.readFile(b,"utf-8");await s.writeFile(p.join(w,f),D);}catch{}a||(console.log(n.green(`
8
+ \u2705 Static site generated in: ${r}`)),console.log(n.gray(" Deploy to GitHub Pages or any static hosting")));}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").option("--no-cache","Disable caching (always analyze from scratch)").action(async e=>{console.log(n.blue.bold(`
9
+ \u{1F310} Repomap - Documentation Server
10
+ `));try{let o=e.path||process.cwd(),a=await P(e.config,o);await new b(a,parseInt(e.port),{noCache:!e.cache}).start(!e.open);}catch(o){console.error(n.red(`
11
+ \u274C Error:`),o.message),process.exit(1);}});d.command("init").description("Initialize repomap configuration").option("-f, --force","Overwrite existing config").action(async e=>{let o="./repomap.config.ts";try{if(await s.access(o).then(()=>!0).catch(()=>!1)&&!e.force){console.log(n.yellow("Config file already exists. Use --force to overwrite."));return}let t=await $(process.cwd()),c=t?.name||"my-project",r=t?.type||"nextjs",i=t?.settings.pagesDir||"src/pages",l=t?.settings.featuresDir||"src/features",m=t?.settings.componentsDir||"src/components",h=`import type { DocGeneratorConfig } from "repomap";
355
12
 
356
13
  export const config: DocGeneratorConfig = {
357
14
  outputDir: "./.repomap",
358
15
  site: {
359
- title: "${projectName} Documentation",
16
+ title: "${c} Documentation",
360
17
  description: "Auto-generated documentation",
361
18
  baseUrl: "/docs",
362
19
  },
363
20
  repositories: [
364
21
  {
365
- name: "${projectName}",
366
- displayName: "${projectName}",
22
+ name: "${c}",
23
+ displayName: "${c}",
367
24
  description: "Main repository",
368
25
  path: ".",
369
26
  branch: "main",
370
- type: "${projectType}",
27
+ type: "${r}",
371
28
  analyzers: ["pages", "graphql", "components", "dataflow"],
372
29
  settings: {
373
- pagesDir: "${pagesDir}",
374
- featuresDir: "${featuresDir}",
375
- componentsDir: "${componentsDir}",
30
+ pagesDir: "${i}",
31
+ featuresDir: "${l}",
32
+ componentsDir: "${m}",
376
33
  },
377
34
  },
378
35
  // Add more repositories for cross-repo analysis:
@@ -408,142 +65,15 @@ export const config: DocGeneratorConfig = {
408
65
  };
409
66
 
410
67
  export default config;
411
- `;
412
- await fs.writeFile(configPath, templateConfig, 'utf-8');
413
- console.log(chalk.green(`✅ Created ${configPath}`));
414
- console.log(chalk.gray("\nRun 'npx repomap serve' to start the documentation server."));
415
- }
416
- catch (error) {
417
- console.error(chalk.red('Failed to create config:'), error.message);
418
- }
419
- });
420
- /**
421
- * Rails command - analyze Rails application
422
- */
423
- program
424
- .command('rails')
425
- .description('Analyze a Rails application and generate interactive map')
426
- .option('--path <path>', 'Path to Rails application')
427
- .option('-o, --output <path>', 'Output HTML file path')
428
- .action(async (options) => {
429
- console.log(chalk.blue.bold('\n🛤️ Repomap - Rails Analyzer\n'));
430
- try {
431
- const targetPath = options.path || process.cwd();
432
- // Verify it's a Rails project
433
- try {
434
- await fs.access(path.join(targetPath, 'config', 'routes.rb'));
435
- }
436
- catch {
437
- console.error(chalk.red('Not a Rails project (config/routes.rb not found)'));
438
- process.exit(1);
439
- }
440
- // Dynamically import Rails analyzer
441
- const { RailsMapGenerator } = await import('./generators/rails-map-generator.js');
442
- // Generate map
443
- const outputPath = options.output || path.join(targetPath, 'rails-map.html');
444
- const generator = new RailsMapGenerator(targetPath);
445
- await generator.generate({
446
- title: `${path.basename(targetPath)} - Rails Map`,
447
- outputPath,
448
- });
449
- console.log(chalk.green(`\n✅ Rails map generated: ${outputPath}`));
450
- // Open in browser
451
- const { exec } = await import('child_process');
452
- exec(`open "${outputPath}"`);
453
- }
454
- catch (error) {
455
- console.error(chalk.red('\n❌ Error:'), error.message);
456
- process.exit(1);
457
- }
458
- });
459
- /**
460
- * Diff command - shows changes since last generation
461
- */
462
- program
463
- .command('diff')
464
- .description('Show documentation changes since last generation')
465
- .option('-c, --config <path>', 'Path to config file')
466
- .action(async (options) => {
467
- console.log(chalk.blue.bold('\n📊 Documentation Diff\n'));
468
- try {
469
- const cwd = process.cwd();
470
- const config = await loadConfig(options.config, cwd);
471
- const reportPath = path.join(config.outputDir, 'report.json');
472
- const reportExists = await fs
473
- .access(reportPath)
474
- .then(() => true)
475
- .catch(() => false);
476
- if (!reportExists) {
477
- console.log(chalk.yellow("No previous report found. Run 'generate' first."));
478
- return;
479
- }
480
- const previousReport = JSON.parse(await fs.readFile(reportPath, 'utf-8'));
481
- // Generate new report without writing
482
- const engine = new DocGeneratorEngine(config);
483
- const currentReport = await engine.generate();
484
- // Compare
485
- showDiff(previousReport, currentReport);
486
- }
487
- catch (error) {
488
- console.error(chalk.red('Failed to generate diff:'), error.message);
489
- }
490
- });
491
- // Helper functions
492
- async function watchAndGenerate(engine, config) {
493
- // Initial generation
494
- await engine.generate();
495
- // Watch for changes using fs.watch
496
- const watchDirs = config.repositories.map((r) => r.path);
497
- for (const dir of watchDirs) {
498
- const watcher = fs.watch(dir, { recursive: true });
499
- let timeout = null;
500
- for await (const event of watcher) {
501
- if (event.filename && (event.filename.endsWith('.ts') || event.filename.endsWith('.tsx'))) {
502
- if (timeout)
503
- clearTimeout(timeout);
504
- timeout = setTimeout(async () => {
505
- console.log(chalk.yellow(`\n🔄 Change detected: ${event.filename}`));
506
- await engine.generate();
507
- }, config.watch.debounce);
508
- }
509
- }
510
- }
511
- }
512
- function printSummary(report) {
513
- console.log(chalk.green.bold('\n📈 Generation Summary\n'));
514
- for (const repo of report.repositories) {
515
- console.log(chalk.cyan(` ${repo.displayName}:`));
516
- console.log(` Pages: ${repo.summary.totalPages}`);
517
- console.log(` Components: ${repo.summary.totalComponents}`);
518
- console.log(` GraphQL Operations: ${repo.summary.totalGraphQLOperations}`);
519
- console.log(` Data Flows: ${repo.summary.totalDataFlows}`);
520
- console.log();
521
- }
522
- console.log(chalk.gray(` Generated at: ${report.generatedAt}`));
523
- }
524
- function showDiff(previous, current) {
525
- console.log(chalk.cyan('Changes detected:\n'));
526
- for (const repo of current.repositories) {
527
- const prevRepo = previous.repositories.find((r) => r.name === repo.name);
528
- if (!prevRepo) {
529
- console.log(chalk.green(` + New repository: ${repo.displayName}`));
530
- continue;
531
- }
532
- const pagesDiff = repo.summary.totalPages - prevRepo.summary.totalPages;
533
- const compDiff = repo.summary.totalComponents - prevRepo.summary.totalComponents;
534
- const gqlDiff = repo.summary.totalGraphQLOperations - prevRepo.summary.totalGraphQLOperations;
535
- if (pagesDiff !== 0 || compDiff !== 0 || gqlDiff !== 0) {
536
- console.log(chalk.yellow(` ~ ${repo.displayName}:`));
537
- if (pagesDiff !== 0) {
538
- console.log(` Pages: ${pagesDiff > 0 ? '+' : ''}${pagesDiff}`);
539
- }
540
- if (compDiff !== 0) {
541
- console.log(` Components: ${compDiff > 0 ? '+' : ''}${compDiff}`);
542
- }
543
- if (gqlDiff !== 0) {
544
- console.log(` GraphQL Ops: ${gqlDiff > 0 ? '+' : ''}${gqlDiff}`);
545
- }
546
- }
547
- }
548
- }
549
- program.parse();
68
+ `;await s.writeFile(o,h,"utf-8"),console.log(n.green(`\u2705 Created ${o}`)),console.log(n.gray(`
69
+ Run 'npx repomap serve' to start the documentation server.`));}catch(a){console.error(n.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(n.blue.bold(`
70
+ \u{1F6E4}\uFE0F Repomap - Rails Analyzer
71
+ `));try{let o=e.path||process.cwd();try{await s.access(p.join(o,"config","routes.rb"));}catch{console.error(n.red("Not a Rails project (config/routes.rb not found)")),process.exit(1);}let{RailsMapGenerator:a}=await import('./rails-map-generator-JL5PKHYP.js'),t=e.output||p.join(o,"rails-map.html");await new a(o).generate({title:`${p.basename(o)} - Rails Map`,outputPath:t}),console.log(n.green(`
72
+ \u2705 Rails map generated: ${t}`));let{exec:r}=await import('child_process');r(`open "${t}"`);}catch(o){console.error(n.red(`
73
+ \u274C Error:`),o.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(n.blue.bold(`
74
+ \u{1F4CA} Documentation Diff
75
+ `));try{let o=process.cwd(),a$1=await P(e.config,o),t=p.join(a$1.outputDir,"report.json");if(!await s.access(t).then(()=>!0).catch(()=>!1)){console.log(n.yellow("No previous report found. Run 'generate' first."));return}let r=JSON.parse(await s.readFile(t,"utf-8")),l=await new a(a$1).generate();F(r,l);}catch(o){console.error(n.red("Failed to generate diff:"),o.message);}});async function C(e,o){await e.generate();let a=o.repositories.map(t=>t.path);for(let t of a){let c=s.watch(t,{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(n.yellow(`
76
+ \u{1F504} Change detected: ${i.filename}`)),await e.generate();},o.watch.debounce));}}function N(e){console.log(n.green.bold(`
77
+ \u{1F4C8} Generation Summary
78
+ `));for(let o of e.repositories)console.log(n.cyan(` ${o.displayName}:`)),console.log(` Pages: ${o.summary.totalPages}`),console.log(` Components: ${o.summary.totalComponents}`),console.log(` GraphQL Operations: ${o.summary.totalGraphQLOperations}`),console.log(` Data Flows: ${o.summary.totalDataFlows}`),console.log();console.log(n.gray(` Generated at: ${e.generatedAt}`));}function F(e,o){console.log(n.cyan(`Changes detected:
79
+ `));for(let a of o.repositories){let t=e.repositories.find(l=>l.name===a.name);if(!t){console.log(n.green(` + New repository: ${a.displayName}`));continue}let c=a.summary.totalPages-t.summary.totalPages,r=a.summary.totalComponents-t.summary.totalComponents,i=a.summary.totalGraphQLOperations-t.summary.totalGraphQLOperations;(c!==0||r!==0||i!==0)&&(console.log(n.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();