mermaid.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. case ast.DiagramTypeGantt:
  38. parser := NewGanttParser()
  39. return parser.Parse(input)
  40. case ast.DiagramTypeTimeline:
  41. parser := NewTimelineParser()
  42. return parser.Parse(input)
  43. case ast.DiagramTypeUserJourney:
  44. parser := NewJourneyParser()
  45. return parser.Parse(input)
  46. case ast.DiagramTypeArchitecture:
  47. parser := NewArchitectureParser()
  48. return parser.Parse(input)
  49. case ast.DiagramTypeOrganization:
  50. parser := NewOrganizationParser()
  51. return parser.Parse(input)
  52. case ast.DiagramTypeBPMN:
  53. parser := NewBPMNParser()
  54. return parser.Parse(input)
  55. default:
  56. return nil, fmt.Errorf("unsupported diagram type: %s", diagramType)
  57. }
  58. }
  59. // detectDiagramType analyzes the input to determine the diagram type
  60. func (p *MermaidParser) detectDiagramType(input string) ast.DiagramType {
  61. // Clean input and get first meaningful line
  62. lines := strings.Split(input, "\n")
  63. for _, line := range lines {
  64. line = strings.TrimSpace(line)
  65. if line == "" || strings.HasPrefix(line, "%%") {
  66. continue // Skip empty lines and comments
  67. }
  68. // Check for explicit diagram type declarations
  69. lowerLine := strings.ToLower(line)
  70. if strings.HasPrefix(lowerLine, "sequencediagram") {
  71. return ast.DiagramTypeSequence
  72. }
  73. if strings.HasPrefix(lowerLine, "classdiagram") {
  74. return ast.DiagramTypeClassDiagram
  75. }
  76. if strings.HasPrefix(lowerLine, "statediagram") {
  77. return ast.DiagramTypeStateDiagram
  78. }
  79. if strings.HasPrefix(lowerLine, "flowchart") ||
  80. strings.HasPrefix(lowerLine, "graph") {
  81. return ast.DiagramTypeFlowchart
  82. }
  83. if strings.HasPrefix(lowerLine, "erdiagram") {
  84. return ast.DiagramTypeERDiagram
  85. }
  86. if strings.HasPrefix(lowerLine, "journey") {
  87. return ast.DiagramTypeUserJourney
  88. }
  89. if strings.HasPrefix(lowerLine, "timeline") {
  90. return ast.DiagramTypeTimeline
  91. }
  92. if strings.HasPrefix(lowerLine, "gantt") {
  93. return ast.DiagramTypeGantt
  94. }
  95. if strings.HasPrefix(lowerLine, "pie") {
  96. return ast.DiagramTypePie
  97. }
  98. if strings.HasPrefix(lowerLine, "quadrantchart") {
  99. return ast.DiagramTypeQuadrant
  100. }
  101. if strings.HasPrefix(lowerLine, "requirementdiagram") {
  102. return ast.DiagramTypeRequirement
  103. }
  104. if strings.HasPrefix(lowerLine, "block") {
  105. return ast.DiagramTypeBlock
  106. }
  107. if strings.HasPrefix(lowerLine, "architecture") {
  108. return ast.DiagramTypeArchitecture
  109. }
  110. if strings.HasPrefix(lowerLine, "organization") || strings.HasPrefix(lowerLine, "orgchart") {
  111. return ast.DiagramTypeOrganization
  112. }
  113. if strings.HasPrefix(lowerLine, "bpmn") {
  114. return ast.DiagramTypeBPMN
  115. }
  116. // If no explicit type found, try to infer from content
  117. // This is a fallback for diagrams without explicit type declarations
  118. // Look for sequence diagram patterns
  119. if strings.Contains(lowerLine, "participant") ||
  120. strings.Contains(lowerLine, "actor") ||
  121. strings.Contains(lowerLine, "-->") ||
  122. strings.Contains(lowerLine, "->>") {
  123. return ast.DiagramTypeSequence
  124. }
  125. // Look for class diagram patterns
  126. if strings.Contains(lowerLine, "class ") ||
  127. strings.Contains(lowerLine, "--|>") ||
  128. strings.Contains(lowerLine, "--*") ||
  129. strings.Contains(lowerLine, "--o") {
  130. return ast.DiagramTypeClassDiagram
  131. }
  132. // Look for state diagram patterns
  133. if strings.Contains(lowerLine, "[*]") ||
  134. strings.Contains(lowerLine, "state ") {
  135. return ast.DiagramTypeStateDiagram
  136. }
  137. // Default to flowchart for backwards compatibility
  138. break
  139. }
  140. // Default fallback
  141. return ast.DiagramTypeFlowchart
  142. }
  143. // ParseWithType forces parsing with a specific diagram type
  144. func (p *MermaidParser) ParseWithType(input string, diagramType ast.DiagramType) (ast.Diagram, error) {
  145. switch diagramType {
  146. case ast.DiagramTypeFlowchart:
  147. parser := NewFlowchartParser()
  148. return parser.Parse(input)
  149. case ast.DiagramTypeSequence:
  150. parser := NewSequenceParser()
  151. return parser.Parse(input)
  152. case ast.DiagramTypeClassDiagram:
  153. parser := NewClassParser()
  154. return parser.Parse(input)
  155. case ast.DiagramTypeStateDiagram:
  156. parser := NewStateParser()
  157. return parser.Parse(input)
  158. case ast.DiagramTypePie:
  159. parser := NewPieParser()
  160. return parser.Parse(input)
  161. case ast.DiagramTypeERDiagram:
  162. parser := NewERParser()
  163. return parser.Parse(input)
  164. case ast.DiagramTypeGantt:
  165. parser := NewGanttParser()
  166. return parser.Parse(input)
  167. case ast.DiagramTypeTimeline:
  168. parser := NewTimelineParser()
  169. return parser.Parse(input)
  170. case ast.DiagramTypeUserJourney:
  171. parser := NewJourneyParser()
  172. return parser.Parse(input)
  173. case ast.DiagramTypeArchitecture:
  174. parser := NewArchitectureParser()
  175. return parser.Parse(input)
  176. case ast.DiagramTypeOrganization:
  177. parser := NewOrganizationParser()
  178. return parser.Parse(input)
  179. case ast.DiagramTypeBPMN:
  180. parser := NewBPMNParser()
  181. return parser.Parse(input)
  182. default:
  183. return nil, fmt.Errorf("unsupported diagram type: %s", diagramType)
  184. }
  185. }