2023-02-19 05:51:55 +00:00
package d2plugin
import (
"fmt"
"oss.terrastruct.com/d2/d2graph"
)
type PluginFeature string
2023-04-13 17:19:58 +00:00
// When this is true, objects can set their `near` key to another object
2023-02-19 05:51:55 +00:00
// When this is false, objects can only set `near` to constants
const NEAR_OBJECT PluginFeature = "near_object"
// When this is true, containers can have dimensions set
const CONTAINER_DIMENSIONS PluginFeature = "container_dimensions"
// When this is true, objects can specify their `top` and `left` keywords
const TOP_LEFT PluginFeature = "top_left"
2023-02-22 20:15:59 +00:00
// When this is true, containers can have connections to descendants
const DESCENDANT_EDGES PluginFeature = "descendant_edges"
2023-02-19 05:51:55 +00:00
func FeatureSupportCheck ( info * PluginInfo , g * d2graph . Graph ) error {
// Older version of plugin. Skip checking.
if info . Features == nil {
return nil
}
2023-02-20 17:05:00 +00:00
featureMap := make ( map [ PluginFeature ] struct { } , len ( info . Features ) )
for _ , f := range info . Features {
featureMap [ f ] = struct { } { }
}
2023-02-19 05:51:55 +00:00
for _ , obj := range g . Objects {
2023-04-14 03:04:55 +00:00
if obj . Top != nil || obj . Left != nil {
2023-02-20 17:05:00 +00:00
if _ , ok := featureMap [ TOP_LEFT ] ; ! ok {
2023-02-19 05:51:55 +00:00
return fmt . Errorf ( ` Object "%s" has attribute "top" and/or "left" set, but layout engine "%s" does not support locked positions. ` , obj . AbsID ( ) , info . Name )
}
}
2023-04-14 03:04:55 +00:00
if ( obj . WidthAttr != nil || obj . HeightAttr != nil ) && len ( obj . ChildrenArray ) > 0 {
2023-02-20 17:05:00 +00:00
if _ , ok := featureMap [ CONTAINER_DIMENSIONS ] ; ! ok {
2023-02-19 05:51:55 +00:00
return fmt . Errorf ( ` Object "%s" has attribute "width" and/or "height" set, but layout engine "%s" does not support dimensions set on containers. ` , obj . AbsID ( ) , info . Name )
}
}
2023-04-14 03:04:55 +00:00
if obj . NearKey != nil {
_ , isKey := g . Root . HasChild ( d2graph . Key ( obj . NearKey ) )
2023-02-19 05:51:55 +00:00
if isKey {
2023-02-20 17:05:00 +00:00
if _ , ok := featureMap [ NEAR_OBJECT ] ; ! ok {
2023-02-19 05:51:55 +00:00
return fmt . Errorf ( ` Object "%s" has "near" set to another object, but layout engine "%s" only supports constant values for "near". ` , obj . AbsID ( ) , info . Name )
}
}
}
}
2023-02-22 20:15:59 +00:00
if _ , ok := featureMap [ DESCENDANT_EDGES ] ; ! ok {
for _ , e := range g . Edges {
2023-02-22 20:31:41 +00:00
// descendant edges are ok in sequence diagrams
if e . Src . OuterSequenceDiagram ( ) != nil || e . Dst . OuterSequenceDiagram ( ) != nil {
continue
}
if ! e . Src . IsContainer ( ) && ! e . Dst . IsContainer ( ) {
continue
}
if e . Src == e . Dst {
return fmt . Errorf ( ` Connection "%s" is a self loop on a container, but layout engine "%s" does not support this. ` , e . AbsID ( ) , info . Name )
}
2023-02-22 20:15:59 +00:00
if e . Src . IsDescendantOf ( e . Dst ) || e . Dst . IsDescendantOf ( e . Src ) {
return fmt . Errorf ( ` Connection "%s" goes from a container to a descendant, but layout engine "%s" does not support this. ` , e . AbsID ( ) , info . Name )
}
}
}
2023-02-19 05:51:55 +00:00
return nil
}