...
1 package d2plugin
2
3 import (
4 "fmt"
5
6 "oss.terrastruct.com/d2/d2graph"
7 )
8
9 type PluginFeature string
10
11
12
13 const NEAR_OBJECT PluginFeature = "near_object"
14
15
16 const CONTAINER_DIMENSIONS PluginFeature = "container_dimensions"
17
18
19 const TOP_LEFT PluginFeature = "top_left"
20
21
22 const DESCENDANT_EDGES PluginFeature = "descendant_edges"
23
24
25 const ROUTES_EDGES PluginFeature = "routes_edges"
26
27 func FeatureSupportCheck(info *PluginInfo, g *d2graph.Graph) error {
28
29 if info.Features == nil {
30 return nil
31 }
32
33 featureMap := make(map[PluginFeature]struct{}, len(info.Features))
34 for _, f := range info.Features {
35 featureMap[f] = struct{}{}
36 }
37
38 for _, obj := range g.Objects {
39 if obj.Top != nil || obj.Left != nil {
40 if _, ok := featureMap[TOP_LEFT]; !ok {
41 return fmt.Errorf(`Object "%s" has attribute "top" and/or "left" set, but layout engine "%s" does not support locked positions. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`, obj.AbsID(), info.Name)
42 }
43 }
44 if (obj.WidthAttr != nil || obj.HeightAttr != nil) &&
45 len(obj.ChildrenArray) > 0 && !obj.IsGridDiagram() {
46 if _, ok := featureMap[CONTAINER_DIMENSIONS]; !ok {
47 return fmt.Errorf(`Object "%s" has attribute "width" and/or "height" set, but layout engine "%s" does not support dimensions set on containers. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`, obj.AbsID(), info.Name)
48 }
49 }
50
51 if obj.NearKey != nil {
52 _, isKey := g.Root.HasChild(d2graph.Key(obj.NearKey))
53 if isKey {
54 if _, ok := featureMap[NEAR_OBJECT]; !ok {
55 return fmt.Errorf(`Object "%s" has "near" set to another object, but layout engine "%s" only supports constant values for "near". See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`, obj.AbsID(), info.Name)
56 }
57 }
58 }
59 }
60 if _, ok := featureMap[DESCENDANT_EDGES]; !ok {
61 for _, e := range g.Edges {
62
63 if e.Src.OuterSequenceDiagram() != nil || e.Dst.OuterSequenceDiagram() != nil {
64 continue
65 }
66 if !e.Src.IsContainer() && !e.Dst.IsContainer() {
67 continue
68 }
69 if e.Src == e.Dst {
70 return fmt.Errorf(`Connection "%s" is a self loop on a container, but layout engine "%s" does not support this. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`, e.AbsID(), info.Name)
71 }
72 if e.Src.IsDescendantOf(e.Dst) || e.Dst.IsDescendantOf(e.Src) {
73 return fmt.Errorf(`Connection "%s" goes from a container to a descendant, but layout engine "%s" does not support this. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`, e.AbsID(), info.Name)
74 }
75 }
76 }
77 return nil
78 }
79
View as plain text