| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- package detector
- import (
- "regexp"
- "strings"
- )
- // DiagramType represents the type of diagram
- type DiagramType string
- const (
- DiagramTypeUnknown DiagramType = "unknown"
- DiagramTypeSequence DiagramType = "sequence"
- DiagramTypeState DiagramType = "state"
- DiagramTypeStateV2 DiagramType = "state-v2"
- DiagramTypeFlowchart DiagramType = "flowchart"
- DiagramTypeClass DiagramType = "class"
- DiagramTypeER DiagramType = "er"
- DiagramTypeGantt DiagramType = "gantt"
- DiagramTypePie DiagramType = "pie"
- DiagramTypeGit DiagramType = "git"
- DiagramTypeUserJourney DiagramType = "user-journey"
- DiagramTypeTimeline DiagramType = "timeline"
- DiagramTypeMindmap DiagramType = "mindmap"
- DiagramTypeKanban DiagramType = "kanban"
- DiagramTypeSankey DiagramType = "sankey"
- DiagramTypeXYChart DiagramType = "xychart"
- DiagramTypeQuadrant DiagramType = "quadrant-chart"
- DiagramTypeRequirement DiagramType = "requirement"
- DiagramTypeBlock DiagramType = "block"
- DiagramTypeC4 DiagramType = "c4"
- DiagramTypeArchitecture DiagramType = "architecture"
- DiagramTypeRadar DiagramType = "radar"
- DiagramTypeTreemap DiagramType = "treemap"
- DiagramTypePacket DiagramType = "packet"
- DiagramTypeInfo DiagramType = "info"
- )
- // DetectorFunc is a function that detects if text matches a specific diagram type
- type DetectorFunc func(text string) bool
- // DiagramDetector represents a diagram detector with its type and detection function
- type DiagramDetector struct {
- Type DiagramType
- Detector DetectorFunc
- Priority int // Higher priority = checked first
- }
- // DetectorRegistry manages all diagram detectors
- type DetectorRegistry struct {
- detectors []DiagramDetector
- }
- // NewDetectorRegistry creates a new detector registry with default detectors
- func NewDetectorRegistry() *DetectorRegistry {
- registry := &DetectorRegistry{
- detectors: make([]DiagramDetector, 0),
- }
- // Register default detectors in order of specificity (most specific first)
- registry.Register(sequenceDetector())
- registry.Register(stateV2Detector())
- registry.Register(stateDetector())
- registry.Register(flowchartDetector())
- registry.Register(classDetector())
- registry.Register(erDetector())
- registry.Register(ganttDetector())
- registry.Register(pieDetector())
- registry.Register(gitDetector())
- registry.Register(userJourneyDetector())
- registry.Register(timelineDetector())
- registry.Register(mindmapDetector())
- registry.Register(kanbanDetector())
- registry.Register(sankeyDetector())
- registry.Register(xyChartDetector())
- registry.Register(quadrantDetector())
- registry.Register(requirementDetector())
- registry.Register(blockDetector())
- registry.Register(c4Detector())
- registry.Register(architectureDetector())
- registry.Register(radarDetector())
- registry.Register(treemapDetector())
- registry.Register(packetDetector())
- registry.Register(infoDetector())
- return registry
- }
- // Register adds a diagram detector to the registry
- func (r *DetectorRegistry) Register(detector DiagramDetector) {
- r.detectors = append(r.detectors, detector)
- // Sort by priority (higher first)
- for i := len(r.detectors) - 1; i > 0; i-- {
- if r.detectors[i].Priority > r.detectors[i-1].Priority {
- r.detectors[i], r.detectors[i-1] = r.detectors[i-1], r.detectors[i]
- } else {
- break
- }
- }
- }
- // DetectDiagramType detects the type of diagram from the given text
- func (r *DetectorRegistry) DetectDiagramType(text string) DiagramType {
- // Clean the text by removing comments and directives
- cleanText := cleanText(text)
- for _, detector := range r.detectors {
- if detector.Detector(cleanText) {
- return detector.Type
- }
- }
- return DiagramTypeUnknown
- }
- // cleanText removes comments, directives, and front matter from text
- func cleanText(text string) string {
- // Remove front matter (YAML between --- markers)
- frontMatterRegex := regexp.MustCompile(`(?s)^---\s*\n(.*?)\n---\s*\n+`)
- text = frontMatterRegex.ReplaceAllString(text, "")
- // Remove directives (%%{...}%%)
- directiveRegex := regexp.MustCompile(`%%\{[^}]*\}%%`)
- text = directiveRegex.ReplaceAllString(text, "")
- // Remove comments (%% ...) - this will leave empty lines
- commentRegex := regexp.MustCompile(`(?m)^\s*%%.*$`)
- text = commentRegex.ReplaceAllString(text, "")
- // Remove multiple consecutive newlines and normalize whitespace
- text = regexp.MustCompile(`\n\s*\n+`).ReplaceAllString(text, "\n")
- // Remove leading/trailing whitespace from each line
- lines := strings.Split(text, "\n")
- for i, line := range lines {
- lines[i] = strings.TrimRight(line, " \t")
- }
- text = strings.Join(lines, "\n")
- // Remove leading/trailing whitespace from entire text
- text = strings.TrimSpace(text)
- return text
- }
- // Individual detector functions
- func sequenceDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeSequence,
- Priority: 100,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*sequenceDiagram`, text)
- return matched
- },
- }
- }
- func stateV2Detector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeStateV2,
- Priority: 95,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*stateDiagram-v2`, text)
- return matched
- },
- }
- }
- func stateDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeState,
- Priority: 90,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*stateDiagram`, text)
- return matched
- },
- }
- }
- func flowchartDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeFlowchart,
- Priority: 85,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*(?:flowchart|graph)`, text)
- return matched
- },
- }
- }
- func classDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeClass,
- Priority: 80,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*classDiagram`, text)
- return matched
- },
- }
- }
- func erDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeER,
- Priority: 75,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*erDiagram`, text)
- return matched
- },
- }
- }
- func ganttDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeGantt,
- Priority: 70,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*gantt`, text)
- return matched
- },
- }
- }
- func pieDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypePie,
- Priority: 65,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*pie`, text)
- return matched
- },
- }
- }
- func gitDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeGit,
- Priority: 60,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*gitGraph`, text)
- return matched
- },
- }
- }
- func userJourneyDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeUserJourney,
- Priority: 55,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*journey`, text)
- return matched
- },
- }
- }
- func timelineDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeTimeline,
- Priority: 50,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*timeline`, text)
- return matched
- },
- }
- }
- func mindmapDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeMindmap,
- Priority: 45,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*mindmap`, text)
- return matched
- },
- }
- }
- func kanbanDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeKanban,
- Priority: 40,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*kanban`, text)
- return matched
- },
- }
- }
- func sankeyDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeSankey,
- Priority: 35,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*sankey-beta`, text)
- return matched
- },
- }
- }
- func xyChartDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeXYChart,
- Priority: 30,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*xychart-beta`, text)
- return matched
- },
- }
- }
- func quadrantDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeQuadrant,
- Priority: 25,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*quadrantChart`, text)
- return matched
- },
- }
- }
- func requirementDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeRequirement,
- Priority: 20,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*requirement`, text)
- return matched
- },
- }
- }
- func blockDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeBlock,
- Priority: 15,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*block-beta`, text)
- return matched
- },
- }
- }
- func c4Detector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeC4,
- Priority: 10,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*c4Context`, text)
- return matched
- },
- }
- }
- func architectureDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeArchitecture,
- Priority: 5,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*architecture`, text)
- return matched
- },
- }
- }
- func radarDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeRadar,
- Priority: 3,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*radar`, text)
- return matched
- },
- }
- }
- func treemapDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeTreemap,
- Priority: 2,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*treemap`, text)
- return matched
- },
- }
- }
- func packetDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypePacket,
- Priority: 1,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*packet`, text)
- return matched
- },
- }
- }
- func infoDetector() DiagramDetector {
- return DiagramDetector{
- Type: DiagramTypeInfo,
- Priority: 0,
- Detector: func(text string) bool {
- matched, _ := regexp.MatchString(`(?i)^\s*info`, text)
- return matched
- },
- }
- }
|