mermaid.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Package parser provides the main parser router for all diagram types
  2. package parser
  3. import (
  4. "fmt"
  5. "strings"
  6. "mermaid-go/pkg/ast"
  7. )
  8. // MermaidParser is the main parser that routes to specific diagram parsers
  9. type MermaidParser struct{}
  10. // NewMermaidParser creates a new main mermaid parser
  11. func NewMermaidParser() *MermaidParser {
  12. return &MermaidParser{}
  13. }
  14. // Parse parses a mermaid diagram string and returns the appropriate AST
  15. func (p *MermaidParser) Parse(input string) (ast.Diagram, error) {
  16. // Detect diagram type from the input
  17. diagramType := p.detectDiagramType(input)
  18. switch diagramType {
  19. case ast.DiagramTypeFlowchart:
  20. parser := NewFlowchartParser()
  21. return parser.Parse(input)
  22. case ast.DiagramTypeSequence:
  23. parser := NewSequenceParser()
  24. return parser.Parse(input)
  25. case ast.DiagramTypeClassDiagram:
  26. parser := NewClassParser()
  27. return parser.Parse(input)
  28. case ast.DiagramTypeStateDiagram:
  29. parser := NewStateParser()
  30. return parser.Parse(input)
  31. case ast.DiagramTypePie:
  32. parser := NewPieParser()
  33. return parser.Parse(input)
  34. case ast.DiagramTypeERDiagram:
  35. parser := NewERParser()
  36. return parser.Parse(input)
  37. default:
  38. return nil, fmt.Errorf("unsupported diagram type: %s", diagramType)
  39. }
  40. }
  41. // detectDiagramType analyzes the input to determine the diagram type
  42. func (p *MermaidParser) detectDiagramType(input string) ast.DiagramType {
  43. // Clean input and get first meaningful line
  44. lines := strings.Split(input, "\n")
  45. for _, line := range lines {
  46. line = strings.TrimSpace(line)
  47. if line == "" || strings.HasPrefix(line, "%%") {
  48. continue // Skip empty lines and comments
  49. }
  50. // Check for explicit diagram type declarations
  51. lowerLine := strings.ToLower(line)
  52. if strings.HasPrefix(lowerLine, "sequencediagram") {
  53. return ast.DiagramTypeSequence
  54. }
  55. if strings.HasPrefix(lowerLine, "classdiagram") {
  56. return ast.DiagramTypeClassDiagram
  57. }
  58. if strings.HasPrefix(lowerLine, "statediagram") {
  59. return ast.DiagramTypeStateDiagram
  60. }
  61. if strings.HasPrefix(lowerLine, "flowchart") ||
  62. strings.HasPrefix(lowerLine, "graph") {
  63. return ast.DiagramTypeFlowchart
  64. }
  65. if strings.HasPrefix(lowerLine, "erdiagram") {
  66. return ast.DiagramTypeERDiagram
  67. }
  68. if strings.HasPrefix(lowerLine, "journey") {
  69. return ast.DiagramTypeUserJourney
  70. }
  71. if strings.HasPrefix(lowerLine, "timeline") {
  72. return ast.DiagramTypeTimeline
  73. }
  74. if strings.HasPrefix(lowerLine, "gantt") {
  75. return ast.DiagramTypeGantt
  76. }
  77. if strings.HasPrefix(lowerLine, "pie") {
  78. return ast.DiagramTypePie
  79. }
  80. if strings.HasPrefix(lowerLine, "quadrantchart") {
  81. return ast.DiagramTypeQuadrant
  82. }
  83. if strings.HasPrefix(lowerLine, "requirementdiagram") {
  84. return ast.DiagramTypeRequirement
  85. }
  86. if strings.HasPrefix(lowerLine, "block") {
  87. return ast.DiagramTypeBlock
  88. }
  89. // If no explicit type found, try to infer from content
  90. // This is a fallback for diagrams without explicit type declarations
  91. // Look for sequence diagram patterns
  92. if strings.Contains(lowerLine, "participant") ||
  93. strings.Contains(lowerLine, "actor") ||
  94. strings.Contains(lowerLine, "-->") ||
  95. strings.Contains(lowerLine, "->>") {
  96. return ast.DiagramTypeSequence
  97. }
  98. // Look for class diagram patterns
  99. if strings.Contains(lowerLine, "class ") ||
  100. strings.Contains(lowerLine, "--|>") ||
  101. strings.Contains(lowerLine, "--*") ||
  102. strings.Contains(lowerLine, "--o") {
  103. return ast.DiagramTypeClassDiagram
  104. }
  105. // Look for state diagram patterns
  106. if strings.Contains(lowerLine, "[*]") ||
  107. strings.Contains(lowerLine, "state ") {
  108. return ast.DiagramTypeStateDiagram
  109. }
  110. // Default to flowchart for backwards compatibility
  111. break
  112. }
  113. // Default fallback
  114. return ast.DiagramTypeFlowchart
  115. }
  116. // ParseWithType forces parsing with a specific diagram type
  117. func (p *MermaidParser) ParseWithType(input string, diagramType ast.DiagramType) (ast.Diagram, error) {
  118. switch diagramType {
  119. case ast.DiagramTypeFlowchart:
  120. parser := NewFlowchartParser()
  121. return parser.Parse(input)
  122. case ast.DiagramTypeSequence:
  123. parser := NewSequenceParser()
  124. return parser.Parse(input)
  125. case ast.DiagramTypeClassDiagram:
  126. parser := NewClassParser()
  127. return parser.Parse(input)
  128. case ast.DiagramTypeStateDiagram:
  129. parser := NewStateParser()
  130. return parser.Parse(input)
  131. case ast.DiagramTypePie:
  132. parser := NewPieParser()
  133. return parser.Parse(input)
  134. case ast.DiagramTypeERDiagram:
  135. parser := NewERParser()
  136. return parser.Parse(input)
  137. default:
  138. return nil, fmt.Errorf("unsupported diagram type: %s", diagramType)
  139. }
  140. }