|
12 | 12 | """ |
13 | 13 |
|
14 | 14 | from collections import defaultdict |
| 15 | +import re |
15 | 16 | from pathlib import Path |
16 | 17 | from typing import Dict, List, Set, Tuple, Optional |
17 | 18 | from .base import Exporter |
@@ -581,32 +582,22 @@ def _readable_id(self, name: str) -> str: |
581 | 582 | code2llm.core.analyze → code2llm__core__analyze |
582 | 583 | code2llm.core.PipelineDetector.__init__ → code2llm__core__PipelineDetector____init__ |
583 | 584 | """ |
584 | | - # Convert dots to double underscores to preserve hierarchy |
585 | | - safe = name.replace('.', '__') |
586 | | - # Replace other unsafe chars |
587 | | - safe = safe.replace('-', '_').replace(':', '_').replace(' ', '_') |
588 | | - # Keep reasonable length but preserve class+method uniqueness |
589 | | - if len(safe) > 60: |
590 | | - parts = name.split('.') |
591 | | - if len(parts) >= 3: |
592 | | - # module__Class__method or module__subpackage__Class__method |
593 | | - module = parts[0] |
594 | | - method = parts[-1] |
595 | | - # Include class name if present (parts[-2] is usually class or subpackage) |
596 | | - if len(parts) >= 4 and parts[-2][0].isupper(): |
597 | | - # Definitely a class: module.sub.Class.method |
598 | | - class_name = parts[-2] |
599 | | - safe = f"{module}__{class_name}__{method}" |
600 | | - else: |
601 | | - # Might be module.subpackage.function |
602 | | - middle = '__'.join(parts[1:-1]) |
603 | | - safe = f"{module}__{middle}__{method}" |
604 | | - safe = safe[:60] |
605 | | - return safe |
| 585 | + return self._sanitize_identifier(name, prefix="N") |
606 | 586 |
|
607 | 587 | def _safe_module(self, name: str) -> str: |
608 | 588 | """Create safe subgraph name.""" |
609 | | - return name.replace('.', '_').replace('-', '_').replace('/', '_').replace(' ', '_') |
| 589 | + return self._sanitize_identifier(name, prefix="M") |
| 590 | + |
| 591 | + @staticmethod |
| 592 | + def _sanitize_identifier(name: str, prefix: str) -> str: |
| 593 | + """Convert an arbitrary string into a Mermaid-safe identifier.""" |
| 594 | + safe = (name or "").replace('.', '__') |
| 595 | + safe = re.sub(r'[^A-Za-z0-9_]+', '_', safe) |
| 596 | + if not safe: |
| 597 | + return prefix |
| 598 | + if not safe[0].isalpha(): |
| 599 | + safe = f"{prefix}_{safe}" |
| 600 | + return safe |
610 | 601 |
|
611 | 602 | def _module_of(self, func_name: str) -> str: |
612 | 603 | """Extract module from qualified name. |
|
0 commit comments