@girardmedia/bootspring 2.5.0 → 2.5.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 (59) hide show
  1. package/README.md +9 -403
  2. package/bin/bootspring.js +1 -96
  3. package/dist/cli/index.js +65134 -0
  4. package/dist/cli-launcher.js +92 -0
  5. package/dist/core/index.d.ts +2110 -5582
  6. package/dist/core/index.js +2 -0
  7. package/dist/core.js +21123 -5413
  8. package/dist/mcp/index.d.ts +357 -1
  9. package/dist/mcp/index.js +2 -0
  10. package/dist/mcp-server.js +51948 -1976
  11. package/package.json +27 -63
  12. package/scripts/postinstall.cjs +144 -0
  13. package/LICENSE +0 -29
  14. package/dist/cli/index.cjs +0 -20776
  15. package/generators/api-docs.js +0 -827
  16. package/generators/decisions.js +0 -655
  17. package/generators/generate.js +0 -595
  18. package/generators/health.js +0 -942
  19. package/generators/index.ts +0 -82
  20. package/generators/presets/full.js +0 -28
  21. package/generators/presets/index.js +0 -12
  22. package/generators/presets/minimal.js +0 -29
  23. package/generators/presets/standard.js +0 -28
  24. package/generators/questionnaire.js +0 -414
  25. package/generators/sections/advanced.js +0 -136
  26. package/generators/sections/ai.js +0 -106
  27. package/generators/sections/auth.js +0 -89
  28. package/generators/sections/backend.js +0 -146
  29. package/generators/sections/business.js +0 -118
  30. package/generators/sections/content.js +0 -300
  31. package/generators/sections/deployment.js +0 -139
  32. package/generators/sections/features.js +0 -122
  33. package/generators/sections/frontend.js +0 -118
  34. package/generators/sections/identity.js +0 -76
  35. package/generators/sections/index.js +0 -40
  36. package/generators/sections/instructions.js +0 -146
  37. package/generators/sections/payments.js +0 -104
  38. package/generators/sections/plugins.js +0 -142
  39. package/generators/sections/pre-build.js +0 -130
  40. package/generators/sections/security.js +0 -127
  41. package/generators/sections/technical.js +0 -171
  42. package/generators/sections/testing.js +0 -125
  43. package/generators/sections/workflow.js +0 -104
  44. package/generators/sprint.js +0 -675
  45. package/generators/templates/agents.template.js +0 -199
  46. package/generators/templates/assistant-context.template.js +0 -83
  47. package/generators/templates/build-planning.template.js +0 -708
  48. package/generators/templates/claude.template.js +0 -379
  49. package/generators/templates/content.template.js +0 -819
  50. package/generators/templates/index.js +0 -16
  51. package/generators/templates/planning.template.js +0 -515
  52. package/generators/templates/seed.template.js +0 -109
  53. package/generators/visual-doc-generator.js +0 -910
  54. package/scripts/postinstall.js +0 -197
  55. /package/{claude-commands → assets/claude-commands}/agent.md +0 -0
  56. /package/{claude-commands → assets/claude-commands}/bs.md +0 -0
  57. /package/{claude-commands → assets/claude-commands}/build.md +0 -0
  58. /package/{claude-commands → assets/claude-commands}/skill.md +0 -0
  59. /package/{claude-commands → assets/claude-commands}/todo.md +0 -0
@@ -1,910 +0,0 @@
1
- /**
2
- * Bootspring Visual Document Generator
3
- *
4
- * Generates visual documentation using Mermaid diagrams.
5
- * Creates architecture, data flow, dependency, and component diagrams.
6
- *
7
- * @package bootspring
8
- * @module generators/visual-doc-generator
9
- */
10
-
11
- const fs = require('fs');
12
- const path = require('path');
13
-
14
- /**
15
- * Diagram types supported by the generator
16
- */
17
- const DIAGRAM_TYPES = {
18
- architecture: 'flowchart',
19
- dataFlow: 'flowchart',
20
- dependencies: 'flowchart',
21
- components: 'flowchart',
22
- sequence: 'sequenceDiagram',
23
- state: 'stateDiagram-v2',
24
- entityRelation: 'erDiagram',
25
- classHierarchy: 'classDiagram',
26
- mindmap: 'mindmap',
27
- timeline: 'timeline'
28
- };
29
-
30
- /**
31
- * Default colors for diagram elements
32
- */
33
- const DIAGRAM_COLORS = {
34
- primary: '#4A90D9',
35
- secondary: '#50B83C',
36
- accent: '#F49342',
37
- warning: '#FFCC00',
38
- error: '#DE3618',
39
- neutral: '#637381',
40
- background: '#F4F6F8'
41
- };
42
-
43
- /**
44
- * Layer styling for architecture diagrams
45
- */
46
- const LAYER_STYLES = {
47
- presentation: { fill: '#E3F2FD', stroke: '#1976D2' },
48
- api: { fill: '#E8F5E9', stroke: '#388E3C' },
49
- service: { fill: '#FFF3E0', stroke: '#F57C00' },
50
- domain: { fill: '#FCE4EC', stroke: '#C2185B' },
51
- data: { fill: '#F3E5F5', stroke: '#7B1FA2' },
52
- infrastructure: { fill: '#ECEFF1', stroke: '#546E7A' }
53
- };
54
-
55
- /**
56
- * Visual Document Generator
57
- * Creates Mermaid diagrams from codebase analysis
58
- */
59
- class VisualDocGenerator {
60
- /**
61
- * Create a new VisualDocGenerator
62
- * @param {object} options - Configuration options
63
- * @param {string} options.projectRoot - Project root directory
64
- * @param {string} options.outputDir - Output directory for diagrams
65
- * @param {string} options.theme - Mermaid theme (default, forest, dark, neutral)
66
- */
67
- constructor(options = {}) {
68
- this.projectRoot = options.projectRoot || process.cwd();
69
- this.outputDir = options.outputDir || path.join(this.projectRoot, 'docs', 'diagrams');
70
- this.theme = options.theme || 'default';
71
- this.includeStyles = options.includeStyles !== false;
72
- }
73
-
74
- /**
75
- * Generate architecture diagram from analysis
76
- * @param {object} analysis - Architecture analysis data
77
- * @returns {string} Mermaid diagram code
78
- */
79
- generateArchitectureDiagram(analysis) {
80
- const lines = ['flowchart TB'];
81
-
82
- // Add theme directive
83
- lines.unshift(`%%{init: {'theme': '${this.theme}'}}%%`);
84
-
85
- // Add subgraphs for each layer
86
- const layers = analysis.layers || this.detectLayers(analysis);
87
-
88
- for (const [layerName, components] of Object.entries(layers)) {
89
- if (components && components.length > 0) {
90
- const style = LAYER_STYLES[layerName] || LAYER_STYLES.neutral;
91
- lines.push(` subgraph ${this.sanitizeId(layerName)}["${this.formatLayerName(layerName)}"]`);
92
-
93
- for (const component of components) {
94
- const nodeId = this.sanitizeId(component.name || component);
95
- const nodeName = component.name || component;
96
- lines.push(` ${nodeId}["${nodeName}"]`);
97
- }
98
-
99
- lines.push(' end');
100
- lines.push('');
101
- }
102
- }
103
-
104
- // Add connections between layers
105
- const connections = analysis.connections || this.inferConnections(layers);
106
- for (const conn of connections) {
107
- const fromId = this.sanitizeId(conn.from);
108
- const toId = this.sanitizeId(conn.to);
109
- const label = conn.label ? `|"${conn.label}"|` : '';
110
- lines.push(` ${fromId} -->${label} ${toId}`);
111
- }
112
-
113
- // Add styling
114
- if (this.includeStyles) {
115
- lines.push('');
116
- for (const [layerName, style] of Object.entries(LAYER_STYLES)) {
117
- const layerId = this.sanitizeId(layerName);
118
- lines.push(` style ${layerId} fill:${style.fill},stroke:${style.stroke}`);
119
- }
120
- }
121
-
122
- return lines.join('\n');
123
- }
124
-
125
- /**
126
- * Generate data flow diagram
127
- * @param {object} analysis - Data flow analysis
128
- * @returns {string} Mermaid diagram code
129
- */
130
- generateDataFlowDiagram(analysis) {
131
- const lines = [
132
- `%%{init: {'theme': '${this.theme}'}}%%`,
133
- 'flowchart LR'
134
- ];
135
-
136
- // Add data sources
137
- if (analysis.sources) {
138
- lines.push(' subgraph Sources["Data Sources"]');
139
- for (const source of analysis.sources) {
140
- const id = this.sanitizeId(source.name);
141
- lines.push(` ${id}[("${source.name}")]`);
142
- }
143
- lines.push(' end');
144
- lines.push('');
145
- }
146
-
147
- // Add processors
148
- if (analysis.processors) {
149
- lines.push(' subgraph Processors["Data Processors"]');
150
- for (const proc of analysis.processors) {
151
- const id = this.sanitizeId(proc.name);
152
- lines.push(` ${id}["${proc.name}"]`);
153
- }
154
- lines.push(' end');
155
- lines.push('');
156
- }
157
-
158
- // Add outputs
159
- if (analysis.outputs) {
160
- lines.push(' subgraph Outputs["Data Outputs"]');
161
- for (const output of analysis.outputs) {
162
- const id = this.sanitizeId(output.name);
163
- const shape = output.type === 'api' ? `{{"${output.name}"}}` : `>"${output.name}"]`;
164
- lines.push(` ${id}${shape}`);
165
- }
166
- lines.push(' end');
167
- lines.push('');
168
- }
169
-
170
- // Add flows
171
- if (analysis.flows) {
172
- for (const flow of analysis.flows) {
173
- const fromId = this.sanitizeId(flow.from);
174
- const toId = this.sanitizeId(flow.to);
175
- const arrow = flow.async ? '-.->' : '-->';
176
- const label = flow.data ? `|"${flow.data}"|` : '';
177
- lines.push(` ${fromId} ${arrow}${label} ${toId}`);
178
- }
179
- }
180
-
181
- return lines.join('\n');
182
- }
183
-
184
- /**
185
- * Generate dependency diagram
186
- * @param {object} analysis - Dependency analysis
187
- * @returns {string} Mermaid diagram code
188
- */
189
- generateDependencyDiagram(analysis) {
190
- const lines = [
191
- `%%{init: {'theme': '${this.theme}'}}%%`,
192
- 'flowchart TD'
193
- ];
194
-
195
- // Group modules by type
196
- const moduleGroups = this.groupModulesByType(analysis.modules || []);
197
-
198
- for (const [groupName, modules] of Object.entries(moduleGroups)) {
199
- if (modules.length > 0) {
200
- lines.push(` subgraph ${this.sanitizeId(groupName)}["${groupName}"]`);
201
-
202
- for (const mod of modules) {
203
- const id = this.sanitizeId(mod.name);
204
- const shape = mod.external ? `(("${mod.name}"))` : `["${mod.name}"]`;
205
- lines.push(` ${id}${shape}`);
206
- }
207
-
208
- lines.push(' end');
209
- lines.push('');
210
- }
211
- }
212
-
213
- // Add dependencies
214
- if (analysis.dependencies) {
215
- for (const dep of analysis.dependencies) {
216
- const fromId = this.sanitizeId(dep.from);
217
- const toId = this.sanitizeId(dep.to);
218
- const style = dep.devOnly ? '-.->' : '-->';
219
- lines.push(` ${fromId} ${style} ${toId}`);
220
- }
221
- }
222
-
223
- // Highlight circular dependencies
224
- if (analysis.circular && analysis.circular.length > 0) {
225
- lines.push('');
226
- lines.push(' %% Circular Dependencies (highlighted in red)');
227
- for (const circular of analysis.circular) {
228
- const id1 = this.sanitizeId(circular[0]);
229
- const id2 = this.sanitizeId(circular[1]);
230
- lines.push(` ${id1} <--> ${id2}`);
231
- lines.push(` linkStyle ${lines.length - 2} stroke:red,stroke-width:2px`);
232
- }
233
- }
234
-
235
- return lines.join('\n');
236
- }
237
-
238
- /**
239
- * Generate component diagram
240
- * @param {object} analysis - Component analysis
241
- * @returns {string} Mermaid diagram code
242
- */
243
- generateComponentDiagram(analysis) {
244
- const lines = [
245
- `%%{init: {'theme': '${this.theme}'}}%%`,
246
- 'flowchart TB'
247
- ];
248
-
249
- // Add components by category
250
- const categories = analysis.categories || { components: analysis.components || [] };
251
-
252
- for (const [category, components] of Object.entries(categories)) {
253
- if (components && components.length > 0) {
254
- lines.push(` subgraph ${this.sanitizeId(category)}["${this.formatCategoryName(category)}"]`);
255
-
256
- for (const comp of components) {
257
- const id = this.sanitizeId(comp.name);
258
- const props = comp.props ? ` (${comp.props.join(', ')})` : '';
259
- lines.push(` ${id}["${comp.name}${props}"]`);
260
- }
261
-
262
- lines.push(' end');
263
- lines.push('');
264
- }
265
- }
266
-
267
- // Add component relationships
268
- if (analysis.relationships) {
269
- for (const rel of analysis.relationships) {
270
- const parentId = this.sanitizeId(rel.parent);
271
- const childId = this.sanitizeId(rel.child);
272
- const label = rel.type ? `|"${rel.type}"|` : '';
273
- lines.push(` ${parentId} -->${label} ${childId}`);
274
- }
275
- }
276
-
277
- return lines.join('\n');
278
- }
279
-
280
- /**
281
- * Generate sequence diagram
282
- * @param {object} analysis - Sequence analysis
283
- * @returns {string} Mermaid diagram code
284
- */
285
- generateSequenceDiagram(analysis) {
286
- const lines = [
287
- `%%{init: {'theme': '${this.theme}'}}%%`,
288
- 'sequenceDiagram'
289
- ];
290
-
291
- // Add participants
292
- if (analysis.participants) {
293
- for (const participant of analysis.participants) {
294
- const type = participant.type === 'actor' ? 'actor' : 'participant';
295
- lines.push(` ${type} ${participant.name}`);
296
- }
297
- lines.push('');
298
- }
299
-
300
- // Add messages
301
- if (analysis.messages) {
302
- for (const msg of analysis.messages) {
303
- const arrow = this.getSequenceArrow(msg.type);
304
- lines.push(` ${msg.from}${arrow}${msg.to}: ${msg.message}`);
305
-
306
- // Add notes if present
307
- if (msg.note) {
308
- lines.push(` Note over ${msg.from},${msg.to}: ${msg.note}`);
309
- }
310
- }
311
- }
312
-
313
- // Add loops/conditions
314
- if (analysis.blocks) {
315
- for (const block of analysis.blocks) {
316
- if (block.type === 'loop') {
317
- lines.push(` loop ${block.condition}`);
318
- } else if (block.type === 'alt') {
319
- lines.push(` alt ${block.condition}`);
320
- } else if (block.type === 'opt') {
321
- lines.push(` opt ${block.condition}`);
322
- }
323
-
324
- for (const msg of block.messages || []) {
325
- const arrow = this.getSequenceArrow(msg.type);
326
- lines.push(` ${msg.from}${arrow}${msg.to}: ${msg.message}`);
327
- }
328
-
329
- lines.push(' end');
330
- }
331
- }
332
-
333
- return lines.join('\n');
334
- }
335
-
336
- /**
337
- * Generate entity-relationship diagram
338
- * @param {object} analysis - Entity analysis (database schema)
339
- * @returns {string} Mermaid diagram code
340
- */
341
- generateERDiagram(analysis) {
342
- const lines = [
343
- `%%{init: {'theme': '${this.theme}'}}%%`,
344
- 'erDiagram'
345
- ];
346
-
347
- // Add entities
348
- if (analysis.entities) {
349
- for (const entity of analysis.entities) {
350
- lines.push(` ${entity.name} {`);
351
-
352
- for (const field of entity.fields || []) {
353
- const pk = field.primaryKey ? ' PK' : '';
354
- const fk = field.foreignKey ? ' FK' : '';
355
- lines.push(` ${field.type} ${field.name}${pk}${fk}`);
356
- }
357
-
358
- lines.push(' }');
359
- lines.push('');
360
- }
361
- }
362
-
363
- // Add relationships
364
- if (analysis.relationships) {
365
- for (const rel of analysis.relationships) {
366
- const cardinality = this.getERCardinality(rel.type);
367
- const label = rel.label ? ` : "${rel.label}"` : '';
368
- lines.push(` ${rel.from} ${cardinality} ${rel.to}${label}`);
369
- }
370
- }
371
-
372
- return lines.join('\n');
373
- }
374
-
375
- /**
376
- * Generate class diagram
377
- * @param {object} analysis - Class hierarchy analysis
378
- * @returns {string} Mermaid diagram code
379
- */
380
- generateClassDiagram(analysis) {
381
- const lines = [
382
- `%%{init: {'theme': '${this.theme}'}}%%`,
383
- 'classDiagram'
384
- ];
385
-
386
- // Add classes
387
- if (analysis.classes) {
388
- for (const cls of analysis.classes) {
389
- lines.push(` class ${cls.name} {`);
390
-
391
- // Add attributes
392
- for (const attr of cls.attributes || []) {
393
- const visibility = this.getVisibilitySymbol(attr.visibility);
394
- lines.push(` ${visibility}${attr.type} ${attr.name}`);
395
- }
396
-
397
- // Add methods
398
- for (const method of cls.methods || []) {
399
- const visibility = this.getVisibilitySymbol(method.visibility);
400
- const params = method.params ? method.params.join(', ') : '';
401
- const returnType = method.returns ? ` ${method.returns}` : '';
402
- lines.push(` ${visibility}${method.name}(${params})${returnType}`);
403
- }
404
-
405
- lines.push(' }');
406
- lines.push('');
407
- }
408
- }
409
-
410
- // Add relationships
411
- if (analysis.relationships) {
412
- for (const rel of analysis.relationships) {
413
- const arrow = this.getClassRelationArrow(rel.type);
414
- const label = rel.label ? ` : ${rel.label}` : '';
415
- lines.push(` ${rel.from} ${arrow} ${rel.to}${label}`);
416
- }
417
- }
418
-
419
- // Add notes/annotations
420
- if (analysis.notes) {
421
- for (const note of analysis.notes) {
422
- lines.push(` note for ${note.class} "${note.text}"`);
423
- }
424
- }
425
-
426
- return lines.join('\n');
427
- }
428
-
429
- /**
430
- * Generate state diagram
431
- * @param {object} analysis - State machine analysis
432
- * @returns {string} Mermaid diagram code
433
- */
434
- generateStateDiagram(analysis) {
435
- const lines = [
436
- `%%{init: {'theme': '${this.theme}'}}%%`,
437
- 'stateDiagram-v2'
438
- ];
439
-
440
- // Add states
441
- if (analysis.states) {
442
- for (const state of analysis.states) {
443
- if (state.type === 'composite') {
444
- lines.push(` state ${state.name} {`);
445
- for (const substate of state.substates || []) {
446
- lines.push(` ${substate}`);
447
- }
448
- lines.push(' }');
449
- } else if (state.description) {
450
- lines.push(` state "${state.description}" as ${state.name}`);
451
- }
452
- }
453
- lines.push('');
454
- }
455
-
456
- // Add transitions
457
- if (analysis.transitions) {
458
- for (const trans of analysis.transitions) {
459
- const from = trans.from === 'initial' ? '[*]' : trans.from;
460
- const to = trans.to === 'final' ? '[*]' : trans.to;
461
- const label = trans.event ? ` : ${trans.event}` : '';
462
- lines.push(` ${from} --> ${to}${label}`);
463
- }
464
- }
465
-
466
- return lines.join('\n');
467
- }
468
-
469
- /**
470
- * Generate mindmap diagram
471
- * @param {object} analysis - Hierarchical concept analysis
472
- * @returns {string} Mermaid diagram code
473
- */
474
- generateMindmapDiagram(analysis) {
475
- const lines = [
476
- `%%{init: {'theme': '${this.theme}'}}%%`,
477
- 'mindmap'
478
- ];
479
-
480
- // Build tree structure
481
- if (analysis.root) {
482
- this.addMindmapNode(lines, analysis.root, 2);
483
- }
484
-
485
- return lines.join('\n');
486
- }
487
-
488
- /**
489
- * Add mindmap node recursively
490
- * @param {Array} lines - Output lines
491
- * @param {object} node - Node to add
492
- * @param {number} indent - Indentation level
493
- */
494
- addMindmapNode(lines, node, indent) {
495
- const spaces = ' '.repeat(indent);
496
- const shape = node.shape || '';
497
- const text = node.name || node;
498
-
499
- if (typeof text === 'string') {
500
- lines.push(`${spaces}${shape}${text}`);
501
- } else {
502
- lines.push(`${spaces}${shape}${text.name}`);
503
-
504
- if (text.children) {
505
- for (const child of text.children) {
506
- this.addMindmapNode(lines, child, indent + 2);
507
- }
508
- }
509
- }
510
- }
511
-
512
- /**
513
- * Generate timeline diagram
514
- * @param {object} analysis - Timeline data
515
- * @returns {string} Mermaid diagram code
516
- */
517
- generateTimelineDiagram(analysis) {
518
- const lines = [
519
- `%%{init: {'theme': '${this.theme}'}}%%`,
520
- 'timeline'
521
- ];
522
-
523
- // Add title
524
- if (analysis.title) {
525
- lines.push(` title ${analysis.title}`);
526
- }
527
-
528
- // Add sections/periods
529
- if (analysis.periods) {
530
- for (const period of analysis.periods) {
531
- lines.push(` section ${period.name}`);
532
-
533
- for (const event of period.events || []) {
534
- lines.push(` ${event.date} : ${event.description}`);
535
- }
536
- }
537
- }
538
-
539
- return lines.join('\n');
540
- }
541
-
542
- /**
543
- * Generate all diagrams from comprehensive analysis
544
- * @param {object} analysis - Full codebase analysis
545
- * @returns {object} Generated diagrams by type
546
- */
547
- generateAllDiagrams(analysis) {
548
- const diagrams = {};
549
-
550
- // Architecture diagram
551
- if (analysis.architecture) {
552
- diagrams.architecture = {
553
- type: 'architecture',
554
- title: 'System Architecture',
555
- code: this.generateArchitectureDiagram(analysis.architecture),
556
- filename: 'architecture.mmd'
557
- };
558
- }
559
-
560
- // Data flow diagram
561
- if (analysis.dataFlow) {
562
- diagrams.dataFlow = {
563
- type: 'dataFlow',
564
- title: 'Data Flow',
565
- code: this.generateDataFlowDiagram(analysis.dataFlow),
566
- filename: 'data-flow.mmd'
567
- };
568
- }
569
-
570
- // Dependency diagram
571
- if (analysis.dependencies) {
572
- diagrams.dependencies = {
573
- type: 'dependencies',
574
- title: 'Module Dependencies',
575
- code: this.generateDependencyDiagram(analysis.dependencies),
576
- filename: 'dependencies.mmd'
577
- };
578
- }
579
-
580
- // Component diagram
581
- if (analysis.components) {
582
- diagrams.components = {
583
- type: 'components',
584
- title: 'Component Hierarchy',
585
- code: this.generateComponentDiagram(analysis.components),
586
- filename: 'components.mmd'
587
- };
588
- }
589
-
590
- // ER diagram (if database schema present)
591
- if (analysis.database) {
592
- diagrams.database = {
593
- type: 'entityRelation',
594
- title: 'Database Schema',
595
- code: this.generateERDiagram(analysis.database),
596
- filename: 'database.mmd'
597
- };
598
- }
599
-
600
- // Class diagram (if class hierarchy present)
601
- if (analysis.classes) {
602
- diagrams.classes = {
603
- type: 'classHierarchy',
604
- title: 'Class Hierarchy',
605
- code: this.generateClassDiagram(analysis.classes),
606
- filename: 'classes.mmd'
607
- };
608
- }
609
-
610
- return diagrams;
611
- }
612
-
613
- /**
614
- * Save diagrams to files
615
- * @param {object} diagrams - Generated diagrams
616
- * @returns {Array<object>} Saved file information
617
- */
618
- saveDiagrams(diagrams) {
619
- // Ensure output directory exists
620
- if (!fs.existsSync(this.outputDir)) {
621
- fs.mkdirSync(this.outputDir, { recursive: true });
622
- }
623
-
624
- const saved = [];
625
-
626
- for (const [type, diagram] of Object.entries(diagrams)) {
627
- const filepath = path.join(this.outputDir, diagram.filename);
628
-
629
- // Add header comment
630
- const content = [
631
- `%% ${diagram.title}`,
632
- '%% Generated by Bootspring Visual Doc Generator',
633
- `%% ${new Date().toISOString()}`,
634
- '',
635
- diagram.code
636
- ].join('\n');
637
-
638
- fs.writeFileSync(filepath, content, 'utf8');
639
-
640
- saved.push({
641
- type,
642
- title: diagram.title,
643
- filepath,
644
- filename: diagram.filename,
645
- size: content.length
646
- });
647
- }
648
-
649
- return saved;
650
- }
651
-
652
- /**
653
- * Generate markdown documentation with embedded diagrams
654
- * @param {object} diagrams - Generated diagrams
655
- * @param {object} options - Documentation options
656
- * @returns {string} Markdown documentation
657
- */
658
- generateMarkdownDoc(diagrams, options = {}) {
659
- const title = options.title || 'Visual Documentation';
660
- const lines = [
661
- `# ${title}`,
662
- '',
663
- `Generated: ${new Date().toISOString()}`,
664
- '',
665
- '---',
666
- ''
667
- ];
668
-
669
- for (const [type, diagram] of Object.entries(diagrams)) {
670
- lines.push(`## ${diagram.title}`);
671
- lines.push('');
672
- lines.push('```mermaid');
673
- lines.push(diagram.code);
674
- lines.push('```');
675
- lines.push('');
676
- }
677
-
678
- return lines.join('\n');
679
- }
680
-
681
- // === Helper Methods ===
682
-
683
- /**
684
- * Sanitize string for use as Mermaid node ID
685
- * @param {string} str - String to sanitize
686
- * @returns {string} Sanitized ID
687
- */
688
- sanitizeId(str) {
689
- return str
690
- .replace(/[^a-zA-Z0-9_]/g, '_')
691
- .replace(/^_+|_+$/g, '')
692
- .replace(/_+/g, '_');
693
- }
694
-
695
- /**
696
- * Format layer name for display
697
- * @param {string} name - Layer name
698
- * @returns {string} Formatted name
699
- */
700
- formatLayerName(name) {
701
- return name.charAt(0).toUpperCase() + name.slice(1) + ' Layer';
702
- }
703
-
704
- /**
705
- * Format category name for display
706
- * @param {string} name - Category name
707
- * @returns {string} Formatted name
708
- */
709
- formatCategoryName(name) {
710
- return name
711
- .split(/[-_]/)
712
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
713
- .join(' ');
714
- }
715
-
716
- /**
717
- * Detect layers from analysis
718
- * @param {object} analysis - Analysis data
719
- * @returns {object} Detected layers
720
- */
721
- detectLayers(analysis) {
722
- const layers = {
723
- presentation: [],
724
- api: [],
725
- service: [],
726
- data: []
727
- };
728
-
729
- if (analysis.files) {
730
- for (const file of analysis.files) {
731
- const name = path.basename(file, path.extname(file));
732
-
733
- if (/component|page|view|ui/i.test(file)) {
734
- layers.presentation.push({ name });
735
- } else if (/api|route|endpoint|controller/i.test(file)) {
736
- layers.api.push({ name });
737
- } else if (/service|handler|manager/i.test(file)) {
738
- layers.service.push({ name });
739
- } else if (/model|schema|repository|database/i.test(file)) {
740
- layers.data.push({ name });
741
- }
742
- }
743
- }
744
-
745
- return layers;
746
- }
747
-
748
- /**
749
- * Infer connections between layers
750
- * @param {object} layers - Layer data
751
- * @returns {Array<object>} Inferred connections
752
- */
753
- inferConnections(layers) {
754
- const connections = [];
755
- const layerOrder = ['presentation', 'api', 'service', 'data'];
756
-
757
- for (let i = 0; i < layerOrder.length - 1; i++) {
758
- const currentLayer = layerOrder[i];
759
- const nextLayer = layerOrder[i + 1];
760
-
761
- if (layers[currentLayer]?.length > 0 && layers[nextLayer]?.length > 0) {
762
- connections.push({
763
- from: this.sanitizeId(currentLayer),
764
- to: this.sanitizeId(nextLayer)
765
- });
766
- }
767
- }
768
-
769
- return connections;
770
- }
771
-
772
- /**
773
- * Group modules by type
774
- * @param {Array} modules - Module list
775
- * @returns {object} Grouped modules
776
- */
777
- groupModulesByType(modules) {
778
- const groups = {
779
- 'Core Modules': [],
780
- 'External Dependencies': [],
781
- 'Dev Dependencies': [],
782
- 'Utilities': []
783
- };
784
-
785
- for (const mod of modules) {
786
- if (mod.external) {
787
- if (mod.devOnly) {
788
- groups['Dev Dependencies'].push(mod);
789
- } else {
790
- groups['External Dependencies'].push(mod);
791
- }
792
- } else if (/util|helper|lib/i.test(mod.name)) {
793
- groups['Utilities'].push(mod);
794
- } else {
795
- groups['Core Modules'].push(mod);
796
- }
797
- }
798
-
799
- return groups;
800
- }
801
-
802
- /**
803
- * Get sequence diagram arrow style
804
- * @param {string} type - Message type
805
- * @returns {string} Arrow string
806
- */
807
- getSequenceArrow(type) {
808
- switch (type) {
809
- case 'sync': return '->>';
810
- case 'async': return '->>+';
811
- case 'reply': return '-->>';
812
- case 'self': return '->>+';
813
- case 'create': return '->>+';
814
- case 'destroy': return '-x';
815
- default: return '->>';
816
- }
817
- }
818
-
819
- /**
820
- * Get ER diagram cardinality notation
821
- * @param {string} type - Relationship type
822
- * @returns {string} Cardinality string
823
- */
824
- getERCardinality(type) {
825
- switch (type) {
826
- case 'one-to-one': return '||--||';
827
- case 'one-to-many': return '||--o{';
828
- case 'many-to-one': return '}o--||';
829
- case 'many-to-many': return '}o--o{';
830
- case 'zero-or-one': return '|o--||';
831
- case 'zero-or-many': return '}o--||';
832
- default: return '||--||';
833
- }
834
- }
835
-
836
- /**
837
- * Get class diagram relationship arrow
838
- * @param {string} type - Relationship type
839
- * @returns {string} Arrow string
840
- */
841
- getClassRelationArrow(type) {
842
- switch (type) {
843
- case 'extends': return '<|--';
844
- case 'implements': return '<|..';
845
- case 'composition': return '*--';
846
- case 'aggregation': return 'o--';
847
- case 'association': return '-->';
848
- case 'dependency': return '..>';
849
- default: return '-->';
850
- }
851
- }
852
-
853
- /**
854
- * Get visibility symbol for class members
855
- * @param {string} visibility - Visibility level
856
- * @returns {string} Symbol
857
- */
858
- getVisibilitySymbol(visibility) {
859
- switch (visibility) {
860
- case 'public': return '+';
861
- case 'private': return '-';
862
- case 'protected': return '#';
863
- case 'package': return '~';
864
- default: return '+';
865
- }
866
- }
867
- }
868
-
869
- /**
870
- * Create a quick architecture diagram from simple config
871
- * @param {object} config - Simple architecture config
872
- * @returns {string} Mermaid diagram code
873
- */
874
- function quickArchitectureDiagram(config) {
875
- const generator = new VisualDocGenerator();
876
- return generator.generateArchitectureDiagram({
877
- layers: config.layers || {},
878
- connections: config.connections || []
879
- });
880
- }
881
-
882
- /**
883
- * Create a quick dependency diagram
884
- * @param {Array} modules - Module list with dependencies
885
- * @returns {string} Mermaid diagram code
886
- */
887
- function quickDependencyDiagram(modules) {
888
- const generator = new VisualDocGenerator();
889
-
890
- const dependencies = [];
891
- for (const mod of modules) {
892
- for (const dep of mod.dependencies || []) {
893
- dependencies.push({ from: mod.name, to: dep });
894
- }
895
- }
896
-
897
- return generator.generateDependencyDiagram({
898
- modules,
899
- dependencies
900
- });
901
- }
902
-
903
- module.exports = {
904
- VisualDocGenerator,
905
- quickArchitectureDiagram,
906
- quickDependencyDiagram,
907
- DIAGRAM_TYPES,
908
- DIAGRAM_COLORS,
909
- LAYER_STYLES
910
- };