-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodels.go
More file actions
153 lines (137 loc) · 5 KB
/
models.go
File metadata and controls
153 lines (137 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package flow
// Models for flow diagrams — the single source of truth for every renderer.
// Mirrors src/main/java/.../flow/FlowModels.java.
// Node is one node in a flow diagram. The diagram is a collapsed /
// summarized view of the underlying graph, so a single flow Node frequently
// represents a *category* of graph nodes (e.g. "Endpoints x42").
type Node struct {
ID string `json:"id"`
Label string `json:"label"`
Kind string `json:"kind"`
Style string `json:"style"`
Properties map[string]any `json:"properties"`
}
// NewNode constructs a Node with default style ("default") and empty
// properties. Use NewNodeWithProps / NewNodeWithStyle for richer cases.
func NewNode(id, label, kind string) Node {
return Node{ID: id, Label: label, Kind: kind, Style: "default", Properties: map[string]any{}}
}
// NewNodeWithProps constructs a Node with the supplied properties map.
func NewNodeWithProps(id, label, kind string, props map[string]any) Node {
if props == nil {
props = map[string]any{}
}
return Node{ID: id, Label: label, Kind: kind, Style: "default", Properties: props}
}
// NewNodeWithStyle constructs a Node with an explicit style class
// (default | success | warning | danger). The style maps to Mermaid
// classDef and DOT color attributes.
func NewNodeWithStyle(id, label, kind, style string, props map[string]any) Node {
if props == nil {
props = map[string]any{}
}
return Node{ID: id, Label: label, Kind: kind, Style: style, Properties: props}
}
// Edge is one edge in a flow diagram. Edges are filtered against the set
// of valid node IDs during rendering — dangling edges are dropped.
type Edge struct {
Source string `json:"source"`
Target string `json:"target"`
Label string `json:"label,omitempty"`
Style string `json:"style"`
}
// NewEdge constructs a solid, unlabelled edge.
func NewEdge(source, target string) Edge {
return Edge{Source: source, Target: target, Style: "solid"}
}
// NewLabelEdge constructs a solid edge with a label.
func NewLabelEdge(source, target, label string) Edge {
return Edge{Source: source, Target: target, Label: label, Style: "solid"}
}
// NewStyledEdge constructs an edge with an explicit style
// (solid | dotted | thick).
func NewStyledEdge(source, target, label, style string) Edge {
return Edge{Source: source, Target: target, Label: label, Style: style}
}
// Subgraph is a labelled group of nodes. Subgraphs may declare a
// drill-down view that the UI follows when the user expands the group.
type Subgraph struct {
ID string `json:"id"`
Label string `json:"label"`
Nodes []Node `json:"nodes"`
DrillDownView string `json:"drill_down_view,omitempty"`
ParentView string `json:"parent_view,omitempty"`
}
// NewSubgraph constructs a subgraph with no drill-down hint.
func NewSubgraph(id, label string, nodes []Node) Subgraph {
if nodes == nil {
nodes = []Node{}
}
return Subgraph{ID: id, Label: label, Nodes: nodes}
}
// NewSubgraphWithDrillDown constructs a subgraph with a drill-down view.
func NewSubgraphWithDrillDown(id, label string, nodes []Node, drillDownView string) Subgraph {
if nodes == nil {
nodes = []Node{}
}
return Subgraph{ID: id, Label: label, Nodes: nodes, DrillDownView: drillDownView}
}
// Diagram is the complete flow diagram. Renderers consume this structure
// directly; no other shape is exposed.
type Diagram struct {
Title string `json:"title"`
View string `json:"view"`
Direction string `json:"direction"`
Subgraphs []Subgraph `json:"subgraphs"`
LooseNodes []Node `json:"loose_nodes"`
Edges []Edge `json:"edges"`
Stats map[string]any `json:"stats"`
}
// NewDiagram constructs an empty diagram for the supplied view with the
// default left-to-right ("LR") direction and pre-allocated slices/maps.
func NewDiagram(title, view string) *Diagram {
return &Diagram{
Title: title,
View: view,
Direction: "LR",
Subgraphs: []Subgraph{},
LooseNodes: []Node{},
Edges: []Edge{},
Stats: map[string]any{},
}
}
// AllNodes returns every node across both loose nodes and subgraph nodes.
// Order matches the Java side: loose nodes first, then each subgraph's
// nodes in subgraph order.
func (d *Diagram) AllNodes() []Node {
if d == nil {
return nil
}
out := make([]Node, 0, len(d.LooseNodes))
out = append(out, d.LooseNodes...)
for _, sg := range d.Subgraphs {
out = append(out, sg.Nodes...)
}
return out
}
// ValidEdges returns the edges whose source AND target IDs exist on a node
// in the diagram. Dangling references are silently dropped — matches the
// Java side's FlowDiagram.toMap behaviour.
func (d *Diagram) ValidEdges() []Edge {
if d == nil {
return nil
}
ids := make(map[string]struct{}, len(d.LooseNodes))
for _, n := range d.AllNodes() {
ids[n.ID] = struct{}{}
}
out := make([]Edge, 0, len(d.Edges))
for _, e := range d.Edges {
_, srcOK := ids[e.Source]
_, tgtOK := ids[e.Target]
if srcOK && tgtOK {
out = append(out, e)
}
}
return out
}