Jelajahi Sumber

增加图表类型

tm 3 bulan lalu
induk
melakukan
8c5612b8be
8 mengubah file dengan 1115 tambahan dan 174 penghapusan
  1. 228 46
      pkg/ast/c4.go
  2. 5 0
      pkg/ast/flowchart.go
  3. 65 0
      pkg/detector/detector.go
  4. 26 3
      pkg/exporter/svg.go
  5. 493 97
      pkg/parser/c4.go
  6. 10 0
      pkg/parser/main.go
  7. 273 25
      pkg/renderer/c4.go
  8. 15 3
      pkg/renderer/mermaid.go

+ 228 - 46
pkg/ast/c4.go

@@ -1,74 +1,241 @@
-// C4 diagram AST structures
+// C4 diagram AST structures based on C4 model
 package ast
 
-// C4Diagram represents a C4 diagram
+// C4Diagram represents a base C4 diagram
 type C4Diagram struct {
-	Title     *string        `json:"title,omitempty"`
-	Elements  []*C4Element   `json:"elements"`
-	Relations []*C4Relation  `json:"relations"`
-	Config    map[string]any `json:"config,omitempty"`
+	Title      *string        `json:"title,omitempty"`
+	Elements   []*C4Element   `json:"elements"`
+	Relations  []*C4Relation  `json:"relations"`
+	Boundaries []*C4Boundary  `json:"boundaries"`
+	Config     map[string]any `json:"config,omitempty"`
 }
 
+// C4Element represents a C4 element (Person, System, Container, Component)
 type C4Element struct {
-	ID          string        `json:"id"`
-	Label       string        `json:"label"`
-	Type        C4ElementType `json:"type"`
-	Technology  *string       `json:"technology,omitempty"`
-	Description *string       `json:"description,omitempty"`
-	Boundary    *string       `json:"boundary,omitempty"`
-	Tags        []string      `json:"tags,omitempty"`
+	ID          string         `json:"id"`
+	Type        C4ElementType  `json:"type"`
+	Name        string         `json:"name"`
+	Description string         `json:"description"`
+	Technology  *string        `json:"technology,omitempty"`
+	Properties  map[string]any `json:"properties,omitempty"`
 }
 
+// C4ElementType represents the type of C4 element
+type C4ElementType string
+
+const (
+	C4ElementPerson    C4ElementType = "person"
+	C4ElementSystem    C4ElementType = "system"
+	C4ElementContainer C4ElementType = "container"
+	C4ElementComponent C4ElementType = "component"
+	C4ElementDatabase  C4ElementType = "database"
+	C4ElementQueue     C4ElementType = "queue"
+	C4ElementExternal  C4ElementType = "external"
+)
+
+// C4Relation represents a relationship between C4 elements
 type C4Relation struct {
-	From        string  `json:"from"`
-	To          string  `json:"to"`
-	Label       *string `json:"label,omitempty"`
-	Technology  *string `json:"technology,omitempty"`
-	Description *string `json:"description,omitempty"`
+	From       string         `json:"from"`
+	To         string         `json:"to"`
+	Label      *string        `json:"label,omitempty"`
+	Technology *string        `json:"technology,omitempty"`
+	Type       C4RelationType `json:"type"`
+	Properties map[string]any `json:"properties,omitempty"`
 }
 
-type C4ElementType string
+// C4RelationType represents the type of C4 relation
+type C4RelationType string
 
 const (
-	C4ElementPerson         C4ElementType = "person"
-	C4ElementPersonExt      C4ElementType = "person_ext"
-	C4ElementSystem         C4ElementType = "system"
-	C4ElementSystemExt      C4ElementType = "system_ext"
-	C4ElementSystemDb       C4ElementType = "system_db"
-	C4ElementSystemQueue    C4ElementType = "system_queue"
-	C4ElementContainer      C4ElementType = "container"
-	C4ElementContainerExt   C4ElementType = "container_ext"
-	C4ElementContainerDb    C4ElementType = "container_db"
-	C4ElementContainerQueue C4ElementType = "container_queue"
-	C4ElementComponent      C4ElementType = "component"
-	C4ElementComponentExt   C4ElementType = "component_ext"
-	C4ElementComponentDb    C4ElementType = "component_db"
-	C4ElementComponentQueue C4ElementType = "component_queue"
-	C4ElementBoundary       C4ElementType = "boundary"
+	C4RelationSync      C4RelationType = "sync"
+	C4RelationAsync     C4RelationType = "async"
+	C4RelationWebSocket C4RelationType = "websocket"
 )
 
+// C4Boundary represents a boundary in C4 diagrams
+type C4Boundary struct {
+	ID          string         `json:"id"`
+	Type        C4BoundaryType `json:"type"`
+	Name        string         `json:"name"`
+	Description *string        `json:"description,omitempty"`
+	Elements    []string       `json:"elements"` // IDs of elements within this boundary
+}
+
+// C4BoundaryType represents the type of C4 boundary
+type C4BoundaryType string
+
+const (
+	C4BoundarySystem    C4BoundaryType = "system"
+	C4BoundaryContainer C4BoundaryType = "container"
+)
+
+// C4ContextDiagram represents a C4 Context diagram
+type C4ContextDiagram struct {
+	C4Diagram
+}
+
 // Type returns the diagram type
-func (c *C4Diagram) Type() DiagramType {
-	return DiagramTypeC4
+func (c *C4ContextDiagram) Type() DiagramType {
+	return DiagramTypeC4Context
 }
 
-// Validate checks if the C4 diagram is valid
-func (c *C4Diagram) Validate() error {
-	if len(c.Elements) == 0 {
-		return NewValidationError("C4 diagram must have at least one element")
+// Validate checks if the C4 Context diagram is valid
+func (c *C4ContextDiagram) Validate() error {
+	// Basic validation - ensure all relations reference valid elements
+	elementMap := make(map[string]bool)
+	for _, element := range c.Elements {
+		elementMap[element.ID] = true
+	}
+
+	for _, relation := range c.Relations {
+		if !elementMap[relation.From] {
+			return NewValidationError("relation references non-existent element: " + relation.From)
+		}
+		if !elementMap[relation.To] {
+			return NewValidationError("relation references non-existent element: " + relation.To)
+		}
 	}
 	return nil
 }
 
-// NewC4Diagram creates a new C4 diagram
-func NewC4Diagram() *C4Diagram {
-	return &C4Diagram{
-		Elements:  make([]*C4Element, 0),
-		Relations: make([]*C4Relation, 0),
-		Config:    make(map[string]any),
+// NewC4ContextDiagram creates a new C4 Context diagram
+func NewC4ContextDiagram() *C4ContextDiagram {
+	return &C4ContextDiagram{
+		C4Diagram: C4Diagram{
+			Elements:   make([]*C4Element, 0),
+			Relations:  make([]*C4Relation, 0),
+			Boundaries: make([]*C4Boundary, 0),
+			Config:     make(map[string]any),
+		},
 	}
 }
 
+// C4ContainerDiagram represents a C4 Container diagram
+type C4ContainerDiagram struct {
+	C4Diagram
+}
+
+// Type returns the diagram type
+func (c *C4ContainerDiagram) Type() DiagramType {
+	return DiagramTypeC4Container
+}
+
+// Validate checks if the C4 Container diagram is valid
+func (c *C4ContainerDiagram) Validate() error {
+	return c.C4Diagram.validate()
+}
+
+// NewC4ContainerDiagram creates a new C4 Container diagram
+func NewC4ContainerDiagram() *C4ContainerDiagram {
+	return &C4ContainerDiagram{
+		C4Diagram: C4Diagram{
+			Elements:   make([]*C4Element, 0),
+			Relations:  make([]*C4Relation, 0),
+			Boundaries: make([]*C4Boundary, 0),
+			Config:     make(map[string]any),
+		},
+	}
+}
+
+// C4ComponentDiagram represents a C4 Component diagram
+type C4ComponentDiagram struct {
+	C4Diagram
+}
+
+// Type returns the diagram type
+func (c *C4ComponentDiagram) Type() DiagramType {
+	return DiagramTypeC4Component
+}
+
+// Validate checks if the C4 Component diagram is valid
+func (c *C4ComponentDiagram) Validate() error {
+	return c.C4Diagram.validate()
+}
+
+// NewC4ComponentDiagram creates a new C4 Component diagram
+func NewC4ComponentDiagram() *C4ComponentDiagram {
+	return &C4ComponentDiagram{
+		C4Diagram: C4Diagram{
+			Elements:   make([]*C4Element, 0),
+			Relations:  make([]*C4Relation, 0),
+			Boundaries: make([]*C4Boundary, 0),
+			Config:     make(map[string]any),
+		},
+	}
+}
+
+// C4DynamicDiagram represents a C4 Dynamic diagram
+type C4DynamicDiagram struct {
+	C4Diagram
+}
+
+// Type returns the diagram type
+func (c *C4DynamicDiagram) Type() DiagramType {
+	return DiagramTypeC4Dynamic
+}
+
+// Validate checks if the C4 Dynamic diagram is valid
+func (c *C4DynamicDiagram) Validate() error {
+	return c.C4Diagram.validate()
+}
+
+// NewC4DynamicDiagram creates a new C4 Dynamic diagram
+func NewC4DynamicDiagram() *C4DynamicDiagram {
+	return &C4DynamicDiagram{
+		C4Diagram: C4Diagram{
+			Elements:   make([]*C4Element, 0),
+			Relations:  make([]*C4Relation, 0),
+			Boundaries: make([]*C4Boundary, 0),
+			Config:     make(map[string]any),
+		},
+	}
+}
+
+// C4DeploymentDiagram represents a C4 Deployment diagram
+type C4DeploymentDiagram struct {
+	C4Diagram
+}
+
+// Type returns the diagram type
+func (c *C4DeploymentDiagram) Type() DiagramType {
+	return DiagramTypeC4Deployment
+}
+
+// Validate checks if the C4 Deployment diagram is valid
+func (c *C4DeploymentDiagram) Validate() error {
+	return c.C4Diagram.validate()
+}
+
+// NewC4DeploymentDiagram creates a new C4 Deployment diagram
+func NewC4DeploymentDiagram() *C4DeploymentDiagram {
+	return &C4DeploymentDiagram{
+		C4Diagram: C4Diagram{
+			Elements:   make([]*C4Element, 0),
+			Relations:  make([]*C4Relation, 0),
+			Boundaries: make([]*C4Boundary, 0),
+			Config:     make(map[string]any),
+		},
+	}
+}
+
+// validate is a helper method for common C4 diagram validation
+func (c *C4Diagram) validate() error {
+	elementMap := make(map[string]bool)
+	for _, element := range c.Elements {
+		elementMap[element.ID] = true
+	}
+
+	for _, relation := range c.Relations {
+		if !elementMap[relation.From] {
+			return NewValidationError("relation references non-existent element: " + relation.From)
+		}
+		if !elementMap[relation.To] {
+			return NewValidationError("relation references non-existent element: " + relation.To)
+		}
+	}
+	return nil
+}
+
 // AddElement adds an element to the C4 diagram
 func (c *C4Diagram) AddElement(element *C4Element) {
 	c.Elements = append(c.Elements, element)
@@ -79,6 +246,11 @@ func (c *C4Diagram) AddRelation(relation *C4Relation) {
 	c.Relations = append(c.Relations, relation)
 }
 
+// AddBoundary adds a boundary to the C4 diagram
+func (c *C4Diagram) AddBoundary(boundary *C4Boundary) {
+	c.Boundaries = append(c.Boundaries, boundary)
+}
+
 // FindElement finds an element by ID
 func (c *C4Diagram) FindElement(id string) *C4Element {
 	for _, element := range c.Elements {
@@ -88,3 +260,13 @@ func (c *C4Diagram) FindElement(id string) *C4Element {
 	}
 	return nil
 }
+
+// FindBoundary finds a boundary by ID
+func (c *C4Diagram) FindBoundary(id string) *C4Boundary {
+	for _, boundary := range c.Boundaries {
+		if boundary.ID == id {
+			return boundary
+		}
+	}
+	return nil
+}

+ 5 - 0
pkg/ast/flowchart.go

@@ -32,6 +32,11 @@ const (
 	DiagramTypePacket       DiagramType = "packet"
 	DiagramTypeInfo         DiagramType = "info"
 	DiagramTypeC4           DiagramType = "c4"
+	DiagramTypeC4Context    DiagramType = "c4context"
+	DiagramTypeC4Container  DiagramType = "c4container"
+	DiagramTypeC4Component  DiagramType = "c4component"
+	DiagramTypeC4Dynamic    DiagramType = "c4dynamic"
+	DiagramTypeC4Deployment DiagramType = "c4deployment"
 )
 
 // Diagram is the base interface for all mermaid diagrams

+ 65 - 0
pkg/detector/detector.go

@@ -29,6 +29,11 @@ const (
 	DiagramTypeRequirement  DiagramType = "requirement"
 	DiagramTypeBlock        DiagramType = "block"
 	DiagramTypeC4           DiagramType = "c4"
+	DiagramTypeC4Context    DiagramType = "c4context"
+	DiagramTypeC4Container  DiagramType = "c4container"
+	DiagramTypeC4Component  DiagramType = "c4component"
+	DiagramTypeC4Dynamic    DiagramType = "c4dynamic"
+	DiagramTypeC4Deployment DiagramType = "c4deployment"
 	DiagramTypeArchitecture DiagramType = "architecture"
 	DiagramTypeRadar        DiagramType = "radar"
 	DiagramTypeTreemap      DiagramType = "treemap"
@@ -78,6 +83,11 @@ func NewDetectorRegistry() *DetectorRegistry {
 	registry.Register(quadrantDetector())
 	registry.Register(requirementDetector())
 	registry.Register(blockDetector())
+	registry.Register(c4ContextDetector())
+	registry.Register(c4ContainerDetector())
+	registry.Register(c4ComponentDetector())
+	registry.Register(c4DynamicDetector())
+	registry.Register(c4DeploymentDetector())
 	registry.Register(c4Detector())
 	registry.Register(architectureDetector())
 	registry.Register(radarDetector())
@@ -434,3 +444,58 @@ func bpmnDetector() DiagramDetector {
 		},
 	}
 }
+
+func c4ContextDetector() DiagramDetector {
+	return DiagramDetector{
+		Type:     DiagramTypeC4Context,
+		Priority: 12,
+		Detector: func(text string) bool {
+			matched, _ := regexp.MatchString(`(?i)^\s*c4context`, text)
+			return matched
+		},
+	}
+}
+
+func c4ContainerDetector() DiagramDetector {
+	return DiagramDetector{
+		Type:     DiagramTypeC4Container,
+		Priority: 11,
+		Detector: func(text string) bool {
+			matched, _ := regexp.MatchString(`(?i)^\s*c4container`, text)
+			return matched
+		},
+	}
+}
+
+func c4ComponentDetector() DiagramDetector {
+	return DiagramDetector{
+		Type:     DiagramTypeC4Component,
+		Priority: 11,
+		Detector: func(text string) bool {
+			matched, _ := regexp.MatchString(`(?i)^\s*c4component`, text)
+			return matched
+		},
+	}
+}
+
+func c4DynamicDetector() DiagramDetector {
+	return DiagramDetector{
+		Type:     DiagramTypeC4Dynamic,
+		Priority: 11,
+		Detector: func(text string) bool {
+			matched, _ := regexp.MatchString(`(?i)^\s*c4dynamic`, text)
+			return matched
+		},
+	}
+}
+
+func c4DeploymentDetector() DiagramDetector {
+	return DiagramDetector{
+		Type:     DiagramTypeC4Deployment,
+		Priority: 11,
+		Detector: func(text string) bool {
+			matched, _ := regexp.MatchString(`(?i)^\s*c4deployment`, text)
+			return matched
+		},
+	}
+}

+ 26 - 3
pkg/exporter/svg.go

@@ -83,7 +83,15 @@ func (e *SVGExporter) ExportToSVG(diagram ast.Diagram) (string, error) {
 		return e.exportPacketToSVG(d)
 	case *ast.InfoDiagram:
 		return e.exportInfoToSVG(d)
-	case *ast.C4Diagram:
+	case *ast.C4ContextDiagram:
+		return e.exportC4ToSVG(d)
+	case *ast.C4ContainerDiagram:
+		return e.exportC4ToSVG(d)
+	case *ast.C4ComponentDiagram:
+		return e.exportC4ToSVG(d)
+	case *ast.C4DynamicDiagram:
+		return e.exportC4ToSVG(d)
+	case *ast.C4DeploymentDiagram:
 		return e.exportC4ToSVG(d)
 	case *ast.QuadrantChart:
 		return e.exportQuadrantToSVG(d)
@@ -657,12 +665,27 @@ func (e *SVGExporter) exportInfoToSVG(diagram *ast.InfoDiagram) (string, error)
 }
 
 // exportC4ToSVG exports C4 diagram to SVG
-func (e *SVGExporter) exportC4ToSVG(diagram *ast.C4Diagram) (string, error) {
+func (e *SVGExporter) exportC4ToSVG(diagram ast.Diagram) (string, error) {
+	// Get element count based on diagram type
+	elementCount := 0
+	switch d := diagram.(type) {
+	case *ast.C4ContextDiagram:
+		elementCount = len(d.Elements)
+	case *ast.C4ContainerDiagram:
+		elementCount = len(d.Elements)
+	case *ast.C4ComponentDiagram:
+		elementCount = len(d.Elements)
+	case *ast.C4DynamicDiagram:
+		elementCount = len(d.Elements)
+	case *ast.C4DeploymentDiagram:
+		elementCount = len(d.Elements)
+	}
+
 	svg := fmt.Sprintf(`<svg width="%d" height="%d" xmlns="http://www.w3.org/2000/svg">
   <rect width="100%%" height="100%%" fill="white"/>
   <text x="%d" y="30" font-family="Arial" font-size="16" font-weight="bold" text-anchor="middle">C4 Diagram</text>
   <text x="%d" y="50" font-family="Arial" font-size="12" text-anchor="middle">%d elements</text>
-</svg>`, e.width, e.height, e.width/2, e.width/2, len(diagram.Elements))
+</svg>`, e.width, e.height, e.width/2, e.width/2, elementCount)
 	return svg, nil
 }
 

+ 493 - 97
pkg/parser/c4.go

@@ -13,18 +13,24 @@ import (
 type C4Parser struct {
 	tokens  []lexer.Token
 	current int
-	diagram *ast.C4Diagram
+	diagram C4DiagramInterface
+}
+
+// C4DiagramInterface is an interface for C4 diagrams
+type C4DiagramInterface interface {
+	ast.Diagram
+	AddElement(element *ast.C4Element)
+	AddRelation(relation *ast.C4Relation)
+	AddBoundary(boundary *ast.C4Boundary)
 }
 
 // NewC4Parser creates a new C4 parser
 func NewC4Parser() *C4Parser {
-	return &C4Parser{
-		diagram: ast.NewC4Diagram(),
-	}
+	return &C4Parser{}
 }
 
-// Parse parses C4 diagram syntax
-func (p *C4Parser) Parse(input string) (*ast.C4Diagram, error) {
+// Parse parses C4 syntax and returns the appropriate C4 diagram
+func (p *C4Parser) Parse(input string) (ast.Diagram, error) {
 	// Tokenize
 	l := lexer.NewLexer(input)
 	tokens, err := l.Tokenize()
@@ -35,41 +41,49 @@ func (p *C4Parser) Parse(input string) (*ast.C4Diagram, error) {
 	// Filter tokens
 	p.tokens = lexer.FilterTokens(tokens)
 	p.current = 0
-	p.diagram = ast.NewC4Diagram()
 
-	// Parse document
-	err = p.parseDocument()
+	// Parse document header to determine diagram type
+	err = p.parseDocumentHeader()
 	if err != nil {
 		return nil, fmt.Errorf("syntax analysis failed: %w", err)
 	}
 
+	// Parse statements
+	for !p.isAtEnd() {
+		if err := p.parseStatement(); err != nil {
+			return nil, err
+		}
+	}
+
 	return p.diagram, nil
 }
 
-// parseDocument parses the C4 diagram document
-func (p *C4Parser) parseDocument() error {
-	// Expect C4Context, C4Container, or C4Component
+// parseDocumentHeader parses the C4 document header to determine diagram type
+func (p *C4Parser) parseDocumentHeader() error {
 	if !p.check(lexer.TokenID) {
 		return p.error("expected C4 diagram type")
 	}
 
-	diagramType := p.peek().Value
-	if diagramType != "C4Context" && diagramType != "C4Container" && diagramType != "C4Component" {
-		return p.error("expected 'C4Context', 'C4Container', or 'C4Component'")
-	}
-	p.advance()
-
-	// Parse statements
-	for !p.isAtEnd() {
-		if err := p.parseStatement(); err != nil {
-			return err
-		}
+	diagramType := p.advance().Value
+	switch strings.ToLower(diagramType) {
+	case "c4context":
+		p.diagram = ast.NewC4ContextDiagram()
+	case "c4container":
+		p.diagram = ast.NewC4ContainerDiagram()
+	case "c4component":
+		p.diagram = ast.NewC4ComponentDiagram()
+	case "c4dynamic":
+		p.diagram = ast.NewC4DynamicDiagram()
+	case "c4deployment":
+		p.diagram = ast.NewC4DeploymentDiagram()
+	default:
+		return p.error("unsupported C4 diagram type: " + diagramType)
 	}
 
 	return nil
 }
 
-// parseStatement parses individual C4 diagram statements
+// parseStatement parses individual C4 statements
 func (p *C4Parser) parseStatement() error {
 	if p.isAtEnd() {
 		return nil
@@ -81,13 +95,32 @@ func (p *C4Parser) parseStatement() error {
 		return nil
 	case p.checkKeyword("title"):
 		return p.parseTitle()
-	case p.checkKeyword("Boundary"):
-		return p.parseBoundary()
+	case p.checkKeyword("person"):
+		return p.parsePerson()
+	case p.checkKeyword("system"):
+		return p.parseSystem()
+	case p.checkKeyword("container"):
+		return p.parseContainer()
+	case p.checkKeyword("component"):
+		return p.parseComponent()
+	case p.checkKeyword("system_boundary"):
+		return p.parseSystemBoundary()
+	case p.checkKeyword("container_boundary"):
+		return p.parseContainerBoundary()
+	case p.checkKeyword("system_ext"):
+		return p.parseSystemExt()
+	case p.checkKeyword("container_ext"):
+		return p.parseContainerExt()
+	case p.checkKeyword("systemdb"):
+		return p.parseSystemDb()
+	case p.checkKeyword("containerdb"):
+		return p.parseContainerDb()
+	case p.checkKeyword("containerqueue"):
+		return p.parseContainerQueue()
+	case p.check(lexer.TokenID):
+		// Could be a relation
+		return p.parseRelation()
 	default:
-		// Try to parse as element or relation definition
-		if p.check(lexer.TokenID) {
-			return p.parseElementOrRelation()
-		}
 		token := p.peek()
 		return p.error(fmt.Sprintf("unexpected token: %s", token.Value))
 	}
@@ -104,115 +137,478 @@ func (p *C4Parser) parseTitle() error {
 
 	if len(titleParts) > 0 {
 		title := strings.TrimSpace(strings.Join(titleParts, " "))
-		p.diagram.Title = &title
+		// Set title on the diagram
+		if ctx, ok := p.diagram.(*ast.C4ContextDiagram); ok {
+			ctx.Title = &title
+		} else if container, ok := p.diagram.(*ast.C4ContainerDiagram); ok {
+			container.Title = &title
+		} else if component, ok := p.diagram.(*ast.C4ComponentDiagram); ok {
+			component.Title = &title
+		} else if dynamic, ok := p.diagram.(*ast.C4DynamicDiagram); ok {
+			dynamic.Title = &title
+		} else if deployment, ok := p.diagram.(*ast.C4DeploymentDiagram); ok {
+			deployment.Title = &title
+		}
 	}
 
 	return nil
 }
 
-// parseBoundary parses boundary definitions
-func (p *C4Parser) parseBoundary() error {
-	p.advance() // consume 'Boundary'
+// parsePerson parses Person statements
+func (p *C4Parser) parsePerson() error {
+	p.advance() // consume 'person'
+
+	if !p.check(lexer.TokenOpenParen) {
+		return p.error("expected '(' after Person")
+	}
+	p.advance() // consume '('
 
 	if !p.check(lexer.TokenID) {
-		return p.error("expected boundary ID")
+		return p.error("expected Person ID")
 	}
+	personID := p.advance().Value
 
-	id := p.advance().Value
-	label := id // Default label is the ID
+	if !p.check(lexer.TokenComma) {
+		return p.error("expected ',' after Person ID")
+	}
+	p.advance() // consume ','
 
-	// Parse label if specified
-	if p.check(lexer.TokenString) {
-		label = p.advance().Value
-		// Remove quotes
-		if strings.HasPrefix(label, "\"") && strings.HasSuffix(label, "\"") {
-			label = label[1 : len(label)-1]
+	// Parse name (quoted string)
+	var nameParts []string
+	for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+		nameParts = append(nameParts, p.advance().Value)
+	}
+	name := strings.Trim(strings.Join(nameParts, " "), "\"")
+
+	// Parse description (optional)
+	var description string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var descParts []string
+		for !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			descParts = append(descParts, p.advance().Value)
 		}
+		description = strings.Trim(strings.Join(descParts, " "), "\"")
+	}
+
+	if !p.check(lexer.TokenCloseParen) {
+		return p.error("expected ')' to close Person")
 	}
+	p.advance() // consume ')'
 
 	element := &ast.C4Element{
-		ID:    id,
-		Label: label,
-		Type:  ast.C4ElementBoundary,
+		ID:          personID,
+		Type:        ast.C4ElementPerson,
+		Name:        name,
+		Description: description,
 	}
 
 	p.diagram.AddElement(element)
 	return nil
 }
 
-// parseElementOrRelation parses element or relation definitions
-func (p *C4Parser) parseElementOrRelation() error {
-	// Parse element ID
-	elementID := p.advance().Value
+// parseSystem parses System statements
+func (p *C4Parser) parseSystem() error {
+	p.advance() // consume 'system'
+
+	if !p.check(lexer.TokenOpenParen) {
+		return p.error("expected '(' after System")
+	}
+	p.advance() // consume '('
+
+	if !p.check(lexer.TokenID) {
+		return p.error("expected System ID")
+	}
+	systemID := p.advance().Value
 
-	// Check if this is a relation (has arrow)
-	if p.check(lexer.TokenArrowSolid) || p.check(lexer.TokenArrowDotted) {
-		return p.parseRelation(elementID)
+	if !p.check(lexer.TokenComma) {
+		return p.error("expected ',' after System ID")
+	}
+	p.advance() // consume ','
+
+	// Parse name (quoted string)
+	var nameParts []string
+	for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+		nameParts = append(nameParts, p.advance().Value)
+	}
+	name := strings.Trim(strings.Join(nameParts, " "), "\"")
+
+	// Parse description (optional)
+	var description string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var descParts []string
+		for !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			descParts = append(descParts, p.advance().Value)
+		}
+		description = strings.Trim(strings.Join(descParts, " "), "\"")
+	}
+
+	if !p.check(lexer.TokenCloseParen) {
+		return p.error("expected ')' to close System")
+	}
+	p.advance() // consume ')'
+
+	element := &ast.C4Element{
+		ID:          systemID,
+		Type:        ast.C4ElementSystem,
+		Name:        name,
+		Description: description,
 	}
 
-	// Otherwise, parse as element definition
-	return p.parseElement(elementID)
+	p.diagram.AddElement(element)
+	return nil
 }
 
-// parseElement parses element definitions
-func (p *C4Parser) parseElement(id string) error {
-	label := id                        // Default label is the ID
-	elementType := ast.C4ElementSystem // Default type
-
-	// Parse type if specified
-	if p.checkKeyword("Person") || p.checkKeyword("Person_Ext") ||
-		p.checkKeyword("System") || p.checkKeyword("System_Ext") ||
-		p.checkKeyword("SystemDb") || p.checkKeyword("Container") ||
-		p.checkKeyword("Container_Ext") || p.checkKeyword("ContainerDb") ||
-		p.checkKeyword("Component") || p.checkKeyword("Component_Ext") ||
-		p.checkKeyword("ComponentDb") {
-		typeStr := p.advance().Value
-		elementType = ast.C4ElementType(strings.ToLower(typeStr))
-	}
-
-	// Parse label if specified
-	if p.check(lexer.TokenString) {
-		label = p.advance().Value
-		// Remove quotes
-		if strings.HasPrefix(label, "\"") && strings.HasSuffix(label, "\"") {
-			label = label[1 : len(label)-1]
+// parseContainer parses Container statements
+func (p *C4Parser) parseContainer() error {
+	p.advance() // consume 'container'
+
+	if !p.check(lexer.TokenOpenParen) {
+		return p.error("expected '(' after Container")
+	}
+	p.advance() // consume '('
+
+	if !p.check(lexer.TokenID) {
+		return p.error("expected Container ID")
+	}
+	containerID := p.advance().Value
+
+	if !p.check(lexer.TokenComma) {
+		return p.error("expected ',' after Container ID")
+	}
+	p.advance() // consume ','
+
+	// Parse name (quoted string)
+	var nameParts []string
+	for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+		nameParts = append(nameParts, p.advance().Value)
+	}
+	name := strings.Trim(strings.Join(nameParts, " "), "\"")
+
+	// Parse technology (optional)
+	var technology string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var techParts []string
+		for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			techParts = append(techParts, p.advance().Value)
 		}
+		technology = strings.Trim(strings.Join(techParts, " "), "\"")
 	}
 
+	// Parse description (optional)
+	var description string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var descParts []string
+		for !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			descParts = append(descParts, p.advance().Value)
+		}
+		description = strings.Trim(strings.Join(descParts, " "), "\"")
+	}
+
+	if !p.check(lexer.TokenCloseParen) {
+		return p.error("expected ')' to close Container")
+	}
+	p.advance() // consume ')'
+
 	element := &ast.C4Element{
-		ID:    id,
-		Label: label,
-		Type:  elementType,
+		ID:          containerID,
+		Type:        ast.C4ElementContainer,
+		Name:        name,
+		Description: description,
+	}
+
+	if technology != "" {
+		element.Technology = &technology
 	}
 
 	p.diagram.AddElement(element)
 	return nil
 }
 
-// parseRelation parses relation definitions
-func (p *C4Parser) parseRelation(from string) error {
-	// Parse arrow type
-	p.advance() // consume arrow
+// parseComponent parses Component statements
+func (p *C4Parser) parseComponent() error {
+	p.advance() // consume 'component'
+
+	if !p.check(lexer.TokenOpenParen) {
+		return p.error("expected '(' after Component")
+	}
+	p.advance() // consume '('
 
-	// Parse target element
 	if !p.check(lexer.TokenID) {
-		return p.error("expected target element ID")
+		return p.error("expected Component ID")
 	}
-	to := p.advance().Value
+	componentID := p.advance().Value
 
-	relation := &ast.C4Relation{
-		From: from,
-		To:   to,
+	if !p.check(lexer.TokenComma) {
+		return p.error("expected ',' after Component ID")
+	}
+	p.advance() // consume ','
+
+	// Parse name (quoted string)
+	var nameParts []string
+	for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+		nameParts = append(nameParts, p.advance().Value)
+	}
+	name := strings.Trim(strings.Join(nameParts, " "), "\"")
+
+	// Parse technology (optional)
+	var technology string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var techParts []string
+		for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			techParts = append(techParts, p.advance().Value)
+		}
+		technology = strings.Trim(strings.Join(techParts, " "), "\"")
+	}
+
+	// Parse description (optional)
+	var description string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var descParts []string
+		for !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			descParts = append(descParts, p.advance().Value)
+		}
+		description = strings.Trim(strings.Join(descParts, " "), "\"")
+	}
+
+	if !p.check(lexer.TokenCloseParen) {
+		return p.error("expected ')' to close Component")
+	}
+	p.advance() // consume ')'
+
+	element := &ast.C4Element{
+		ID:          componentID,
+		Type:        ast.C4ElementComponent,
+		Name:        name,
+		Description: description,
+	}
+
+	if technology != "" {
+		element.Technology = &technology
+	}
+
+	p.diagram.AddElement(element)
+	return nil
+}
+
+// parseSystemBoundary parses System_Boundary statements
+func (p *C4Parser) parseSystemBoundary() error {
+	p.advance() // consume 'system_boundary'
+
+	if !p.check(lexer.TokenOpenParen) {
+		return p.error("expected '(' after System_Boundary")
+	}
+	p.advance() // consume '('
+
+	if !p.check(lexer.TokenID) {
+		return p.error("expected System_Boundary ID")
+	}
+	boundaryID := p.advance().Value
+
+	if !p.check(lexer.TokenComma) {
+		return p.error("expected ',' after System_Boundary ID")
+	}
+	p.advance() // consume ','
+
+	// Parse name (quoted string)
+	var nameParts []string
+	for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.check(lexer.TokenOpenBrace) && !p.isAtEnd() {
+		nameParts = append(nameParts, p.advance().Value)
+	}
+	name := strings.Trim(strings.Join(nameParts, " "), "\"")
+
+	// Skip comma if present
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+	}
+
+	// Check if there's a closing parenthesis before the brace
+	if p.check(lexer.TokenCloseParen) {
+		p.advance() // consume ')'
 	}
 
-	// Parse label if specified
-	if p.check(lexer.TokenString) {
-		label := p.advance().Value
-		// Remove quotes
-		if strings.HasPrefix(label, "\"") && strings.HasSuffix(label, "\"") {
-			label = label[1 : len(label)-1]
+	if !p.check(lexer.TokenOpenBrace) {
+		return p.error("expected '{' to start System_Boundary")
+	}
+	p.advance() // consume '{'
+
+	boundary := &ast.C4Boundary{
+		ID:       boundaryID,
+		Type:     ast.C4BoundarySystem,
+		Name:     name,
+		Elements: make([]string, 0),
+	}
+
+	// Parse elements within boundary
+	for !p.check(lexer.TokenCloseBrace) && !p.isAtEnd() {
+		if err := p.parseStatement(); err != nil {
+			return err
+		}
+		// Add the last parsed element to this boundary
+		if len(p.diagram.(C4DiagramInterface).(*ast.C4ContextDiagram).Elements) > 0 {
+			lastElement := p.diagram.(C4DiagramInterface).(*ast.C4ContextDiagram).Elements[len(p.diagram.(C4DiagramInterface).(*ast.C4ContextDiagram).Elements)-1]
+			boundary.Elements = append(boundary.Elements, lastElement.ID)
 		}
-		relation.Label = &label
+	}
+
+	if !p.check(lexer.TokenCloseBrace) {
+		return p.error("expected '}' to close System_Boundary")
+	}
+	p.advance() // consume '}'
+
+	p.diagram.AddBoundary(boundary)
+	return nil
+}
+
+// parseContainerBoundary parses Container_Boundary statements
+func (p *C4Parser) parseContainerBoundary() error {
+	// Similar to parseSystemBoundary but for containers
+	return p.parseSystemBoundary() // Simplified for now
+}
+
+// parseSystemExt parses System_Ext statements
+func (p *C4Parser) parseSystemExt() error {
+	// Similar to parseSystem but marked as external
+	return p.parseSystem() // Simplified for now
+}
+
+// parseContainerExt parses Container_Ext statements
+func (p *C4Parser) parseContainerExt() error {
+	// Similar to parseContainer but marked as external
+	return p.parseContainer() // Simplified for now
+}
+
+// parseSystemDb parses SystemDb statements
+func (p *C4Parser) parseSystemDb() error {
+	p.advance() // consume 'systemdb'
+
+	if !p.check(lexer.TokenOpenParen) {
+		return p.error("expected '(' after SystemDb")
+	}
+	p.advance() // consume '('
+
+	if !p.check(lexer.TokenID) {
+		return p.error("expected SystemDb ID")
+	}
+	dbID := p.advance().Value
+
+	if !p.check(lexer.TokenComma) {
+		return p.error("expected ',' after SystemDb ID")
+	}
+	p.advance() // consume ','
+
+	// Parse name (quoted string)
+	var nameParts []string
+	for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+		nameParts = append(nameParts, p.advance().Value)
+	}
+	name := strings.Trim(strings.Join(nameParts, " "), "\"")
+
+	// Parse description (optional)
+	var description string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var descParts []string
+		for !p.check(lexer.TokenComma) && !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			descParts = append(descParts, p.advance().Value)
+		}
+		description = strings.Trim(strings.Join(descParts, " "), "\"")
+	}
+
+	// Parse technology (optional)
+	var technology string
+	if p.check(lexer.TokenComma) {
+		p.advance() // consume ','
+		var techParts []string
+		for !p.check(lexer.TokenCloseParen) && !p.isAtEnd() {
+			techParts = append(techParts, p.advance().Value)
+		}
+		technology = strings.Trim(strings.Join(techParts, " "), "\"")
+	}
+
+	if !p.check(lexer.TokenCloseParen) {
+		return p.error("expected ')' to close SystemDb")
+	}
+	p.advance() // consume ')'
+
+	element := &ast.C4Element{
+		ID:          dbID,
+		Type:        ast.C4ElementDatabase,
+		Name:        name,
+		Description: description,
+	}
+
+	if technology != "" {
+		element.Technology = &technology
+	}
+
+	p.diagram.AddElement(element)
+	return nil
+}
+
+// parseContainerDb parses ContainerDb statements
+func (p *C4Parser) parseContainerDb() error {
+	return p.parseSystemDb() // Similar implementation
+}
+
+// parseContainerQueue parses ContainerQueue statements
+func (p *C4Parser) parseContainerQueue() error {
+	// Similar to parseSystemDb but for queues
+	return p.parseSystemDb() // Simplified for now
+}
+
+// parseRelation parses relation statements
+func (p *C4Parser) parseRelation() error {
+	fromID := p.advance().Value
+
+	// Check for relation type
+	relationType := ast.C4RelationSync
+	if p.check(lexer.TokenArrowSolid) {
+		p.advance() // consume '-->'
+	} else if p.check(lexer.TokenMinus) {
+		p.advance() // consume first '-'
+		if p.check(lexer.TokenMinus) {
+			p.advance() // consume second '-'
+			if p.check(lexer.TokenCloseAngle) {
+				p.advance() // consume '>'
+			}
+		} else if p.check(lexer.TokenCloseAngle) {
+			p.advance() // consume '>'
+		}
+	}
+
+	if !p.check(lexer.TokenID) {
+		return p.error("expected target ID for relation")
+	}
+	toID := p.advance().Value
+
+	// Parse optional label
+	var label *string
+	if p.check(lexer.TokenColon) {
+		p.advance() // consume ':'
+		var labelParts []string
+		for !p.check(lexer.TokenNewline) && !p.isAtEnd() {
+			labelParts = append(labelParts, p.advance().Value)
+		}
+		if len(labelParts) > 0 {
+			labelText := strings.TrimSpace(strings.Join(labelParts, " "))
+			label = &labelText
+		}
+	}
+
+	relation := &ast.C4Relation{
+		From: fromID,
+		To:   toID,
+		Type: relationType,
+	}
+
+	if label != nil {
+		relation.Label = label
 	}
 
 	p.diagram.AddRelation(relation)

+ 10 - 0
pkg/parser/main.go

@@ -60,6 +60,16 @@ func (p *MermaidParser) Parse(input string) (ast.Diagram, error) {
 		return p.parseBlock(input)
 	case detector.DiagramTypeC4:
 		return p.parseC4(input)
+	case detector.DiagramTypeC4Context:
+		return p.parseC4(input)
+	case detector.DiagramTypeC4Container:
+		return p.parseC4(input)
+	case detector.DiagramTypeC4Component:
+		return p.parseC4(input)
+	case detector.DiagramTypeC4Dynamic:
+		return p.parseC4(input)
+	case detector.DiagramTypeC4Deployment:
+		return p.parseC4(input)
 	case detector.DiagramTypeArchitecture:
 		return p.parseArchitecture(input)
 	case detector.DiagramTypeRadar:

+ 273 - 25
pkg/renderer/c4.go

@@ -9,46 +9,294 @@ import (
 )
 
 // C4Renderer implements C4 diagram rendering
-type C4Renderer struct{}
+type C4Renderer struct {
+	diagram ast.Diagram
+}
 
 // NewC4Renderer creates a new C4 renderer
-func NewC4Renderer() *C4Renderer {
-	return &C4Renderer{}
+func NewC4Renderer(diagram ast.Diagram) *C4Renderer {
+	return &C4Renderer{
+		diagram: diagram,
+	}
+}
+
+// Render renders the C4 diagram to Mermaid syntax
+func (r *C4Renderer) Render() (string, error) {
+	var builder strings.Builder
+
+	// Render based on diagram type
+	switch d := r.diagram.(type) {
+	case *ast.C4ContextDiagram:
+		return r.renderC4Context(d, &builder)
+	case *ast.C4ContainerDiagram:
+		return r.renderC4Container(d, &builder)
+	case *ast.C4ComponentDiagram:
+		return r.renderC4Component(d, &builder)
+	case *ast.C4DynamicDiagram:
+		return r.renderC4Dynamic(d, &builder)
+	case *ast.C4DeploymentDiagram:
+		return r.renderC4Deployment(d, &builder)
+	default:
+		return "", fmt.Errorf("unsupported C4 diagram type: %T", d)
+	}
+}
+
+// renderC4Context renders a C4 Context diagram
+func (r *C4Renderer) renderC4Context(diagram *ast.C4ContextDiagram, builder *strings.Builder) (string, error) {
+	builder.WriteString("C4Context\n")
+
+	// Render title
+	if diagram.Title != nil {
+		builder.WriteString(fmt.Sprintf("    title %s\n", *diagram.Title))
+	}
+
+	// Render elements
+	for _, element := range diagram.Elements {
+		r.renderElement(element, builder)
+	}
+
+	// Render boundaries
+	for _, boundary := range diagram.Boundaries {
+		r.renderBoundary(boundary, diagram, builder)
+	}
+
+	// Render relations
+	for _, relation := range diagram.Relations {
+		r.renderRelation(relation, builder)
+	}
+
+	return builder.String(), nil
+}
+
+// renderC4Container renders a C4 Container diagram
+func (r *C4Renderer) renderC4Container(diagram *ast.C4ContainerDiagram, builder *strings.Builder) (string, error) {
+	builder.WriteString("C4Container\n")
+
+	// Render title
+	if diagram.Title != nil {
+		builder.WriteString(fmt.Sprintf("    title %s\n", *diagram.Title))
+	}
+
+	// Render elements
+	for _, element := range diagram.Elements {
+		r.renderElement(element, builder)
+	}
+
+	// Render boundaries
+	for _, boundary := range diagram.Boundaries {
+		r.renderBoundary(boundary, diagram, builder)
+	}
+
+	// Render relations
+	for _, relation := range diagram.Relations {
+		r.renderRelation(relation, builder)
+	}
+
+	return builder.String(), nil
+}
+
+// renderC4Component renders a C4 Component diagram
+func (r *C4Renderer) renderC4Component(diagram *ast.C4ComponentDiagram, builder *strings.Builder) (string, error) {
+	builder.WriteString("C4Component\n")
+
+	// Render title
+	if diagram.Title != nil {
+		builder.WriteString(fmt.Sprintf("    title %s\n", *diagram.Title))
+	}
+
+	// Render elements
+	for _, element := range diagram.Elements {
+		r.renderElement(element, builder)
+	}
+
+	// Render boundaries
+	for _, boundary := range diagram.Boundaries {
+		r.renderBoundary(boundary, diagram, builder)
+	}
+
+	// Render relations
+	for _, relation := range diagram.Relations {
+		r.renderRelation(relation, builder)
+	}
+
+	return builder.String(), nil
 }
 
-// Render renders a C4 diagram to mermaid syntax
-func (r *C4Renderer) Render(diagram *ast.C4Diagram) (string, error) {
-	var result strings.Builder
+// renderC4Dynamic renders a C4 Dynamic diagram
+func (r *C4Renderer) renderC4Dynamic(diagram *ast.C4DynamicDiagram, builder *strings.Builder) (string, error) {
+	builder.WriteString("C4Dynamic\n")
 
-	// Start with C4Context keyword (assuming context level)
-	result.WriteString("C4Context\n")
+	// Render title
+	if diagram.Title != nil {
+		builder.WriteString(fmt.Sprintf("    title %s\n", *diagram.Title))
+	}
+
+	// Render elements
+	for _, element := range diagram.Elements {
+		r.renderElement(element, builder)
+	}
+
+	// Render boundaries
+	for _, boundary := range diagram.Boundaries {
+		r.renderBoundary(boundary, diagram, builder)
+	}
+
+	// Render relations
+	for _, relation := range diagram.Relations {
+		r.renderRelation(relation, builder)
+	}
+
+	return builder.String(), nil
+}
 
-	// Add title if present
+// renderC4Deployment renders a C4 Deployment diagram
+func (r *C4Renderer) renderC4Deployment(diagram *ast.C4DeploymentDiagram, builder *strings.Builder) (string, error) {
+	builder.WriteString("C4Deployment\n")
+
+	// Render title
 	if diagram.Title != nil {
-		result.WriteString(fmt.Sprintf("  title %s\n", *diagram.Title))
+		builder.WriteString(fmt.Sprintf("    title %s\n", *diagram.Title))
 	}
 
 	// Render elements
 	for _, element := range diagram.Elements {
-		result.WriteString(fmt.Sprintf("  %s(%s, \"%s\")",
-			string(element.Type), element.ID, element.Label))
-		if element.Technology != nil {
-			result.WriteString(fmt.Sprintf(" : %s", *element.Technology))
-		}
-		result.WriteString("\n")
+		r.renderElement(element, builder)
+	}
+
+	// Render boundaries
+	for _, boundary := range diagram.Boundaries {
+		r.renderBoundary(boundary, diagram, builder)
 	}
 
 	// Render relations
 	for _, relation := range diagram.Relations {
-		result.WriteString(fmt.Sprintf("  %s --> %s", relation.From, relation.To))
-		if relation.Label != nil {
-			result.WriteString(fmt.Sprintf(" : %s", *relation.Label))
-		}
-		if relation.Technology != nil {
-			result.WriteString(fmt.Sprintf(" : %s", *relation.Technology))
-		}
-		result.WriteString("\n")
+		r.renderRelation(relation, builder)
+	}
+
+	return builder.String(), nil
+}
+
+// renderElement renders a C4 element
+func (r *C4Renderer) renderElement(element *ast.C4Element, builder *strings.Builder) {
+	switch element.Type {
+	case ast.C4ElementPerson:
+		r.renderPerson(element, builder)
+	case ast.C4ElementSystem:
+		r.renderSystem(element, builder)
+	case ast.C4ElementContainer:
+		r.renderContainer(element, builder)
+	case ast.C4ElementComponent:
+		r.renderComponent(element, builder)
+	case ast.C4ElementDatabase:
+		r.renderDatabase(element, builder)
+	case ast.C4ElementQueue:
+		r.renderQueue(element, builder)
+	case ast.C4ElementExternal:
+		r.renderExternal(element, builder)
+	}
+}
+
+// renderPerson renders a Person element
+func (r *C4Renderer) renderPerson(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    Person(%s, \"%s\"", element.ID, element.Name))
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
+	}
+	builder.WriteString(")\n")
+}
+
+// renderSystem renders a System element
+func (r *C4Renderer) renderSystem(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    System(%s, \"%s\"", element.ID, element.Name))
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
 	}
+	builder.WriteString(")\n")
+}
+
+// renderContainer renders a Container element
+func (r *C4Renderer) renderContainer(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    Container(%s, \"%s\"", element.ID, element.Name))
+	if element.Technology != nil {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", *element.Technology))
+	}
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
+	}
+	builder.WriteString(")\n")
+}
+
+// renderComponent renders a Component element
+func (r *C4Renderer) renderComponent(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    Component(%s, \"%s\"", element.ID, element.Name))
+	if element.Technology != nil {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", *element.Technology))
+	}
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
+	}
+	builder.WriteString(")\n")
+}
 
-	return result.String(), nil
+// renderDatabase renders a Database element
+func (r *C4Renderer) renderDatabase(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    SystemDb(%s, \"%s\"", element.ID, element.Name))
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
+	}
+	if element.Technology != nil {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", *element.Technology))
+	}
+	builder.WriteString(")\n")
+}
+
+// renderQueue renders a Queue element
+func (r *C4Renderer) renderQueue(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    ContainerQueue(%s, \"%s\"", element.ID, element.Name))
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
+	}
+	if element.Technology != nil {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", *element.Technology))
+	}
+	builder.WriteString(")\n")
+}
+
+// renderExternal renders an External element
+func (r *C4Renderer) renderExternal(element *ast.C4Element, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    System_Ext(%s, \"%s\"", element.ID, element.Name))
+	if element.Description != "" {
+		builder.WriteString(fmt.Sprintf(", \"%s\"", element.Description))
+	}
+	builder.WriteString(")\n")
+}
+
+// renderBoundary renders a boundary
+func (r *C4Renderer) renderBoundary(boundary *ast.C4Boundary, diagram ast.Diagram, builder *strings.Builder) {
+	switch boundary.Type {
+	case ast.C4BoundarySystem:
+		builder.WriteString(fmt.Sprintf("    System_Boundary(%s, \"%s\") {\n", boundary.ID, boundary.Name))
+	case ast.C4BoundaryContainer:
+		builder.WriteString(fmt.Sprintf("    Container_Boundary(%s, \"%s\") {\n", boundary.ID, boundary.Name))
+	}
+
+	// Render elements within boundary
+	// Note: This is a simplified implementation
+	// In a full implementation, we would need to access the diagram's elements
+	for _, elementID := range boundary.Elements {
+		// For now, we'll skip rendering elements within boundaries
+		// This would need to be implemented with proper access to diagram elements
+		_ = elementID
+	}
+
+	builder.WriteString("    }\n")
+}
+
+// renderRelation renders a relation
+func (r *C4Renderer) renderRelation(relation *ast.C4Relation, builder *strings.Builder) {
+	builder.WriteString(fmt.Sprintf("    %s --> %s", relation.From, relation.To))
+	if relation.Label != nil {
+		builder.WriteString(fmt.Sprintf(" : %s", *relation.Label))
+	}
+	builder.WriteString("\n")
 }

+ 15 - 3
pkg/renderer/mermaid.go

@@ -81,9 +81,21 @@ func (r *MermaidRenderer) Render(diagram ast.Diagram) (string, error) {
 	case *ast.InfoDiagram:
 		renderer := NewInfoRenderer()
 		return renderer.Render(d)
-	case *ast.C4Diagram:
-		renderer := NewC4Renderer()
-		return renderer.Render(d)
+	case *ast.C4ContextDiagram:
+		renderer := NewC4Renderer(d)
+		return renderer.Render()
+	case *ast.C4ContainerDiagram:
+		renderer := NewC4Renderer(d)
+		return renderer.Render()
+	case *ast.C4ComponentDiagram:
+		renderer := NewC4Renderer(d)
+		return renderer.Render()
+	case *ast.C4DynamicDiagram:
+		renderer := NewC4Renderer(d)
+		return renderer.Render()
+	case *ast.C4DeploymentDiagram:
+		renderer := NewC4Renderer(d)
+		return renderer.Render()
 	case *ast.QuadrantChart:
 		return r.renderQuadrantChart(d)
 	case *ast.RequirementDiagram: