Skip to content

feat: enhance Mermaid export with subgraphs, edge labels, node shapes and styling#97

Merged
carlos-alm merged 6 commits intomainfrom
feat/mermaid-subgraphs-styling
Feb 25, 2026
Merged

feat: enhance Mermaid export with subgraphs, edge labels, node shapes and styling#97
carlos-alm merged 6 commits intomainfrom
feat/mermaid-subgraphs-styling

Conversation

@carlos-alm
Copy link
Contributor

Summary

  • Changes graph LR to flowchart {direction} with a new --direction CLI option (default: LR)
  • Adds directory subgraph clustering in file-level mode (ported from the DOT export)
  • Adds edge labels from edge.kind (imports, calls), collapsing imports-type to imports
  • Adds node shapes by kind: stadium ([]) for functions/methods, hexagon {{}} for classes/structs/enums/etc, subroutine [[]] for modules
  • Groups function-level nodes by file into subgraphs
  • Adds role-based styling in function-level mode (entry=green, core=blue, utility=gray, dead=red, leaf=yellow)
  • Uses stable node IDs (n0, n1, ...) for cleaner output

Closes the gap between our Mermaid export and the DOT export, which already had subgraph clustering and edge metadata. Inspired by the rich Mermaid flowchart in PR #95's Greptile review.

Test plan

  • All 526 existing + new tests pass (npm test)
  • Lint clean (npm run lint)
  • Paste node src/cli.js export -f mermaid -T output into mermaid.live to confirm rendering
  • Verify --direction TB produces flowchart TB
  • Verify --functions mode shows shapes, subgraphs, edge labels, and role colors

Sets Xenova/bge-large-en-v1.5 (1024d) as the default embedding model
for codegraph self-analysis, replacing the default minilm.
… and styling

- Change `graph LR` to `flowchart {direction}` with configurable --direction option
- Add directory subgraph clustering in file-level mode (ported from DOT export)
- Add edge labels from edge.kind (imports, calls) with imports-type collapsed to imports
- Add node shapes by kind: stadium for functions/methods, hexagon for classes/structs,
  subroutine for modules
- Add role-based styling: entry=green, core=blue, utility=gray, dead=red, leaf=yellow
- Group function-level nodes by file into subgraphs
- Use stable node IDs (n0, n1, ...) for cleaner output

Impact: 4 functions changed, 2 affected
@claude
Copy link

claude bot commented Feb 25, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root cause analysis - understand problem and approach
  • Phase 2: Configuration change detection
  • Phase 3: Test integrity verification
  • Phase 4: Code quality review
  • Final assessment and rating

Phase 1: Root Cause Analysis ✅

Problem Being Solved: The existing Mermaid export was limited compared to DOT export - missing subgraph clustering, edge labels, node shapes, and role-based styling. This creates a gap where DOT export had richer features.

Why This Approach: The implementation logically ports successful features from DOT export to Mermaid, maintaining consistency. The changes add value without breaking existing functionality.

Risk Assessment: Low risk - this is feature enhancement, not bug fixing.

Phase 2: Configuration Change Detection ✅

Configuration Changes Analysis:

  • Low Risk: Added .codegraphrc.json with "embeddings": { "model": "bge-large" } - legitimate default configuration, not rule relaxation
  • No lint/build rule changes: biome.json unchanged, no test timeouts modified
  • No TypeScript strict mode changes: Not applicable (JS project)
  • No rule disabling: No eslint-disable or configuration relaxation detected

Verdict: Configuration changes are appropriate and safe.

Phase 3: Test Integrity Verification ✅

Test Changes Analysis:

  • Strengthened assertions: Updated existing tests from graph LR to flowchart LR - MORE SPECIFIC, not weakened
  • Added comprehensive coverage: 7 new test cases covering all new features (direction, subgraphs, edge labels, shapes, styling)
  • No removed/skipped tests: All original tests maintained and improved
  • No conditional assertions: All test assertions are concrete and definitive
  • Clear test scenarios: Each test focuses on one specific feature with appropriate setup

Verdict: Test integrity is excellent - tests were strengthened, not weakened.

Phase 4: Code Quality Review ✅

Implementation Analysis (src/export.js:128-314):

✅ Architecture & Design:

  • Well-structured mermaidShape() function with clear kind-to-shape mapping (lines 129-147)
  • Logical ROLE_STYLES color constants following Material Design colors (lines 150-156)
  • Stable node ID generation via nodeId() function prevents duplicate IDs (lines 168-173)

✅ Security:

  • All user input properly sanitized: replace(/[^a-zA-Z0-9]/g, '_') for subgraph IDs (line 224, 282)
  • Parameterized SQL queries prevent injection (lines 177-184, 246-257, 304-305)
  • No eval/execSync/innerHTML usage detected

✅ Performance:

  • Efficient edge deduplication using Map (lines 234-239)
  • Single DB query per operation, no N+1 problems
  • Proper use of DISTINCT in SQL queries to avoid duplicates

✅ Maintainability:

  • Code follows existing patterns from exportDOT() function
  • Clear separation between file-level (lines 175-243) and function-level (lines 244-310) modes
  • Consistent error handling and fallback strategies (hasDirectoryNodes check)

Minor Observations:

  • Line 238: Edge deduplication strategy could potentially lose multiple edge types between same nodes, but this is intentional per the "imports-type → imports" collapsing requirement
  • CLI integration (src/cli.js:277) properly validates direction parameter

No security, performance, or correctness issues identified.

Final Assessment

Root Cause Analysis

Problem Being Solved: Closing the feature gap between Mermaid and DOT exports by adding subgraphs, edge labels, node shapes, and styling - a legitimate enhancement request

Why This Approach: Systematic port of proven DOT export features to Mermaid with appropriate adaptations for Mermaid syntax

Risk Assessment: Very low risk - pure feature addition with comprehensive test coverage

Critical Concerns

None identified. This is a well-implemented feature enhancement.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Excellent implementation with comprehensive testing. Clean code that follows existing patterns. Only withholding 5th star because the manual test plan items are incomplete - would like to see verification of actual Mermaid rendering.

Recommended Actions Before Merge:

  1. Complete manual test plan items (paste output into mermaid.live)
  2. Verify --direction TB produces correct output
  3. Test function-level mode rendering in Mermaid Live

This PR significantly enhances the Mermaid export functionality and brings it to parity with the DOT export. Well done! 🎉


@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 25, 2026

Greptile Summary

This PR significantly enhances the Mermaid export functionality to match the feature parity of the DOT export. Key changes include:

  • Switched from graph LR to flowchart {direction} with configurable direction via --direction CLI flag
  • Added directory-based subgraph clustering in file-level mode with fallback from DB nodes to path.dirname()
  • Added edge labels showing relationship types (imports, calls) with imports-type collapsed to imports
  • Implemented node shapes by kind: stadium for functions/methods, hexagon for classes/structs/enums, subroutine for modules
  • Added file-based subgraph grouping in function-level mode
  • Applied role-based color styling (entry=green, core=blue, utility=gray, dead=red, leaf=yellow) in function-level mode
  • Used stable node IDs (n0, n1, ...) for cleaner output

All previous review issues have been properly addressed in commits 1c4ca34, b9d6ae4, 4f40eee, and 0c10e23. The implementation includes comprehensive test coverage and follows existing patterns in the codebase.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • All tests pass (526 total), lint is clean, all previous review issues have been addressed with fixes, comprehensive test coverage added for new features, implementation follows existing codebase patterns, and changes are well-scoped to export functionality
  • No files require special attention

Important Files Changed

Filename Overview
src/cli.js Added --direction CLI flag for Mermaid export with default value LR
src/export.js Enhanced Mermaid export with subgraphs, edge labels, node shapes, role styling, and stable node IDs; fixed previous review issues
tests/graph/export.test.js Added comprehensive tests for new Mermaid features including direction, subgraphs, edge labels, node shapes, and role styling

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CLI[CLI export command] --> ExportOpts{Parse options}
    ExportOpts --> Direction[direction flag]
    ExportOpts --> FileLevel[fileLevel flag]
    ExportOpts --> Format[format selection]
    
    Format --> Mermaid[exportMermaid]
    Format --> DOT[exportDOT]
    Format --> JSON[exportJSON]
    
    Mermaid --> FlowchartHeader[Generate flowchart header with direction]
    FlowchartHeader --> NodeIDGen[Generate stable node IDs n0, n1...]
    
    NodeIDGen --> FileLevelCheck{fileLevel?}
    
    FileLevelCheck -->|Yes| FileEdges[Query file-level edges]
    FileEdges --> DirSubgraphs[Build directory subgraphs]
    DirSubgraphs --> EdgeLabels[Add edge labels from kind]
    EdgeLabels --> CollapseTypes[Collapse imports-type to imports]
    
    FileLevelCheck -->|No| FnEdges[Query function-level edges]
    FnEdges --> FileSubgraphs[Group nodes by file into subgraphs]
    FileSubgraphs --> NodeShapes[Apply shapes by kind]
    NodeShapes --> CallLabels[Add call edge labels]
    CallLabels --> RoleStyles[Apply role-based styling]
    
    CollapseTypes --> Output[Generate Mermaid syntax]
    RoleStyles --> Output
Loading

Last reviewed commit: 0c10e23

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

src/export.js Outdated
Comment on lines +233 to +238
// Deduplicate edges per source-target pair, picking the most specific kind
const edgeMap = new Map();
for (const { source, target, edge_kind } of edges) {
const key = `${source}|${target}`;
const label = edge_kind === 'imports-type' ? 'imports' : edge_kind;
if (!edgeMap.has(key)) edgeMap.set(key, { source, target, label });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment says "picking the most specific kind" but implementation just takes first encountered edge (via !edgeMap.has(key) check). Either update comment to say "deduplicating edges" or implement actual specificity logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1c4ca34

Comment on lines +129 to +146
function mermaidShape(kind, label) {
switch (kind) {
case 'function':
case 'method':
return `(["${label}"])`;
case 'class':
case 'interface':
case 'type':
case 'struct':
case 'enum':
case 'trait':
case 'record':
return `{{"${label}"}}`;
case 'module':
return `[["${label}"]]`;
default:
return `["${label}"]`;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Labels with special characters (quotes, brackets) could break Mermaid syntax. Consider escaping double quotes in labels:

Suggested change
function mermaidShape(kind, label) {
switch (kind) {
case 'function':
case 'method':
return `(["${label}"])`;
case 'class':
case 'interface':
case 'type':
case 'struct':
case 'enum':
case 'trait':
case 'record':
return `{{"${label}"}}`;
case 'module':
return `[["${label}"]]`;
default:
return `["${label}"]`;
}
function mermaidShape(kind, label) {
const escaped = label.replace(/"/g, '#quot;');
switch (kind) {
case 'function':
case 'method':
return `(["${escaped}"])`;
case 'class':
case 'interface':
case 'type':
case 'struct':
case 'enum':
case 'trait':
case 'record':
return `{{"${escaped}"}}`;
case 'module':
return `[["${escaped}"]]`;
default:
return `["${escaped}"]`;
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1c4ca34 — added escapeLabel() that replaces double quotes with #quot;, applied to all label sites.

src/export.js Outdated
lines.push(` subgraph ${sgId}["${dir}"]`);
for (const f of files) {
const nId = nodeId(f);
lines.push(` ${nId}["${path.basename(f)}"]`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File basenames with quotes would break Mermaid syntax. Apply same escaping as suggested for mermaidShape.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1c4ca34 — same escapeLabel() applied to directory names, file basenames, and subgraph titles.

- Add escapeLabel() to replace double quotes with #quot; in all Mermaid
  labels (node shapes, file basenames, directory names, subgraph titles)
- Fix misleading comment: "picking the most specific kind" → "keeping the
  first encountered kind"

Impact: 3 functions changed, 2 affected
@carlos-alm
Copy link
Contributor Author

@greptileai

@claude
Copy link

claude bot commented Feb 25, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root cause analysis - understand problem and approach
  • Phase 2: Configuration change detection
  • Phase 3: Test integrity verification
  • Phase 4: Code quality review
  • Final assessment and rating

Phase 1: Root Cause Analysis ✅

Problem Being Solved: The existing Mermaid export was limited compared to DOT export - missing subgraph clustering, edge labels, node shapes, and role-based styling. This creates a gap where DOT export had richer features.

Why This Approach: The implementation logically ports successful features from DOT export to Mermaid, maintaining consistency. The changes add value without breaking existing functionality.

Risk Assessment: Low risk - this is feature enhancement, not bug fixing.

Phase 2: Configuration Change Detection ✅

Configuration Changes Analysis:

  • Low Risk: Added .codegraphrc.json with "embeddings": { "model": "bge-large" } - legitimate default configuration, not rule relaxation
  • No lint/build rule changes: biome.json unchanged, no test timeouts modified
  • No TypeScript strict mode changes: Not applicable (JS project)
  • No rule disabling: No eslint-disable or configuration relaxation detected

Verdict: Configuration changes are appropriate and safe.

Phase 3: Test Integrity Verification ✅

Test Changes Analysis:

  • Strengthened assertions: Updated existing tests from graph LR to flowchart LR - MORE SPECIFIC, not weakened
  • Added comprehensive coverage: 7 new test cases covering all new features (direction, subgraphs, edge labels, shapes, styling)
  • No removed/skipped tests: All original tests maintained and improved
  • No conditional assertions: All test assertions are concrete and definitive
  • Clear test scenarios: Each test focuses on one specific feature with appropriate setup

Verdict: Test integrity is excellent - tests were strengthened, not weakened.

Phase 4: Code Quality Review ✅

Implementation Analysis (src/export.js:128-314):

✅ Architecture & Design:

  • Well-structured mermaidShape() function with clear kind-to-shape mapping (lines 134-153)
  • Logical ROLE_STYLES color constants following Material Design colors (lines 156-162)
  • Stable node ID generation via nodeId() function prevents duplicate IDs (lines 176-179)

✅ Security:

  • All user input properly sanitized: escapeLabel() function handles quotes (lines 129-131)
  • Parameterized SQL queries prevent injection (lines 182-191, 251-263, 309-311)
  • No eval/execSync/innerHTML usage detected

✅ Performance:

  • Efficient edge deduplication using Map (lines 240-245)
  • Single DB query per operation, no N+1 problems
  • Proper use of DISTINCT in SQL queries to avoid duplicates

✅ Maintainability:

  • Code follows existing patterns from exportDOT() function
  • Clear separation between file-level (lines 181-249) and function-level (lines 250-317) modes
  • Consistent error handling and fallback strategies (hasDirectoryNodes check)

Minor Observations:

  • Implementation addresses Greptile's feedback by adding proper quote escaping via escapeLabel() function
  • CLI integration (src/cli.js:277) properly validates direction parameter
  • Edge deduplication strategy is intentional per "imports-type → imports" collapsing requirement

No security, performance, or correctness issues identified.

Final Assessment

Root Cause Analysis

Problem Being Solved: Closing the feature gap between Mermaid and DOT exports by adding subgraphs, edge labels, node shapes, and styling - a legitimate enhancement request

Why This Approach: Systematic port of proven DOT export features to Mermaid with appropriate adaptations for Mermaid syntax

Risk Assessment: Very low risk - pure feature addition with comprehensive test coverage

Critical Concerns

None identified. This is a well-implemented feature enhancement.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Excellent implementation with comprehensive testing. Clean code that follows existing patterns. Only withholding 5th star because the manual test plan items are incomplete - would like to see verification of actual Mermaid rendering.

Recommended Actions Before Merge:

  1. Complete manual test plan items (paste output into mermaid.live)
  2. Verify --direction TB produces correct output
  3. Test function-level mode rendering in Mermaid Live

This PR significantly enhances the Mermaid export functionality and brings it to parity with the DOT export. Well done! 🎉


@carlos-alm
Copy link
Contributor Author

Diff-impact Mermaid for this PR

flowchart TB
    subgraph sg0["src/builder.js **(modified)**"]
        n0["buildGraph"]
    end
    style sg0 fill:#fff3e0,stroke:#ff9800
    subgraph sg1["src/cli.js **(modified)**"]
        n2["command:export"]
        n3["command:prune"]
        n4["command:search"]
        n5["command:roles"]
    end
    style sg1 fill:#fff3e0,stroke:#ff9800
    subgraph sg2["src/db.js **(modified)**"]
        n6["initSchema"]
    end
    style sg2 fill:#fff3e0,stroke:#ff9800
    subgraph sg3["src/embedder.js **(modified)**"]
        n7["globMatch"]
        n14["disposeModel"]
        n15["loadModel"]
        n8["_prepareSearch"]
        n12["search"]
    end
    style sg3 fill:#fff3e0,stroke:#ff9800
    subgraph sg4["src/export.js **(modified)**"]
        n20["escapeLabel"]
        n21["mermaidShape"]
        n23["exportMermaid"]
        n22["nodeId"]
    end
    style sg4 fill:#fff3e0,stroke:#ff9800
    subgraph sg5["src/mcp.js **(modified)**"]
        n13["startMCPServer"]
    end
    style sg5 fill:#fff3e0,stroke:#ff9800
    subgraph sg6["src/queries.js **(modified)**"]
        n24["listFunctionsData"]
        n25["statsData"]
        n26["stats"]
        n28["contextData"]
        n29["context"]
        n31["explainFileImpl"]
        n36["mapSymbol"]
        n34["explainFunctionImpl"]
        n37["explain"]
        n39["printFunctionExplain"]
        n40["whereSymbolImpl"]
        n42["where"]
        n44["rolesData"]
        n45["roles"]
    end
    style sg6 fill:#fff3e0,stroke:#ff9800
    subgraph sg7["src/registry.js **(modified)**"]
        n46["pruneRegistry"]
    end
    style sg7 fill:#fff3e0,stroke:#ff9800
    subgraph sg8["src/structure.js **(modified)**"]
        n48["median"]
        n49["classifyNodeRoles"]
    end
    style sg8 fill:#fff3e0,stroke:#ff9800
    n9["searchData"]
    n16["embed"]
    n17["buildEmbeddings"]
    n32["getFileLines"]
    n41["whereData"]
    subgraph sg9["Callers **(blast radius)**"]
        n1["command:build"]
        n10["multiSearchData"]
        n11["benchmarkModel"]
        n18["command:embed"]
        n19["command:mcp"]
        n27["command:stats"]
        n30["command:context"]
        n33["getFileLines"]
        n35["explainCallees"]
        n38["command:explain"]
        n43["command:where"]
        n47["command:list"]
        n50["resolveBarrelExport"]
    end
    style sg9 fill:#f3e5f5,stroke:#9c27b0
    n0 --> n1
    n6 --> n0
    n7 --> n8
    n8 --> n9
    n8 --> n10
    n9 --> n11
    n9 --> n12
    n9 --> n13
    n14 --> n11
    n14 --> n15
    n15 --> n16
    n16 --> n17
    n16 --> n9
    n16 --> n10
    n17 --> n11
    n17 --> n18
    n12 --> n4
    n13 --> n19
    n20 --> n21
    n20 --> n22
    n21 --> n22
    n24 --> n13
    n25 --> n26
    n26 --> n27
    n28 --> n13
    n28 --> n29
    n29 --> n30
    n31 --> n32
    n32 --> n33
    n32 --> n34
    n34 --> n35
    n34 --> n32
    n32 --> n31
    n37 --> n38
    n40 --> n41
    n41 --> n13
    n41 --> n42
    n42 --> n43
    n44 --> n13
    n44 --> n45
    n45 --> n5
    n46 --> n13
    n46 --> n47
    n46 --> n3
    n48 --> n49
    n49 --> n50
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

src/export.js Outdated
const allKeys = [...nodeIdMap.keys()];
const roleStyles = [];
for (const key of allKeys) {
const [file, name] = key.split('::');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splitting on :: will break if file paths or function names contain ::. Use split('::') with a limit or find the first occurrence and slice.

Suggested change
const [file, name] = key.split('::');
const colonIdx = key.indexOf('::');
const file = colonIdx !== -1 ? key.slice(0, colonIdx) : key;
const name = colonIdx !== -1 ? key.slice(colonIdx + 2) : '';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b9d6ae4 — now uses indexOf + slice instead of split('::').

Impact: 1 functions changed, 0 affected
@claude
Copy link

claude bot commented Feb 25, 2026

Claude finished @carlos-alm's task —— View job


Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root cause analysis - understand problem and approach
  • Phase 2: Configuration change detection
  • Phase 3: Test integrity verification
  • Phase 4: Code quality review
  • Final assessment and rating

Phase 1: Root Cause Analysis ✅

Problem Being Solved: The existing Mermaid export was limited compared to DOT export - missing subgraph clustering, edge labels, node shapes, and role-based styling. This creates a gap where DOT export had richer features.

Why This Approach: The implementation logically ports successful features from DOT export to Mermaid, maintaining consistency. The changes add value without breaking existing functionality.

Risk Assessment: Low risk - this is feature enhancement, not bug fixing.

Phase 2: Configuration Change Detection ✅

Configuration Changes Analysis:

  • Low Risk: Added .codegraphrc.json with "embeddings": { "model": "bge-large" } - legitimate default configuration, not rule relaxation
  • No lint/build rule changes: biome.json unchanged, no test timeouts modified
  • No TypeScript strict mode changes: Not applicable (JS project)
  • No rule disabling: No eslint-disable or configuration relaxation detected

Verdict: Configuration changes are appropriate and safe.

Phase 3: Test Integrity Verification ✅

Test Changes Analysis:

  • Strengthened assertions: Updated existing tests from graph LR to flowchart LR - MORE SPECIFIC, not weakened
  • Added comprehensive coverage: 7 new test cases covering all new features (direction, subgraphs, edge labels, shapes, styling)
  • No removed/skipped tests: All original tests maintained and improved
  • No conditional assertions: All test assertions are concrete and definitive
  • Clear test scenarios: Each test focuses on one specific feature with appropriate setup

Verdict: Test integrity is excellent - tests were strengthened, not weakened.

Phase 4: Code Quality Review ✅

Implementation Analysis (src/export.js:128-314):

✅ Architecture & Design:

  • Well-structured mermaidShape() function with clear kind-to-shape mapping (lines 134-153)
  • Logical ROLE_STYLES color constants following Material Design colors (lines 156-162)
  • Stable node ID generation via nodeId() function prevents duplicate IDs (lines 176-179)

✅ Security:

  • All user input properly sanitized: escapeLabel() function handles quotes (lines 129-131)
  • Parameterized SQL queries prevent injection (lines 182-191, 251-263, 309-311)
  • No eval/execSync/innerHTML usage detected

✅ Performance:

  • Efficient edge deduplication using Map (lines 240-245)
  • Single DB query per operation, no N+1 problems
  • Proper use of DISTINCT in SQL queries to avoid duplicates

✅ Maintainability:

  • Code follows existing patterns from exportDOT() function
  • Clear separation between file-level (lines 181-249) and function-level (lines 250-317) modes
  • Consistent error handling and fallback strategies (hasDirectoryNodes check)

Minor Observations:

  • Implementation addresses Greptile's feedback by adding proper quote escaping via escapeLabel() function
  • CLI integration (src/cli.js:277) properly validates direction parameter
  • Edge deduplication strategy is intentional per "imports-type → imports" collapsing requirement

No security, performance, or correctness issues identified.

Final Assessment

Root Cause Analysis

Problem Being Solved: Closing the feature gap between Mermaid and DOT exports by adding subgraphs, edge labels, node shapes, and styling - a legitimate enhancement request

Why This Approach: Systematic port of proven DOT export features to Mermaid with appropriate adaptations for Mermaid syntax

Risk Assessment: Very low risk - pure feature addition with comprehensive test coverage

Critical Concerns

None identified. This is a well-implemented feature enhancement.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Excellent implementation with comprehensive testing. Clean code that follows existing patterns. Only withholding 5th star because the manual test plan items are incomplete - would like to see verification of actual Mermaid rendering.

Recommended Actions Before Merge:

  1. Complete manual test plan items (paste output into mermaid.live)
  2. Verify --direction TB produces correct output
  3. Test function-level mode rendering in Mermaid Live

This PR significantly enhances the Mermaid export functionality and brings it to parity with the DOT export. Well done! 🎉


… first

Impact: 1 functions changed, 0 affected
@claude
Copy link

claude bot commented Feb 25, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root cause analysis - understand problem and approach
  • Phase 2: Configuration change detection
  • Phase 3: Test integrity verification
  • Phase 4: Code quality review
  • Final assessment and rating

Phase 1: Root Cause Analysis ✅

Problem Being Solved: The existing Mermaid export was limited compared to DOT export - missing subgraph clustering, edge labels, node shapes, and role-based styling. This creates a gap where DOT export had richer features.

Why This Approach: The implementation logically ports successful features from DOT export to Mermaid, maintaining consistency. The changes add value without breaking existing functionality.

Risk Assessment: Low risk - this is feature enhancement, not bug fixing.

Phase 2: Configuration Change Detection ✅

Configuration Changes Analysis:

  • Low Risk: Added .codegraphrc.json with "embeddings": { "model": "bge-large" } - legitimate default configuration, not rule relaxation
  • No lint/build rule changes: biome.json unchanged, no test timeouts modified
  • No TypeScript strict mode changes: Not applicable (JS project)
  • No rule disabling: No eslint-disable or configuration relaxation detected

Verdict: Configuration changes are appropriate and safe.

Phase 3: Test Integrity Verification ✅

Test Changes Analysis:

  • Strengthened assertions: Updated existing tests from graph LR to flowchart LR - MORE SPECIFIC, not weakened
  • Added comprehensive coverage: 11 new test cases covering all new features (direction, subgraphs, edge labels, shapes, styling)
  • No removed/skipped tests: All original tests maintained and improved
  • No conditional assertions: All test assertions are concrete and definitive
  • Clear test scenarios: Each test focuses on one specific feature with appropriate setup

Verdict: Test integrity is excellent - tests were strengthened, not weakened.

Phase 4: Code Quality Review ✅

Implementation Analysis (src/export.js:128-314):

✅ Architecture & Design:

  • Well-structured mermaidShape() function with clear kind-to-shape mapping (lines 134-153)
  • Logical ROLE_STYLES color constants following Material Design colors (lines 156-162)
  • Stable node ID generation via nodeId() function prevents duplicate IDs (lines 176-179)

✅ Security:

  • All user input properly sanitized: escapeLabel() function handles quotes (lines 129-131)
  • Parameterized SQL queries prevent injection (lines 182-191, 251-263, 309-311)
  • No eval/execSync/innerHTML usage detected

✅ Performance:

  • Efficient edge deduplication using Map (lines 240-245)
  • Single DB query per operation, no N+1 problems
  • Proper use of DISTINCT in SQL queries to avoid duplicates

✅ Maintainability:

  • Code follows existing patterns from exportDOT() function
  • Clear separation between file-level (lines 181-249) and function-level (lines 250-317) modes
  • Consistent error handling and fallback strategies (hasDirectoryNodes check)

Minor Observations:

  • Implementation addresses Greptile's feedback by adding proper quote escaping via escapeLabel() function
  • CLI integration (src/cli.js:277) properly validates direction parameter
  • Edge deduplication strategy is intentional per "imports-type → imports" collapsing requirement

No security, performance, or correctness issues identified.

Final Assessment

Root Cause Analysis

Problem Being Solved: Closing the feature gap between Mermaid and DOT exports by adding subgraphs, edge labels, node shapes, and styling - a legitimate enhancement request

Why This Approach: Systematic port of proven DOT export features to Mermaid with appropriate adaptations for Mermaid syntax

Risk Assessment: Very low risk - pure feature addition with comprehensive test coverage

Critical Concerns

None identified. This is a well-implemented feature enhancement.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Excellent implementation with comprehensive testing. Clean code that follows existing patterns. Only withholding 5th star because the manual test plan items are incomplete - would like to see verification of actual Mermaid rendering.

Recommended Actions Before Merge:

  1. Complete manual test plan items (paste output into mermaid.live)
  2. Verify --direction TB produces correct output
  3. Test function-level mode rendering in Mermaid Live

This PR significantly enhances the Mermaid export functionality and brings it to parity with the DOT export. Well done! 🎉


@carlos-alm
Copy link
Contributor Author

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +308 to +314
for (const key of allKeys) {
const colonIdx = key.indexOf('::');
const file = colonIdx !== -1 ? key.slice(0, colonIdx) : key;
const name = colonIdx !== -1 ? key.slice(colonIdx + 2) : '';
const row = db
.prepare('SELECT role FROM nodes WHERE file = ? AND name = ? AND role IS NOT NULL LIMIT 1')
.get(file, name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

role lookup logic assumes all keys in nodeIdMap for function-level mode will have :: separators, but file-level keys don't. if file nodes end up in the map during function mode (shouldn't happen based on current SQL, but defensive code would help), the query will search for file=<full-key> and name='' which will never match

Suggested change
for (const key of allKeys) {
const colonIdx = key.indexOf('::');
const file = colonIdx !== -1 ? key.slice(0, colonIdx) : key;
const name = colonIdx !== -1 ? key.slice(colonIdx + 2) : '';
const row = db
.prepare('SELECT role FROM nodes WHERE file = ? AND name = ? AND role IS NOT NULL LIMIT 1')
.get(file, name);
for (const key of allKeys) {
const colonIdx = key.indexOf('::');
if (colonIdx === -1) continue; // Skip file-level keys
const file = key.slice(0, colonIdx);
const name = key.slice(colonIdx + 2);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0c10e23 — keys without :: are now skipped with continue.

Impact: 1 functions changed, 0 affected
@claude
Copy link

claude bot commented Feb 25, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root cause analysis - understand problem and approach
  • Phase 2: Configuration change detection
  • Phase 3: Test integrity verification
  • Phase 4: Code quality review
  • Final assessment and rating

Phase 1: Root Cause Analysis ✅

Problem Being Solved: The existing Mermaid export was limited compared to DOT export - missing subgraph clustering, edge labels, node shapes, and role-based styling. This creates a gap where DOT export had richer features.

Why This Approach: The implementation logically ports successful features from DOT export to Mermaid, maintaining consistency. The changes add value without breaking existing functionality.

Risk Assessment: Low risk - this is feature enhancement, not bug fixing.

Phase 2: Configuration Change Detection ✅

Configuration Changes Analysis:

  • Low Risk: Added .codegraphrc.json with "embeddings": { "model": "bge-large" } - legitimate default configuration, not rule relaxation
  • No lint/build rule changes: biome.json unchanged, no test timeouts modified
  • No TypeScript strict mode changes: Not applicable (JS project)
  • No rule disabling: No eslint-disable or configuration relaxation detected

Verdict: Configuration changes are appropriate and safe.

Phase 3: Test Integrity Verification ✅

Test Changes Analysis:

  • Strengthened assertions: Updated existing tests from graph LR to flowchart LR - MORE SPECIFIC, not weakened
  • Added comprehensive coverage: 11 new test cases covering all new features (direction, subgraphs, edge labels, shapes, styling)
  • No removed/skipped tests: All original tests maintained and improved
  • No conditional assertions: All test assertions are concrete and definitive
  • Clear test scenarios: Each test focuses on one specific feature with appropriate setup

Verdict: Test integrity is excellent - tests were strengthened, not weakened.

Phase 4: Code Quality Review ✅

Implementation Analysis (src/export.js:128-314):

✅ Architecture & Design:

  • Well-structured mermaidShape() function with clear kind-to-shape mapping (lines 134-153)
  • Logical ROLE_STYLES color constants following Material Design colors (lines 156-162)
  • Stable node ID generation via nodeId() function prevents duplicate IDs (lines 176-179)

✅ Security:

  • All user input properly sanitized: escapeLabel() function handles quotes (lines 129-131)
  • Parameterized SQL queries prevent injection (lines 182-191, 251-263, 309-311)
  • No eval/execSync/innerHTML usage detected

✅ Performance:

  • Efficient edge deduplication using Map (lines 240-245)
  • Single DB query per operation, no N+1 problems
  • Proper use of DISTINCT in SQL queries to avoid duplicates

✅ Maintainability:

  • Code follows existing patterns from exportDOT() function
  • Clear separation between file-level (lines 181-249) and function-level (lines 250-317) modes
  • Consistent error handling and fallback strategies (hasDirectoryNodes check)

Minor Observations:

  • Implementation addresses Greptile's feedback by adding proper quote escaping via escapeLabel() function
  • CLI integration (src/cli.js:277) properly validates direction parameter
  • Edge deduplication strategy is intentional per "imports-type → imports" collapsing requirement

No security, performance, or correctness issues identified.

Final Assessment

Root Cause Analysis

Problem Being Solved: Closing the feature gap between Mermaid and DOT exports by adding subgraphs, edge labels, node shapes, and styling - a legitimate enhancement request

Why This Approach: Systematic port of proven DOT export features to Mermaid with appropriate adaptations for Mermaid syntax

Risk Assessment: Very low risk - pure feature addition with comprehensive test coverage

Critical Concerns

None identified. This is a well-implemented feature enhancement.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Excellent implementation with comprehensive testing. Clean code that follows existing patterns. Only withholding 5th star because the manual test plan items are incomplete - would like to see verification of actual Mermaid rendering.

Recommended Actions Before Merge:

  1. Complete manual test plan items (paste output into mermaid.live)
  2. Verify --direction TB produces correct output
  3. Test function-level mode rendering in Mermaid Live

This PR significantly enhances the Mermaid export functionality and brings it to parity with the DOT export. Well done! 🎉

View job

@carlos-alm
Copy link
Contributor Author

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@carlos-alm carlos-alm merged commit 1aeea34 into main Feb 25, 2026
21 checks passed
@carlos-alm carlos-alm deleted the feat/mermaid-subgraphs-styling branch February 25, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant