refactor d2graph.Attributes

This commit is contained in:
Gavin Nishizawa 2023-04-13 20:04:55 -07:00
parent 3c43db31d0
commit 214c95eefc
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
18 changed files with 564 additions and 572 deletions

View file

@ -150,7 +150,7 @@ func (c *compiler) compileMap(obj *d2graph.Object, m *d2ir.Map) {
c.compileField(obj, f)
}
switch obj.Attributes.Shape.Value {
switch obj.Shape.Value {
case d2target.ShapeClass:
c.compileClass(obj)
case d2target.ShapeSQLTable:
@ -191,25 +191,25 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
}
return
} else if isReserved {
c.compileReserved(obj.Attributes, f)
c.compileReserved(&obj.Attributes, f)
return
} else if f.Name == "style" {
if f.Map() == nil {
return
}
c.compileStyle(obj.Attributes, f.Map())
if obj.Attributes.Style.Animated != nil {
c.errorf(obj.Attributes.Style.Animated.MapKey, `key "animated" can only be applied to edges`)
c.compileStyle(&obj.Attributes, f.Map())
if obj.Style.Animated != nil {
c.errorf(obj.Style.Animated.MapKey, `key "animated" can only be applied to edges`)
}
return
}
if obj.Parent != nil {
if obj.Parent.Attributes.Shape.Value == d2target.ShapeSQLTable {
if obj.Parent.Shape.Value == d2target.ShapeSQLTable {
c.errorf(f.LastRef().AST(), "sql_table columns cannot have children")
return
}
if obj.Parent.Attributes.Shape.Value == d2target.ShapeClass {
if obj.Parent.Shape.Value == d2target.ShapeClass {
c.errorf(f.LastRef().AST(), "class fields cannot have children")
return
}
@ -217,14 +217,14 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
obj = obj.EnsureChild(d2graphIDA([]string{f.Name}))
if f.Primary() != nil {
c.compileLabel(obj.Attributes, f)
c.compileLabel(&obj.Attributes, f)
}
if f.Map() != nil {
c.compileMap(obj, f.Map())
}
if obj.Attributes.Label.MapKey == nil {
obj.Attributes.Label.MapKey = f.LastPrimaryKey()
if obj.Label.MapKey == nil {
obj.Label.MapKey = f.LastPrimaryKey()
}
for _, fr := range f.References {
if fr.Primary() {
@ -337,18 +337,18 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
c.errorf(scalar, "non-integer width %#v: %s", scalar.ScalarString(), err)
return
}
attrs.Width = &d2graph.Scalar{}
attrs.Width.Value = scalar.ScalarString()
attrs.Width.MapKey = f.LastPrimaryKey()
attrs.WidthAttr = &d2graph.Scalar{}
attrs.WidthAttr.Value = scalar.ScalarString()
attrs.WidthAttr.MapKey = f.LastPrimaryKey()
case "height":
_, err := strconv.Atoi(scalar.ScalarString())
if err != nil {
c.errorf(scalar, "non-integer height %#v: %s", scalar.ScalarString(), err)
return
}
attrs.Height = &d2graph.Scalar{}
attrs.Height.Value = scalar.ScalarString()
attrs.Height.MapKey = f.LastPrimaryKey()
attrs.HeightAttr = &d2graph.Scalar{}
attrs.HeightAttr.Value = scalar.ScalarString()
attrs.HeightAttr.MapKey = f.LastPrimaryKey()
case "top":
v, err := strconv.Atoi(scalar.ScalarString())
if err != nil {
@ -530,9 +530,9 @@ func compileStyleFieldInit(attrs *d2graph.Attributes, f *d2ir.Field) {
case "filled":
attrs.Style.Filled = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
case "width":
attrs.Width = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
attrs.WidthAttr = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
case "height":
attrs.Height = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
attrs.HeightAttr = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
case "top":
attrs.Top = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
case "left":
@ -552,13 +552,13 @@ func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
}
if e.Primary() != nil {
c.compileLabel(edge.Attributes, e)
c.compileLabel(&edge.Attributes, e)
}
if e.Map() != nil {
c.compileEdgeMap(edge, e.Map())
}
edge.Attributes.Label.MapKey = e.LastPrimaryKey()
edge.Label.MapKey = e.LastPrimaryKey()
for _, er := range e.References {
scopeObjIDA := d2ir.BoardIDA(er.Context.ScopeMap)
scopeObj := edge.Src.Graph.Root.EnsureChildIDVal(scopeObjIDA)
@ -604,13 +604,13 @@ func (c *compiler) compileEdgeField(edge *d2graph.Edge, f *d2ir.Field) {
}
_, isReserved := d2graph.SimpleReservedKeywords[keyword]
if isReserved {
c.compileReserved(edge.Attributes, f)
c.compileReserved(&edge.Attributes, f)
return
} else if f.Name == "style" {
if f.Map() == nil {
return
}
c.compileStyle(edge.Attributes, f.Map())
c.compileStyle(&edge.Attributes, f.Map())
return
}
@ -686,7 +686,7 @@ func (c *compiler) compileClass(obj *d2graph.Object) {
}
if !strings.Contains(f.IDVal, "(") {
typ := f.Attributes.Label.Value
typ := f.Label.Value
if typ == f.IDVal {
typ = ""
}
@ -698,7 +698,7 @@ func (c *compiler) compileClass(obj *d2graph.Object) {
} else {
// TODO: Not great, AST should easily allow specifying alternate primary field
// as an explicit label should change the name.
returnType := f.Attributes.Label.Value
returnType := f.Label.Value
if returnType == f.IDVal {
returnType = "void"
}
@ -725,7 +725,7 @@ func (c *compiler) compileClass(obj *d2graph.Object) {
func (c *compiler) compileSQLTable(obj *d2graph.Object) {
obj.SQLTable = &d2target.SQLTable{}
for _, col := range obj.ChildrenArray {
typ := col.Attributes.Label.Value
typ := col.Label.Value
if typ == col.IDVal {
// Not great, AST should easily allow specifying alternate primary field
// as an explicit label should change the name.
@ -735,8 +735,8 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) {
Name: d2target.Text{Label: col.IDVal},
Type: d2target.Text{Label: typ},
}
if col.Attributes.Constraint.Value != "" {
d2Col.Constraint = col.Attributes.Constraint.Value
if col.Constraint.Value != "" {
d2Col.Constraint = col.Constraint.Value
}
obj.SQLTable.Columns = append(obj.SQLTable.Columns, d2Col)
}
@ -766,35 +766,35 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
keyword := strings.ToLower(f.Name)
_, isReserved := d2graph.ReservedKeywords[keyword]
if isReserved {
switch obj.Attributes.Shape.Value {
switch obj.Shape.Value {
case d2target.ShapeCircle, d2target.ShapeSquare:
checkEqual := (keyword == "width" && obj.Attributes.Height != nil) || (keyword == "height" && obj.Attributes.Width != nil)
if checkEqual && obj.Attributes.Width.Value != obj.Attributes.Height.Value {
c.errorf(f.LastPrimaryKey(), "width and height must be equal for %s shapes", obj.Attributes.Shape.Value)
checkEqual := (keyword == "width" && obj.HeightAttr != nil) || (keyword == "height" && obj.WidthAttr != nil)
if checkEqual && obj.WidthAttr.Value != obj.HeightAttr.Value {
c.errorf(f.LastPrimaryKey(), "width and height must be equal for %s shapes", obj.Shape.Value)
}
}
switch f.Name {
case "style":
if obj.Attributes.Style.ThreeDee != nil {
if !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeSquare) && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeRectangle) && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeHexagon) {
c.errorf(obj.Attributes.Style.ThreeDee.MapKey, `key "3d" can only be applied to squares, rectangles, and hexagons`)
if obj.Style.ThreeDee != nil {
if !strings.EqualFold(obj.Shape.Value, d2target.ShapeSquare) && !strings.EqualFold(obj.Shape.Value, d2target.ShapeRectangle) && !strings.EqualFold(obj.Shape.Value, d2target.ShapeHexagon) {
c.errorf(obj.Style.ThreeDee.MapKey, `key "3d" can only be applied to squares, rectangles, and hexagons`)
}
}
if obj.Attributes.Style.DoubleBorder != nil {
if obj.Attributes.Shape.Value != "" && obj.Attributes.Shape.Value != d2target.ShapeSquare && obj.Attributes.Shape.Value != d2target.ShapeRectangle && obj.Attributes.Shape.Value != d2target.ShapeCircle && obj.Attributes.Shape.Value != d2target.ShapeOval {
c.errorf(obj.Attributes.Style.DoubleBorder.MapKey, `key "double-border" can only be applied to squares, rectangles, circles, ovals`)
if obj.Style.DoubleBorder != nil {
if obj.Shape.Value != "" && obj.Shape.Value != d2target.ShapeSquare && obj.Shape.Value != d2target.ShapeRectangle && obj.Shape.Value != d2target.ShapeCircle && obj.Shape.Value != d2target.ShapeOval {
c.errorf(obj.Style.DoubleBorder.MapKey, `key "double-border" can only be applied to squares, rectangles, circles, ovals`)
}
}
case "shape":
if obj.Attributes.Shape.Value == d2target.ShapeImage && obj.Attributes.Icon == nil {
if obj.Shape.Value == d2target.ShapeImage && obj.Icon == nil {
c.errorf(f.LastPrimaryKey(), `image shape must include an "icon" field`)
}
in := d2target.IsShape(obj.Attributes.Shape.Value)
_, arrowheadIn := d2target.Arrowheads[obj.Attributes.Shape.Value]
in := d2target.IsShape(obj.Shape.Value)
_, arrowheadIn := d2target.Arrowheads[obj.Shape.Value]
if !in && arrowheadIn {
c.errorf(f.LastPrimaryKey(), fmt.Sprintf(`invalid shape, can only set "%s" for arrowheads`, obj.Attributes.Shape.Value))
c.errorf(f.LastPrimaryKey(), fmt.Sprintf(`invalid shape, can only set "%s" for arrowheads`, obj.Shape.Value))
}
case "grid-rows", "grid-columns", "grid-gap", "vertical-gap", "horizontal-gap":
for _, child := range obj.ChildrenArray {
@ -807,7 +807,7 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
return
}
if obj.Attributes.Shape.Value == d2target.ShapeImage {
if obj.Shape.Value == d2target.ShapeImage {
c.errorf(f.LastRef().AST(), "image shapes cannot have children.")
return
}
@ -820,9 +820,9 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
func (c *compiler) validateNear(g *d2graph.Graph) {
for _, obj := range g.Objects {
if obj.Attributes.NearKey != nil {
nearObj, isKey := g.Root.HasChild(d2graph.Key(obj.Attributes.NearKey))
_, isConst := d2graph.NearConstants[d2graph.Key(obj.Attributes.NearKey)[0]]
if obj.NearKey != nil {
nearObj, isKey := g.Root.HasChild(d2graph.Key(obj.NearKey))
_, isConst := d2graph.NearConstants[d2graph.Key(obj.NearKey)[0]]
if isKey {
// Doesn't make sense to set near to an ancestor or descendant
nearIsAncestor := false
@ -833,7 +833,7 @@ func (c *compiler) validateNear(g *d2graph.Graph) {
}
}
if nearIsAncestor {
c.errorf(obj.Attributes.NearKey, "near keys cannot be set to an ancestor")
c.errorf(obj.NearKey, "near keys cannot be set to an ancestor")
continue
}
nearIsDescendant := false
@ -844,27 +844,27 @@ func (c *compiler) validateNear(g *d2graph.Graph) {
}
}
if nearIsDescendant {
c.errorf(obj.Attributes.NearKey, "near keys cannot be set to an descendant")
c.errorf(obj.NearKey, "near keys cannot be set to an descendant")
continue
}
if nearObj.OuterSequenceDiagram() != nil {
c.errorf(obj.Attributes.NearKey, "near keys cannot be set to an object within sequence diagrams")
c.errorf(obj.NearKey, "near keys cannot be set to an object within sequence diagrams")
continue
}
if nearObj.Attributes.NearKey != nil {
_, nearObjNearIsConst := d2graph.NearConstants[d2graph.Key(nearObj.Attributes.NearKey)[0]]
if nearObj.NearKey != nil {
_, nearObjNearIsConst := d2graph.NearConstants[d2graph.Key(nearObj.NearKey)[0]]
if nearObjNearIsConst {
c.errorf(obj.Attributes.NearKey, "near keys cannot be set to an object with a constant near key")
c.errorf(obj.NearKey, "near keys cannot be set to an object with a constant near key")
continue
}
}
} else if isConst {
if obj.Parent != g.Root {
c.errorf(obj.Attributes.NearKey, "constant near keys can only be set on root level shapes")
c.errorf(obj.NearKey, "constant near keys can only be set on root level shapes")
continue
}
} else {
c.errorf(obj.Attributes.NearKey, "near key %#v must be the absolute path to a shape or one of the following constants: %s", d2format.Format(obj.Attributes.NearKey), strings.Join(d2graph.NearConstantsArray, ", "))
c.errorf(obj.NearKey, "near key %#v must be the absolute path to a shape or one of the following constants: %s", d2format.Format(obj.NearKey), strings.Join(d2graph.NearConstantsArray, ", "))
continue
}
}
@ -877,10 +877,10 @@ func (c *compiler) validateNear(g *d2graph.Graph) {
var isSrcNearConst, isDstNearConst bool
if srcNearContainer != nil {
_, isSrcNearConst = d2graph.NearConstants[d2graph.Key(srcNearContainer.Attributes.NearKey)[0]]
_, isSrcNearConst = d2graph.NearConstants[d2graph.Key(srcNearContainer.NearKey)[0]]
}
if dstNearContainer != nil {
_, isDstNearConst = d2graph.NearConstants[d2graph.Key(dstNearContainer.Attributes.NearKey)[0]]
_, isDstNearConst = d2graph.NearConstants[d2graph.Key(dstNearContainer.NearKey)[0]]
}
if (isSrcNearConst || isDstNearConst) && srcNearContainer != dstNearContainer {
@ -905,11 +905,11 @@ func (c *compiler) validateEdges(g *d2graph.Graph) {
func (c *compiler) validateBoardLinks(g *d2graph.Graph) {
for _, obj := range g.Objects {
if obj.Attributes.Link == nil {
if obj.Link == nil {
continue
}
linkKey, err := d2parser.ParseKey(obj.Attributes.Link.Value)
linkKey, err := d2parser.ParseKey(obj.Link.Value)
if err != nil {
continue
}
@ -919,7 +919,7 @@ func (c *compiler) validateBoardLinks(g *d2graph.Graph) {
}
if !hasBoard(g.RootBoard(), linkKey.IDA()) {
c.errorf(obj.Attributes.Link.MapKey, "linked board not found")
c.errorf(obj.Link.MapKey, "linked board not found")
continue
}
}

View file

@ -43,8 +43,8 @@ x: {
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value != d2target.ShapeCircle {
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value to be circle: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value != d2target.ShapeCircle {
t.Fatalf("expected g.Objects[0].Shape.Value to be circle: %#v", g.Objects[0].Shape.Value)
}
},
@ -65,8 +65,8 @@ x: {
t.Fatalf("expected g.Objects[0].ID to be x: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("expected g.Objects[0].Attributes.Style.Opacity.Value to be 0.4: %#v", g.Objects[0].Attributes.Style.Opacity.Value)
if g.Objects[0].Style.Opacity.Value != "0.4" {
t.Fatalf("expected g.Objects[0].Style.Opacity.Value to be 0.4: %#v", g.Objects[0].Style.Opacity.Value)
}
},
@ -102,14 +102,14 @@ x: {
if g.Objects[0].ID != "hey" {
t.Fatalf("expected g.Objects[0].ID to be 'hey': %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value != d2target.ShapeHexagon {
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value to be hexagon: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value != d2target.ShapeHexagon {
t.Fatalf("expected g.Objects[0].Shape.Value to be hexagon: %#v", g.Objects[0].Shape.Value)
}
if g.Objects[0].Attributes.Width.Value != "200" {
t.Fatalf("expected g.Objects[0].Attributes.Width.Value to be 200: %#v", g.Objects[0].Attributes.Width.Value)
if g.Objects[0].WidthAttr.Value != "200" {
t.Fatalf("expected g.Objects[0].Width.Value to be 200: %#v", g.Objects[0].WidthAttr.Value)
}
if g.Objects[0].Attributes.Height.Value != "230" {
t.Fatalf("expected g.Objects[0].Attributes.Height.Value to be 230: %#v", g.Objects[0].Attributes.Height.Value)
if g.Objects[0].HeightAttr.Value != "230" {
t.Fatalf("expected g.Objects[0].Height.Value to be 230: %#v", g.Objects[0].HeightAttr.Value)
}
},
},
@ -121,7 +121,7 @@ x: {
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "200", g.Objects[0].Attributes.Top.Value)
tassert.Equal(t, "200", g.Objects[0].Top.Value)
},
},
{
@ -160,13 +160,13 @@ d2/testdata/d2compiler/TestCompile/equal_dimensions_on_circle.d2:4:2: width and
if g.Objects[0].ID != "hey" {
t.Fatalf("expected ID to be 'hey': %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value != d2target.ShapeCircle {
t.Fatalf("expected Attributes.Shape.Value to be circle: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value != d2target.ShapeCircle {
t.Fatalf("expected Attributes.Shape.Value to be circle: %#v", g.Objects[0].Shape.Value)
}
if g.Objects[0].Attributes.Width != nil {
t.Fatalf("expected Attributes.Width to be nil: %#v", g.Objects[0].Attributes.Width)
if g.Objects[0].WidthAttr != nil {
t.Fatalf("expected Attributes.Width to be nil: %#v", g.Objects[0].WidthAttr)
}
if g.Objects[0].Attributes.Height == nil {
if g.Objects[0].HeightAttr == nil {
t.Fatalf("Attributes.Height is nil")
}
},
@ -237,7 +237,7 @@ containers: {
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
if g.Objects[0].Attributes.Icon == nil {
if g.Objects[0].Icon == nil {
t.Fatal("Attribute icon is nil")
}
},
@ -326,7 +326,7 @@ containers: {
if len(g.Objects) != 1 {
t.Fatalf("expected 1 objects: %#v", g.Objects)
}
if g.Objects[0].Attributes.Style.StrokeWidth.Value != "0" {
if g.Objects[0].Style.StrokeWidth.Value != "0" {
t.Fatalf("unexpected")
}
},
@ -442,8 +442,8 @@ y: "But it's real. And if it's real it can be affected ... we may not be able"
if len(g.Root.ChildrenArray) != 2 {
t.Fatalf("expected 2 objects at the root: %#v", len(g.Root.ChildrenArray))
}
if g.Objects[1].Attributes.Label.Value != "But it's real. And if it's real it can be affected ... we may not be able" {
t.Fatalf("expected g.Objects[1].Label.Value to be last value: %#v", g.Objects[1].Attributes.Label.Value)
if g.Objects[1].Label.Value != "But it's real. And if it's real it can be affected ... we may not be able" {
t.Fatalf("expected g.Objects[1].Label.Value to be last value: %#v", g.Objects[1].Label.Value)
}
},
},
@ -470,8 +470,8 @@ x: {
if len(g.Root.ChildrenArray) != 2 {
t.Fatalf("expected 2 objects at the root: %#v", len(g.Root.ChildrenArray))
}
if g.Objects[0].Attributes.Label.Value != "All we are given is possibilities -- to make ourselves one thing or another." {
t.Fatalf("expected g.Objects[0].Label.Value to be last value: %#v", g.Objects[0].Attributes.Label.Value)
if g.Objects[0].Label.Value != "All we are given is possibilities -- to make ourselves one thing or another." {
t.Fatalf("expected g.Objects[0].Label.Value to be last value: %#v", g.Objects[0].Label.Value)
}
},
},
@ -626,11 +626,11 @@ x: {
if g.Edges[1].Dst.ID != "b" {
t.Fatalf("expected g.Edges[1].Dst.ID to be b: %#v", g.Edges[1])
}
if g.Edges[0].Attributes.Label.Value != "Can you imagine how life could be improved if we could do away with" {
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Attributes.Label)
if g.Edges[0].Label.Value != "Can you imagine how life could be improved if we could do away with" {
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Label)
}
if g.Edges[1].Attributes.Label.Value != "Well, it's garish, ugly, and derelicts have used it for a toilet." {
t.Fatalf("unexpected g.Edges[1].Label: %#v", g.Edges[1].Attributes.Label)
if g.Edges[1].Label.Value != "Well, it's garish, ugly, and derelicts have used it for a toilet." {
t.Fatalf("unexpected g.Edges[1].Label: %#v", g.Edges[1].Label)
}
},
},
@ -656,8 +656,8 @@ x: {
if g.Edges[0].Dst.ID != "b" {
t.Fatalf("expected g.Edges[0].Dst.ID to be b: %#v", g.Edges[0])
}
if g.Edges[0].Attributes.Label.Value != "Well, it's garish, ugly, and derelicts have used it for a toilet." {
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Attributes.Label)
if g.Edges[0].Label.Value != "Well, it's garish, ugly, and derelicts have used it for a toilet." {
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Label)
}
},
},
@ -756,11 +756,11 @@ x -> y -> z: "The kids will love our inflatable slides"
t.Fatalf("expected g.Edges[1].Dst.ID to be y: %#v", g.Edges[1])
}
if g.Edges[0].Attributes.Label.Value != "The kids will love our inflatable slides" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label: %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "The kids will love our inflatable slides" {
t.Fatalf("unexpected g.Edges[0].Label: %#v", g.Edges[0].Label.Value)
}
if g.Edges[1].Attributes.Label.Value != "The kids will love our inflatable slides" {
t.Fatalf("unexpected g.Edges[1].Attributes.Label: %#v", g.Edges[1].Attributes.Label.Value)
if g.Edges[1].Label.Value != "The kids will love our inflatable slides" {
t.Fatalf("unexpected g.Edges[1].Label: %#v", g.Edges[1].Label.Value)
}
},
},
@ -797,8 +797,8 @@ x -> y: one
if !g.Edges[0].DstArrow {
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0].DstArrow)
}
if g.Edges[0].Attributes.Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Attributes.Label to be two: %#v", g.Edges[0].Attributes.Label)
if g.Edges[0].Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Label to be two: %#v", g.Edges[0].Label)
}
},
},
@ -840,8 +840,8 @@ b: {
if !g.Edges[0].DstArrow {
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0].DstArrow)
}
if g.Edges[0].Attributes.Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Attributes.Label to be two: %#v", g.Edges[0].Attributes.Label)
if g.Edges[0].Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Label to be two: %#v", g.Edges[0].Label)
}
},
},
@ -883,8 +883,8 @@ b.(x -> y)[0]: two
if !g.Edges[0].DstArrow {
t.Fatalf("expected g.Edges[0].DstArrow to be true: %#v", g.Edges[0].DstArrow)
}
if g.Edges[0].Attributes.Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Attributes.Label to be two: %#v", g.Edges[0].Attributes.Label)
if g.Edges[0].Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Label to be two: %#v", g.Edges[0].Label)
}
},
},
@ -936,8 +936,8 @@ x -> y: {
if g.Edges[0].Dst.ID != "y" {
t.Fatalf("expected g.Edges[0].Dst.ID to be y: %#v", g.Edges[0])
}
if g.Edges[0].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -950,8 +950,8 @@ x -> y: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Label.Value != "asdf" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "asdf" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -972,7 +972,7 @@ x -> y: {
t.Fatalf("expected 2 objects: %#v", g.Objects)
}
assert.String(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
assert.String(t, "", g.Edges[0].Attributes.Shape.Value)
assert.String(t, "", g.Edges[0].Shape.Value)
// Make sure the DSL didn't change. this is a regression test where it did
exp := `x -> y: {
source-arrowhead: {
@ -1025,9 +1025,9 @@ x -> y: {
assert.String(t, "Reisner's Rule of Conceptual Inertia", g.Edges[0].SrcArrowhead.Label.Value)
assert.String(t, "QOTD", g.Edges[0].DstArrowhead.Label.Value)
assert.String(t, "true", g.Edges[0].DstArrowhead.Style.Filled.Value)
assert.String(t, "", g.Edges[0].Attributes.Shape.Value)
assert.String(t, "", g.Edges[0].Attributes.Label.Value)
assert.JSON(t, nil, g.Edges[0].Attributes.Style.Filled)
assert.String(t, "", g.Edges[0].Shape.Value)
assert.String(t, "", g.Edges[0].Label.Value)
assert.JSON(t, nil, g.Edges[0].Style.Filled)
},
},
{
@ -1044,7 +1044,7 @@ x -> y: {
t.Fatalf("expected 2 objects: %#v", g.Objects)
}
assert.String(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
assert.String(t, "", g.Edges[0].Attributes.Shape.Value)
assert.String(t, "", g.Edges[0].Shape.Value)
},
},
{
@ -1061,7 +1061,7 @@ x -> y: {
t.Fatalf("expected 2 objects: %#v", g.Objects)
}
assert.String(t, "triangle", g.Edges[0].SrcArrowhead.Shape.Value)
assert.String(t, "", g.Edges[0].Attributes.Shape.Value)
assert.String(t, "", g.Edges[0].Shape.Value)
},
},
{
@ -1087,7 +1087,7 @@ x -> y: {
t.Fatalf("expected 2 objects: %#v", g.Objects)
}
assert.String(t, "yo", g.Edges[0].SrcArrowhead.Label.Value)
assert.String(t, "", g.Edges[0].Attributes.Label.Value)
assert.String(t, "", g.Edges[0].Label.Value)
},
},
{
@ -1106,7 +1106,7 @@ x -> y: {
t.Fatalf("expected 2 objects: %#v", g.Objects)
}
assert.String(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
assert.String(t, "", g.Edges[0].Attributes.Shape.Value)
assert.String(t, "", g.Edges[0].Shape.Value)
},
},
{
@ -1128,7 +1128,7 @@ x -> y: {
}
assert.String(t, "diamond", g.Edges[0].SrcArrowhead.Shape.Value)
assert.String(t, "diamond", g.Edges[0].DstArrowhead.Shape.Value)
assert.String(t, "", g.Edges[0].Attributes.Shape.Value)
assert.String(t, "", g.Edges[0].Shape.Value)
},
},
{
@ -1143,8 +1143,8 @@ x -> y: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Animated.Value != "true" {
t.Fatalf("Edges[0].Attributes.Style.Animated.Value: %#v", g.Edges[0].Attributes.Style.Animated.Value)
if g.Edges[0].Style.Animated.Value != "true" {
t.Fatalf("Edges[0].Style.Animated.Value: %#v", g.Edges[0].Style.Animated.Value)
}
},
},
@ -1201,11 +1201,11 @@ x -> y -> z: {
if len(g.Edges) != 2 {
t.Fatalf("expected 2 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
if g.Edges[1].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[1].Attributes.Label.Value)
if g.Edges[1].Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[1].Label.Value)
}
},
},
@ -1226,8 +1226,8 @@ x -> y
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "Space: the final frontier. These are the voyages of the starship Enterprise." {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1249,8 +1249,8 @@ x -> y: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
},
},
@ -1270,11 +1270,11 @@ x -> y: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1293,11 +1293,11 @@ x -> y
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1317,11 +1317,11 @@ x -> y
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1342,11 +1342,11 @@ x.(a -> b)[0].style.opacity: 0.4
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1367,11 +1367,11 @@ x: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1396,11 +1396,11 @@ x: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1423,11 +1423,11 @@ x: {
if len(g.Edges) != 1 {
t.Fatalf("expected 1 edge: %#v", g.Edges)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Attributes.Style.Opacity.Value: %#v", g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatalf("unexpected g.Edges[0].Style.Opacity.Value: %#v", g.Edges[0].Style.Opacity.Value)
}
if g.Edges[0].Attributes.Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Attributes.Label.Value : %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "" {
t.Fatalf("unexpected g.Edges[0].Label.Value : %#v", g.Edges[0].Label.Value)
}
},
},
@ -1452,8 +1452,8 @@ x -> y: {
if len(g.Objects) != 1 {
t.Fatal(g.Objects)
}
if g.Objects[0].Attributes.Link.Value != "https://google.com" {
t.Fatal(g.Objects[0].Attributes.Link.Value)
if g.Objects[0].Link.Value != "https://google.com" {
t.Fatal(g.Objects[0].Link.Value)
}
},
},
@ -1465,8 +1465,8 @@ x -> y: {
t.Fatal(g.Objects)
}
if g.Objects[0].Attributes.Tooltip.Value != "https://google.com" {
t.Fatal(g.Objects[0].Attributes.Tooltip.Value)
if g.Objects[0].Tooltip.Value != "https://google.com" {
t.Fatal(g.Objects[0].Tooltip.Value)
}
},
},
@ -1482,12 +1482,12 @@ x -> y: {
if len(g.Objects) != 1 {
t.Fatal(g.Objects)
}
if g.Objects[0].Attributes.Link.Value != "https://google.com" {
t.Fatal(g.Objects[0].Attributes.Link.Value)
if g.Objects[0].Link.Value != "https://google.com" {
t.Fatal(g.Objects[0].Link.Value)
}
if g.Objects[0].Attributes.Tooltip.Value != "hello world" {
t.Fatal(g.Objects[0].Attributes.Tooltip.Value)
if g.Objects[0].Tooltip.Value != "hello world" {
t.Fatal(g.Objects[0].Tooltip.Value)
}
},
},
@ -1517,8 +1517,8 @@ b: {
if len(g.Objects) != 1 {
t.Fatal(g.Objects)
}
if g.Objects[0].Attributes.Link.Value != "Overview.Untitled board 7.zzzzz" {
t.Fatal(g.Objects[0].Attributes.Link.Value)
if g.Objects[0].Link.Value != "Overview.Untitled board 7.zzzzz" {
t.Fatal(g.Objects[0].Link.Value)
}
},
},
@ -1603,20 +1603,20 @@ y
if len(g.Objects) != 2 {
t.Fatal(g.Objects)
}
if g.Objects[0].Attributes.NearKey == nil {
if g.Objects[0].NearKey == nil {
t.Fatal("missing near key")
}
if g.Objects[0].Attributes.Icon.Path != "orange" {
t.Fatal(g.Objects[0].Attributes.Icon)
if g.Objects[0].Icon.Path != "orange" {
t.Fatal(g.Objects[0].Icon)
}
if g.Objects[0].Attributes.Style.Opacity.Value != "0.5" {
t.Fatal(g.Objects[0].Attributes.Style.Opacity)
if g.Objects[0].Style.Opacity.Value != "0.5" {
t.Fatal(g.Objects[0].Style.Opacity)
}
if g.Objects[0].Attributes.Style.Stroke.Value != "red" {
t.Fatal(g.Objects[0].Attributes.Style.Stroke)
if g.Objects[0].Style.Stroke.Value != "red" {
t.Fatal(g.Objects[0].Style.Stroke)
}
if g.Objects[0].Attributes.Style.Fill.Value != "green" {
t.Fatal(g.Objects[0].Attributes.Style.Fill)
if g.Objects[0].Style.Fill.Value != "green" {
t.Fatal(g.Objects[0].Style.Fill)
}
},
},
@ -1696,7 +1696,7 @@ y -> x.style
}
assert.String(t, `"b\nb"`, g.Objects[0].ID)
assert.String(t, `b
b`, g.Objects[0].Attributes.Label.Value)
b`, g.Objects[0].Label.Value)
},
},
{
@ -1708,7 +1708,7 @@ b`, g.Objects[0].Attributes.Label.Value)
t.Fatal(g.Objects)
}
assert.String(t, "b\rb", g.Objects[0].ID)
assert.String(t, "b\rb", g.Objects[0].Attributes.Label.Value)
assert.String(t, "b\rb", g.Objects[0].Label.Value)
},
},
{
@ -1730,8 +1730,8 @@ b`, g.Objects[0].Attributes.Label.Value)
if len(g.Objects[0].Class.Methods) != 0 {
t.Fatal(len(g.Objects[0].Class.Methods))
}
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatal(g.Objects[0].Attributes.Style.Opacity.Value)
if g.Objects[0].Style.Opacity.Value != "0.4" {
t.Fatal(g.Objects[0].Style.Opacity.Value)
}
},
},
@ -1751,8 +1751,8 @@ b`, g.Objects[0].Attributes.Label.Value)
if len(g.Objects[0].SQLTable.Columns) != 1 {
t.Fatal(len(g.Objects[0].SQLTable.Columns))
}
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatal(g.Objects[0].Attributes.Style.Opacity.Value)
if g.Objects[0].Style.Opacity.Value != "0.4" {
t.Fatal(g.Objects[0].Style.Opacity.Value)
}
},
},
@ -1775,8 +1775,8 @@ b`, g.Objects[0].Attributes.Label.Value)
if len(g.Objects[0].SQLTable.Columns) != 1 {
t.Fatal(len(g.Objects[0].SQLTable.Columns))
}
if g.Objects[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatal(g.Objects[0].Attributes.Style.Opacity.Value)
if g.Objects[0].Style.Opacity.Value != "0.4" {
t.Fatal(g.Objects[0].Style.Opacity.Value)
}
},
},
@ -1796,7 +1796,7 @@ x.y -> a.b: {
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "true", g.Edges[0].Attributes.Style.Animated.Value)
tassert.Equal(t, "true", g.Edges[0].Style.Animated.Value)
},
},
{
@ -1901,7 +1901,7 @@ dst.id <-> src.dst_id
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.String(t, "sequence_diagram", g.Objects[0].Attributes.Shape.Value)
assert.String(t, "sequence_diagram", g.Objects[0].Shape.Value)
},
},
{
@ -1948,7 +1948,7 @@ b
text: `shape: sequence_diagram
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.String(t, "sequence_diagram", g.Root.Attributes.Shape.Value)
assert.String(t, "sequence_diagram", g.Root.Shape.Value)
},
},
{
@ -2028,7 +2028,7 @@ ok: {
text: `direction: right`,
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.String(t, "right", g.Root.Attributes.Direction.Value)
assert.String(t, "right", g.Root.Direction.Value)
},
},
{
@ -2036,7 +2036,7 @@ ok: {
text: `x`,
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.String(t, "", g.Objects[0].Attributes.Direction.Value)
assert.String(t, "", g.Objects[0].Direction.Value)
},
},
{
@ -2046,7 +2046,7 @@ ok: {
direction: left
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.String(t, "left", g.Objects[0].Attributes.Direction.Value)
assert.String(t, "left", g.Objects[0].Direction.Value)
},
},
{
@ -2057,7 +2057,7 @@ ok: {
constraint: BIZ
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
assert.String(t, "bar", g.Objects[0].Attributes.Label.Value)
assert.String(t, "bar", g.Objects[0].Label.Value)
},
},
{
@ -2151,7 +2151,7 @@ layers: {
}
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "root.layers.x", g.Objects[0].Attributes.Link.Value)
tassert.Equal(t, "root.layers.x", g.Objects[0].Link.Value)
},
},
{
@ -2171,8 +2171,8 @@ scenarios: {
}
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "root.layers.cat", g.Objects[0].Attributes.Link.Value)
tassert.Equal(t, "root.layers.cat", g.Scenarios[0].Objects[0].Attributes.Link.Value)
tassert.Equal(t, "root.layers.cat", g.Objects[0].Link.Value)
tassert.Equal(t, "root.layers.cat", g.Scenarios[0].Objects[0].Link.Value)
},
},
{
@ -2205,7 +2205,7 @@ layers: {
}
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "root.layers.x.layers.x", g.Objects[0].Attributes.Link.Value)
tassert.Equal(t, "root.layers.x.layers.x", g.Objects[0].Link.Value)
},
},
{
@ -2219,7 +2219,7 @@ layers: {
}
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "root.layers.x", g.Objects[1].Attributes.Link.Value)
tassert.Equal(t, "root.layers.x", g.Objects[1].Link.Value)
},
},
{
@ -2237,9 +2237,9 @@ layers: {
}
}`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.NotNil(t, g.Layers[0].Layers[0].Objects[0].Attributes.Link.Value)
tassert.Equal(t, "root.layers.x", g.Layers[0].Layers[0].Objects[0].Attributes.Link.Value)
tassert.Equal(t, "root.layers.x", g.Layers[0].Layers[0].Objects[1].Attributes.Link.Value)
tassert.NotNil(t, g.Layers[0].Layers[0].Objects[0].Link.Value)
tassert.Equal(t, "root.layers.x", g.Layers[0].Layers[0].Objects[0].Link.Value)
tassert.Equal(t, "root.layers.x", g.Layers[0].Layers[0].Objects[1].Link.Value)
},
},
{
@ -2289,7 +2289,7 @@ obj {
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "200", g.Objects[0].Attributes.GridRows.Value)
tassert.Equal(t, "200", g.Objects[0].GridRows.Value)
},
},
{
@ -2362,16 +2362,16 @@ nostar -> 1star: { class: path }
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, 3, len(g.Objects))
tassert.Equal(t, "dragon_ball", g.Objects[0].Attributes.Classes[0])
tassert.Equal(t, "", g.Objects[0].Attributes.Label.Value)
tassert.Equal(t, "dragon_ball", g.Objects[0].Classes[0])
tassert.Equal(t, "", g.Objects[0].Label.Value)
// Class field overrides primary
tassert.Equal(t, "", g.Objects[1].Attributes.Label.Value)
tassert.Equal(t, "**", g.Objects[2].Attributes.Label.Value)
tassert.Equal(t, "orange", g.Objects[0].Attributes.Style.Fill.Value)
tassert.Equal(t, "red", g.Objects[1].Attributes.Style.Fill.Value)
tassert.Equal(t, "", g.Objects[1].Label.Value)
tassert.Equal(t, "**", g.Objects[2].Label.Value)
tassert.Equal(t, "orange", g.Objects[0].Style.Fill.Value)
tassert.Equal(t, "red", g.Objects[1].Style.Fill.Value)
tassert.Equal(t, "4", g.Edges[0].Attributes.Style.StrokeWidth.Value)
tassert.Equal(t, "then", g.Edges[0].Attributes.Label.Value)
tassert.Equal(t, "4", g.Edges[0].Style.StrokeWidth.Value)
tassert.Equal(t, "then", g.Edges[0].Label.Value)
},
},
{
@ -2386,7 +2386,7 @@ classes.x.shape: diamond
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, 1, len(g.Objects))
tassert.Equal(t, "diamond", g.Objects[0].Attributes.Shape.Value)
tassert.Equal(t, "diamond", g.Objects[0].Shape.Value)
},
},
{

View file

@ -42,10 +42,10 @@ func Export(ctx context.Context, g *d2graph.Graph, fontFamily *d2fonts.FontFamil
func applyTheme(shape *d2target.Shape, obj *d2graph.Object, theme *d2themes.Theme) {
shape.Stroke = obj.GetStroke(shape.StrokeDash)
shape.Fill = obj.GetFill()
if obj.Attributes.Shape.Value == d2target.ShapeText {
if obj.Shape.Value == d2target.ShapeText {
shape.Color = color.N1
}
if obj.Attributes.Shape.Value == d2target.ShapeSQLTable || obj.Attributes.Shape.Value == d2target.ShapeClass {
if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
shape.PrimaryAccentColor = color.B2
shape.SecondaryAccentColor = color.AA2
shape.NeutralAccentColor = color.N2
@ -72,64 +72,64 @@ func applyTheme(shape *d2target.Shape, obj *d2graph.Object, theme *d2themes.Them
}
func applyStyles(shape *d2target.Shape, obj *d2graph.Object) {
if obj.Attributes.Style.Opacity != nil {
shape.Opacity, _ = strconv.ParseFloat(obj.Attributes.Style.Opacity.Value, 64)
if obj.Style.Opacity != nil {
shape.Opacity, _ = strconv.ParseFloat(obj.Style.Opacity.Value, 64)
}
if obj.Attributes.Style.StrokeDash != nil {
shape.StrokeDash, _ = strconv.ParseFloat(obj.Attributes.Style.StrokeDash.Value, 64)
if obj.Style.StrokeDash != nil {
shape.StrokeDash, _ = strconv.ParseFloat(obj.Style.StrokeDash.Value, 64)
}
if obj.Attributes.Style.Fill != nil {
shape.Fill = obj.Attributes.Style.Fill.Value
} else if obj.Attributes.Shape.Value == d2target.ShapeText {
if obj.Style.Fill != nil {
shape.Fill = obj.Style.Fill.Value
} else if obj.Shape.Value == d2target.ShapeText {
shape.Fill = "transparent"
}
if obj.Attributes.Style.FillPattern != nil {
shape.FillPattern = obj.Attributes.Style.FillPattern.Value
if obj.Style.FillPattern != nil {
shape.FillPattern = obj.Style.FillPattern.Value
}
if obj.Attributes.Style.Stroke != nil {
shape.Stroke = obj.Attributes.Style.Stroke.Value
if obj.Style.Stroke != nil {
shape.Stroke = obj.Style.Stroke.Value
}
if obj.Attributes.Style.StrokeWidth != nil {
shape.StrokeWidth, _ = strconv.Atoi(obj.Attributes.Style.StrokeWidth.Value)
if obj.Style.StrokeWidth != nil {
shape.StrokeWidth, _ = strconv.Atoi(obj.Style.StrokeWidth.Value)
}
if obj.Attributes.Style.Shadow != nil {
shape.Shadow, _ = strconv.ParseBool(obj.Attributes.Style.Shadow.Value)
if obj.Style.Shadow != nil {
shape.Shadow, _ = strconv.ParseBool(obj.Style.Shadow.Value)
}
if obj.Attributes.Style.ThreeDee != nil {
shape.ThreeDee, _ = strconv.ParseBool(obj.Attributes.Style.ThreeDee.Value)
if obj.Style.ThreeDee != nil {
shape.ThreeDee, _ = strconv.ParseBool(obj.Style.ThreeDee.Value)
}
if obj.Attributes.Style.Multiple != nil {
shape.Multiple, _ = strconv.ParseBool(obj.Attributes.Style.Multiple.Value)
if obj.Style.Multiple != nil {
shape.Multiple, _ = strconv.ParseBool(obj.Style.Multiple.Value)
}
if obj.Attributes.Style.BorderRadius != nil {
shape.BorderRadius, _ = strconv.Atoi(obj.Attributes.Style.BorderRadius.Value)
if obj.Style.BorderRadius != nil {
shape.BorderRadius, _ = strconv.Atoi(obj.Style.BorderRadius.Value)
}
if obj.Attributes.Style.FontColor != nil {
shape.Color = obj.Attributes.Style.FontColor.Value
if obj.Style.FontColor != nil {
shape.Color = obj.Style.FontColor.Value
}
if obj.Attributes.Style.Italic != nil {
shape.Italic, _ = strconv.ParseBool(obj.Attributes.Style.Italic.Value)
if obj.Style.Italic != nil {
shape.Italic, _ = strconv.ParseBool(obj.Style.Italic.Value)
}
if obj.Attributes.Style.Bold != nil {
shape.Bold, _ = strconv.ParseBool(obj.Attributes.Style.Bold.Value)
if obj.Style.Bold != nil {
shape.Bold, _ = strconv.ParseBool(obj.Style.Bold.Value)
}
if obj.Attributes.Style.Underline != nil {
shape.Underline, _ = strconv.ParseBool(obj.Attributes.Style.Underline.Value)
if obj.Style.Underline != nil {
shape.Underline, _ = strconv.ParseBool(obj.Style.Underline.Value)
}
if obj.Attributes.Style.Font != nil {
shape.FontFamily = obj.Attributes.Style.Font.Value
if obj.Style.Font != nil {
shape.FontFamily = obj.Style.Font.Value
}
if obj.Attributes.Style.DoubleBorder != nil {
shape.DoubleBorder, _ = strconv.ParseBool(obj.Attributes.Style.DoubleBorder.Value)
if obj.Style.DoubleBorder != nil {
shape.DoubleBorder, _ = strconv.ParseBool(obj.Style.DoubleBorder.Value)
}
}
func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
shape := d2target.BaseShape()
shape.SetType(obj.Attributes.Shape.Value)
shape.SetType(obj.Shape.Value)
shape.ID = obj.AbsID()
shape.Classes = obj.Attributes.Classes
shape.Classes = obj.Classes
shape.ZIndex = obj.ZIndex
shape.Level = int(obj.Level())
shape.Pos = d2target.NewPoint(int(obj.TopLeft.X), int(obj.TopLeft.Y))
@ -155,10 +155,10 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
shape.Color = text.GetColor(shape.Italic)
applyStyles(shape, obj)
switch obj.Attributes.Shape.Value {
switch obj.Shape.Value {
case d2target.ShapeCode, d2target.ShapeText:
shape.Language = obj.Attributes.Language
shape.Label = obj.Attributes.Label.Value
shape.Language = obj.Language
shape.Label = obj.Label.Value
case d2target.ShapeClass:
shape.Class = *obj.Class
// The label is the header for classes and tables, which is set in client to be 4 px larger than the object's set font size
@ -178,13 +178,13 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
}
}
if obj.Attributes.Tooltip != nil {
shape.Tooltip = obj.Attributes.Tooltip.Value
if obj.Tooltip != nil {
shape.Tooltip = obj.Tooltip.Value
}
if obj.Attributes.Link != nil {
shape.Link = obj.Attributes.Link.Value
if obj.Link != nil {
shape.Link = obj.Link.Value
}
shape.Icon = obj.Attributes.Icon
shape.Icon = obj.Icon
if obj.IconPosition != nil {
shape.IconPosition = *obj.IconPosition
}
@ -195,7 +195,7 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection {
connection := d2target.BaseConnection()
connection.ID = edge.AbsID()
connection.Classes = edge.Attributes.Classes
connection.Classes = edge.Classes
connection.ZIndex = edge.ZIndex
text := edge.Text()
@ -236,60 +236,60 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection
if theme != nil && theme.SpecialRules.NoCornerRadius {
connection.BorderRadius = 0
}
if edge.Attributes.Style.BorderRadius != nil {
connection.BorderRadius, _ = strconv.ParseFloat(edge.Attributes.Style.BorderRadius.Value, 64)
if edge.Style.BorderRadius != nil {
connection.BorderRadius, _ = strconv.ParseFloat(edge.Style.BorderRadius.Value, 64)
}
if edge.Attributes.Style.Opacity != nil {
connection.Opacity, _ = strconv.ParseFloat(edge.Attributes.Style.Opacity.Value, 64)
if edge.Style.Opacity != nil {
connection.Opacity, _ = strconv.ParseFloat(edge.Style.Opacity.Value, 64)
}
if edge.Attributes.Style.StrokeDash != nil {
connection.StrokeDash, _ = strconv.ParseFloat(edge.Attributes.Style.StrokeDash.Value, 64)
if edge.Style.StrokeDash != nil {
connection.StrokeDash, _ = strconv.ParseFloat(edge.Style.StrokeDash.Value, 64)
}
connection.Stroke = edge.GetStroke(connection.StrokeDash)
if edge.Attributes.Style.Stroke != nil {
connection.Stroke = edge.Attributes.Style.Stroke.Value
if edge.Style.Stroke != nil {
connection.Stroke = edge.Style.Stroke.Value
}
if edge.Attributes.Style.StrokeWidth != nil {
connection.StrokeWidth, _ = strconv.Atoi(edge.Attributes.Style.StrokeWidth.Value)
if edge.Style.StrokeWidth != nil {
connection.StrokeWidth, _ = strconv.Atoi(edge.Style.StrokeWidth.Value)
}
if edge.Attributes.Style.Fill != nil {
connection.Fill = edge.Attributes.Style.Fill.Value
if edge.Style.Fill != nil {
connection.Fill = edge.Style.Fill.Value
}
connection.FontSize = text.FontSize
if edge.Attributes.Style.FontSize != nil {
connection.FontSize, _ = strconv.Atoi(edge.Attributes.Style.FontSize.Value)
if edge.Style.FontSize != nil {
connection.FontSize, _ = strconv.Atoi(edge.Style.FontSize.Value)
}
if edge.Attributes.Style.Animated != nil {
connection.Animated, _ = strconv.ParseBool(edge.Attributes.Style.Animated.Value)
if edge.Style.Animated != nil {
connection.Animated, _ = strconv.ParseBool(edge.Style.Animated.Value)
}
if edge.Attributes.Tooltip != nil {
connection.Tooltip = edge.Attributes.Tooltip.Value
if edge.Tooltip != nil {
connection.Tooltip = edge.Tooltip.Value
}
connection.Icon = edge.Attributes.Icon
connection.Icon = edge.Icon
if edge.Attributes.Style.Italic != nil {
connection.Italic, _ = strconv.ParseBool(edge.Attributes.Style.Italic.Value)
if edge.Style.Italic != nil {
connection.Italic, _ = strconv.ParseBool(edge.Style.Italic.Value)
}
connection.Color = text.GetColor(connection.Italic)
if edge.Attributes.Style.FontColor != nil {
connection.Color = edge.Attributes.Style.FontColor.Value
if edge.Style.FontColor != nil {
connection.Color = edge.Style.FontColor.Value
}
if edge.Attributes.Style.Bold != nil {
connection.Bold, _ = strconv.ParseBool(edge.Attributes.Style.Bold.Value)
if edge.Style.Bold != nil {
connection.Bold, _ = strconv.ParseBool(edge.Style.Bold.Value)
}
if theme != nil && theme.SpecialRules.Mono {
connection.FontFamily = "mono"
}
if edge.Attributes.Style.Font != nil {
connection.FontFamily = edge.Attributes.Style.Font.Value
if edge.Style.Font != nil {
connection.FontFamily = edge.Style.Font.Value
}
connection.Label = text.Text
connection.LabelWidth = text.Dimensions.Width

View file

@ -56,10 +56,9 @@ type Graph struct {
func NewGraph() *Graph {
d := &Graph{}
d.Root = &Object{
Graph: d,
Parent: nil,
Children: make(map[string]*Object),
Attributes: &Attributes{},
Graph: d,
Parent: nil,
Children: make(map[string]*Object),
}
return d
}
@ -90,11 +89,10 @@ type Object struct {
// IDVal: yes'"
//
// ID allows joining on . naively and construct a valid D2 key path
ID string `json:"id"`
IDVal string `json:"id_val"`
Map *d2ast.Map `json:"-"`
LabelDimensions d2target.TextDimensions `json:"label_dimensions"`
References []Reference `json:"references,omitempty"`
ID string `json:"id"`
IDVal string `json:"id_val"`
Map *d2ast.Map `json:"-"`
References []Reference `json:"references,omitempty"`
*geo.Box `json:"box,omitempty"`
LabelPosition *string `json:"labelPosition,omitempty"`
@ -106,20 +104,22 @@ type Object struct {
Children map[string]*Object `json:"-"`
ChildrenArray []*Object `json:"-"`
Attributes *Attributes `json:"attributes,omitempty"`
Attributes `json:"attributes"`
ZIndex int `json:"zIndex"`
}
type Attributes struct {
Label Scalar `json:"label"`
Label Scalar `json:"label"`
LabelDimensions d2target.TextDimensions `json:"labelDimensions"`
Style Style `json:"style"`
Icon *url.URL `json:"icon,omitempty"`
Tooltip *Scalar `json:"tooltip,omitempty"`
Link *Scalar `json:"link,omitempty"`
Width *Scalar `json:"width,omitempty"`
Height *Scalar `json:"height,omitempty"`
WidthAttr *Scalar `json:"width,omitempty"`
HeightAttr *Scalar `json:"height,omitempty"`
Top *Scalar `json:"top,omitempty"`
Left *Scalar `json:"left,omitempty"`
@ -412,7 +412,7 @@ func (l ContainerLevel) LabelSize() int {
func (obj *Object) GetFill() string {
level := int(obj.Level())
shape := obj.Attributes.Shape.Value
shape := obj.Shape.Value
if strings.EqualFold(shape, d2target.ShapeSQLTable) || strings.EqualFold(shape, d2target.ShapeClass) {
return color.N1
@ -491,7 +491,7 @@ func (obj *Object) GetFill() string {
}
func (obj *Object) GetStroke(dashGapSize interface{}) string {
shape := obj.Attributes.Shape.Value
shape := obj.Shape.Value
if strings.EqualFold(shape, d2target.ShapeCode) ||
strings.EqualFold(shape, d2target.ShapeText) {
return color.N1
@ -518,10 +518,10 @@ func (obj *Object) IsContainer() bool {
}
func (obj *Object) HasOutsideBottomLabel() bool {
if obj == nil || obj.Attributes == nil {
if obj == nil {
return false
}
switch obj.Attributes.Shape.Value {
switch obj.Shape.Value {
case d2target.ShapeImage, d2target.ShapePerson:
return true
default:
@ -530,14 +530,14 @@ func (obj *Object) HasOutsideBottomLabel() bool {
}
func (obj *Object) HasLabel() bool {
if obj == nil || obj.Attributes == nil {
if obj == nil {
return false
}
switch obj.Attributes.Shape.Value {
switch obj.Shape.Value {
case d2target.ShapeText, d2target.ShapeClass, d2target.ShapeSQLTable, d2target.ShapeCode:
return false
default:
return obj.Attributes.Label.Value != ""
return obj.Label.Value != ""
}
}
@ -556,12 +556,12 @@ func (obj *Object) AbsIDArray() []string {
}
func (obj *Object) Text() *d2target.MText {
isBold := !obj.IsContainer() && obj.Attributes.Shape.Value != "text"
isBold := !obj.IsContainer() && obj.Shape.Value != "text"
isItalic := false
if obj.Attributes.Style.Bold != nil && obj.Attributes.Style.Bold.Value == "true" {
if obj.Style.Bold != nil && obj.Style.Bold.Value == "true" {
isBold = true
}
if obj.Attributes.Style.Italic != nil && obj.Attributes.Style.Italic.Value == "true" {
if obj.Style.Italic != nil && obj.Style.Italic.Value == "true" {
isItalic = true
}
fontSize := d2fonts.FONT_SIZE_M
@ -571,14 +571,14 @@ func (obj *Object) Text() *d2target.MText {
}
if obj.OuterSequenceDiagram() == nil {
if obj.IsContainer() && obj.Attributes.Shape.Value != "text" {
if obj.IsContainer() && obj.Shape.Value != "text" {
fontSize = obj.Level().LabelSize()
}
} else {
isBold = false
}
if obj.Attributes.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(obj.Attributes.Style.FontSize.Value)
if obj.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(obj.Style.FontSize.Value)
}
// Class and Table objects have Label set to header
if obj.Class != nil || obj.SQLTable != nil {
@ -588,12 +588,12 @@ func (obj *Object) Text() *d2target.MText {
isBold = false
}
return &d2target.MText{
Text: obj.Attributes.Label.Value,
Text: obj.Label.Value,
FontSize: fontSize,
IsBold: isBold,
IsItalic: isItalic,
Language: obj.Attributes.Language,
Shape: obj.Attributes.Shape.Value,
Language: obj.Language,
Shape: obj.Shape.Value,
Dimensions: obj.LabelDimensions,
}
@ -608,7 +608,7 @@ func (obj *Object) newObject(id string) *Object {
child := &Object{
ID: id,
IDVal: idval,
Attributes: &Attributes{
Attributes: Attributes{
Label: Scalar{
Value: idval,
},
@ -786,7 +786,7 @@ func (obj *Object) FindEdges(mk *d2ast.Key) ([]*Edge, bool) {
func (obj *Object) ensureChildEdge(ida []string) *Object {
for i := range ida {
switch obj.Attributes.Shape.Value {
switch obj.Shape.Value {
case d2target.ShapeClass, d2target.ShapeSQLTable:
// This will only be called for connecting edges where we want to truncate to the
// container.
@ -865,23 +865,23 @@ func (obj *Object) AppendReferences(ida []string, ref Reference, unresolvedObj *
}
func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily) (*d2target.TextDimensions, error) {
shapeType := strings.ToLower(obj.Attributes.Shape.Value)
shapeType := strings.ToLower(obj.Shape.Value)
if obj.Attributes.Style.Font != nil {
f := d2fonts.D2_FONT_TO_FAMILY[obj.Attributes.Style.Font.Value]
if obj.Style.Font != nil {
f := d2fonts.D2_FONT_TO_FAMILY[obj.Style.Font.Value]
fontFamily = &f
}
var dims *d2target.TextDimensions
switch shapeType {
case d2target.ShapeText:
if obj.Attributes.Language == "latex" {
if obj.Language == "latex" {
width, height, err := d2latex.Measure(obj.Text().Text)
if err != nil {
return nil, err
}
dims = d2target.NewTextDimensions(width, height)
} else if obj.Attributes.Language != "" {
} else if obj.Language != "" {
var err error
dims, err = getMarkdownDimensions(mtexts, ruler, obj.Text(), fontFamily)
if err != nil {
@ -898,7 +898,7 @@ func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Rul
dims = GetTextDimensions(mtexts, ruler, obj.Text(), fontFamily)
}
if shapeType == d2target.ShapeSQLTable && obj.Attributes.Label.Value == "" {
if shapeType == d2target.ShapeSQLTable && obj.Label.Value == "" {
// measure with placeholder text to determine height
placeholder := *obj.Text()
placeholder.Text = "Table"
@ -927,7 +927,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
labelDims.Height += INNER_LABEL_PADDING
}
switch strings.ToLower(obj.Attributes.Shape.Value) {
switch strings.ToLower(obj.Shape.Value) {
default:
return d2target.NewTextDimensions(labelDims.Width, labelDims.Height), nil
@ -938,8 +938,8 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
maxWidth := go2.Max(12, labelDims.Width)
fontSize := d2fonts.FONT_SIZE_L
if obj.Attributes.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(obj.Attributes.Style.FontSize.Value)
if obj.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(obj.Style.FontSize.Value)
}
for _, f := range obj.Class.Fields {
@ -984,8 +984,8 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
constraintWidth := 0
colFontSize := d2fonts.FONT_SIZE_L
if obj.Attributes.Style.FontSize != nil {
colFontSize, _ = strconv.Atoi(obj.Attributes.Style.FontSize.Value)
if obj.Style.FontSize != nil {
colFontSize, _ = strconv.Atoi(obj.Style.FontSize.Value)
}
for i := range obj.SQLTable.Columns {
@ -1031,7 +1031,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
func (obj *Object) OuterNearContainer() *Object {
for obj != nil {
if obj.Attributes.NearKey != nil {
if obj.NearKey != nil {
return obj
}
obj = obj.Parent
@ -1048,9 +1048,8 @@ type Edge struct {
SrcTableColumnIndex *int `json:"srcTableColumnIndex,omitempty"`
DstTableColumnIndex *int `json:"dstTableColumnIndex,omitempty"`
LabelDimensions d2target.TextDimensions `json:"label_dimensions"`
LabelPosition *string `json:"labelPosition,omitempty"`
LabelPercentage *float64 `json:"labelPercentage,omitempty"`
LabelPosition *string `json:"labelPosition,omitempty"`
LabelPercentage *float64 `json:"labelPercentage,omitempty"`
IsCurve bool `json:"isCurve"`
Route []*geo.Point `json:"route,omitempty"`
@ -1064,7 +1063,7 @@ type Edge struct {
DstArrowhead *Attributes `json:"dstArrowhead,omitempty"`
References []EdgeReference `json:"references,omitempty"`
Attributes *Attributes `json:"attributes,omitempty"`
Attributes `json:"attributes,omitempty"`
ZIndex int `json:"zIndex"`
}
@ -1104,15 +1103,15 @@ func (e *Edge) ArrowString() string {
func (e *Edge) Text() *d2target.MText {
fontSize := d2fonts.FONT_SIZE_M
if e.Attributes.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(e.Attributes.Style.FontSize.Value)
if e.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(e.Style.FontSize.Value)
}
isBold := false
if e.Attributes.Style.Bold != nil {
isBold, _ = strconv.ParseBool(e.Attributes.Style.Bold.Value)
if e.Style.Bold != nil {
isBold, _ = strconv.ParseBool(e.Style.Bold.Value)
}
return &d2target.MText{
Text: e.Attributes.Label.Value,
Text: e.Label.Value,
FontSize: fontSize,
IsBold: isBold,
IsItalic: true,
@ -1160,7 +1159,7 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
}
e := &Edge{
Attributes: &Attributes{
Attributes: Attributes{
Label: Scalar{
Value: label,
},
@ -1179,7 +1178,7 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
}
func addSQLTableColumnIndices(e *Edge, srcID, dstID []string, obj, src, dst *Object) {
if src.Attributes.Shape.Value == d2target.ShapeSQLTable {
if src.Shape.Value == d2target.ShapeSQLTable {
if src == dst {
// Ignore edge to column inside table.
return
@ -1197,7 +1196,7 @@ func addSQLTableColumnIndices(e *Edge, srcID, dstID []string, obj, src, dst *Obj
}
}
}
if dst.Attributes.Shape.Value == d2target.ShapeSQLTable {
if dst.Shape.Value == d2target.ShapeSQLTable {
objAbsID := obj.AbsIDArray()
dstAbsID := dst.AbsIDArray()
if len(objAbsID)+len(dstID) > len(dstAbsID) {
@ -1344,16 +1343,16 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
var desiredWidth int
var desiredHeight int
if obj.Attributes.Width != nil {
desiredWidth, _ = strconv.Atoi(obj.Attributes.Width.Value)
if obj.WidthAttr != nil {
desiredWidth, _ = strconv.Atoi(obj.WidthAttr.Value)
}
if obj.Attributes.Height != nil {
desiredHeight, _ = strconv.Atoi(obj.Attributes.Height.Value)
if obj.HeightAttr != nil {
desiredHeight, _ = strconv.Atoi(obj.HeightAttr.Value)
}
dslShape := strings.ToLower(obj.Attributes.Shape.Value)
dslShape := strings.ToLower(obj.Shape.Value)
if obj.Attributes.Label.Value == "" &&
if obj.Label.Value == "" &&
dslShape != d2target.ShapeImage &&
dslShape != d2target.ShapeSQLTable &&
dslShape != d2target.ShapeClass {
@ -1379,12 +1378,12 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
continue
}
if g.Theme != nil && g.Theme.SpecialRules.CapsLock && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeCode) {
if obj.Attributes.Language != "latex" && !obj.Attributes.Style.NoneTextTransform() {
obj.Attributes.Label.Value = strings.ToUpper(obj.Attributes.Label.Value)
if g.Theme != nil && g.Theme.SpecialRules.CapsLock && !strings.EqualFold(obj.Shape.Value, d2target.ShapeCode) {
if obj.Language != "latex" && !obj.Style.NoneTextTransform() {
obj.Label.Value = strings.ToUpper(obj.Label.Value)
}
}
obj.Attributes.ApplyTextTransform()
obj.ApplyTextTransform()
labelDims, err := obj.GetLabelSize(mtexts, ruler, fontFamily)
if err != nil {
@ -1394,7 +1393,7 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
// if there is a desired width or height, fit to content box without inner label padding for smallest minimum size
withInnerLabelPadding := desiredWidth == 0 && desiredHeight == 0 &&
dslShape != d2target.ShapeText && obj.Attributes.Label.Value != ""
dslShape != d2target.ShapeText && obj.Label.Value != ""
defaultDims, err := obj.GetDefaultSize(mtexts, ruler, fontFamily, *labelDims, withInnerLabelPadding)
if err != nil {
return err
@ -1426,7 +1425,7 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
}
// give shapes with icons extra padding to fit their label
if obj.Attributes.Icon != nil {
if obj.Icon != nil {
labelHeight := float64(labelDims.Height + INNER_LABEL_PADDING)
// Evenly pad enough to fit label above icon
if desiredWidth == 0 {
@ -1440,10 +1439,10 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
switch shapeType {
case shape.TABLE_TYPE, shape.CLASS_TYPE, shape.CODE_TYPE, shape.IMAGE_TYPE:
default:
if obj.Attributes.Link != nil {
if obj.Link != nil {
paddingX += 32
}
if obj.Attributes.Tooltip != nil {
if obj.Tooltip != nil {
paddingX += 32
}
}
@ -1489,18 +1488,18 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
edge.MinHeight += dims.Height + 5
}
if edge.Attributes.Label.Value == "" {
if edge.Label.Value == "" {
continue
}
if g.Theme != nil && g.Theme.SpecialRules.CapsLock && !edge.Attributes.Style.NoneTextTransform() {
edge.Attributes.Label.Value = strings.ToUpper(edge.Attributes.Label.Value)
if g.Theme != nil && g.Theme.SpecialRules.CapsLock && !edge.Style.NoneTextTransform() {
edge.Label.Value = strings.ToUpper(edge.Label.Value)
}
edge.Attributes.ApplyTextTransform()
edge.ApplyTextTransform()
usedFont := fontFamily
if edge.Attributes.Style.Font != nil {
f := d2fonts.D2_FONT_TO_FAMILY[edge.Attributes.Style.Font.Value]
if edge.Style.Font != nil {
f := d2fonts.D2_FONT_TO_FAMILY[edge.Style.Font.Value]
usedFont = &f
}
@ -1522,11 +1521,11 @@ func (g *Graph) Texts() []*d2target.MText {
capsLock := g.Theme != nil && g.Theme.SpecialRules.CapsLock
for _, obj := range g.Objects {
if obj.Attributes.Label.Value != "" {
obj.Attributes.ApplyTextTransform()
if obj.Label.Value != "" {
obj.ApplyTextTransform()
text := obj.Text()
if capsLock && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeCode) {
if obj.Attributes.Language != "latex" && !obj.Attributes.Style.NoneTextTransform() {
if capsLock && !strings.EqualFold(obj.Shape.Value, d2target.ShapeCode) {
if obj.Language != "latex" && !obj.Style.NoneTextTransform() {
text.Text = strings.ToUpper(text.Text)
}
}
@ -1534,8 +1533,8 @@ func (g *Graph) Texts() []*d2target.MText {
}
if obj.Class != nil {
fontSize := d2fonts.FONT_SIZE_L
if obj.Attributes.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(obj.Attributes.Style.FontSize.Value)
if obj.Style.FontSize != nil {
fontSize, _ = strconv.Atoi(obj.Style.FontSize.Value)
}
for _, field := range obj.Class.Fields {
texts = appendTextDedup(texts, field.Text(fontSize))
@ -1545,8 +1544,8 @@ func (g *Graph) Texts() []*d2target.MText {
}
} else if obj.SQLTable != nil {
colFontSize := d2fonts.FONT_SIZE_L
if obj.Attributes.Style.FontSize != nil {
colFontSize, _ = strconv.Atoi(obj.Attributes.Style.FontSize.Value)
if obj.Style.FontSize != nil {
colFontSize, _ = strconv.Atoi(obj.Style.FontSize.Value)
}
for _, column := range obj.SQLTable.Columns {
for _, t := range column.Texts(colFontSize) {
@ -1556,10 +1555,10 @@ func (g *Graph) Texts() []*d2target.MText {
}
}
for _, edge := range g.Edges {
if edge.Attributes.Label.Value != "" {
edge.Attributes.ApplyTextTransform()
if edge.Label.Value != "" {
edge.ApplyTextTransform()
text := edge.Text()
if capsLock && !edge.Attributes.Style.NoneTextTransform() {
if capsLock && !edge.Style.NoneTextTransform() {
text.Text = strings.ToUpper(text.Text)
}
texts = appendTextDedup(texts, text)

View file

@ -1,8 +1,8 @@
package d2graph
func (obj *Object) IsGridDiagram() bool {
return obj != nil && obj.Attributes != nil &&
(obj.Attributes.GridRows != nil || obj.Attributes.GridColumns != nil)
return obj != nil &&
(obj.GridRows != nil || obj.GridColumns != nil)
}
func (obj *Object) ClosestGridDiagram() *Object {

View file

@ -3,7 +3,7 @@ package d2graph
import "oss.terrastruct.com/d2/d2target"
func (obj *Object) IsSequenceDiagram() bool {
return obj != nil && obj.Attributes != nil && obj.Attributes.Shape.Value == d2target.ShapeSequenceDiagram
return obj != nil && obj.Shape.Value == d2target.ShapeSequenceDiagram
}
func (obj *Object) OuterSequenceDiagram() *Object {

View file

@ -265,73 +265,51 @@ func CompareSerializedObject(obj, other *Object) error {
}
}
if obj.Attributes != nil && other.Attributes == nil {
return fmt.Errorf("other should have attributes")
} else if obj.Attributes == nil && other.Attributes != nil {
return fmt.Errorf("other should not have attributes")
} else if obj.Attributes != nil {
if d2target.IsShape(obj.Attributes.Shape.Value) != d2target.IsShape(other.Attributes.Shape.Value) {
return fmt.Errorf(
"shapes differ: obj=%s, other=%s",
obj.Attributes.Shape.Value,
other.Attributes.Shape.Value,
)
}
if obj.Attributes.Icon == nil && other.Attributes.Icon != nil {
return fmt.Errorf("other does not have an icon")
} else if obj.Attributes.Icon != nil && other.Attributes.Icon == nil {
return fmt.Errorf("obj does not have an icon")
}
if obj.Attributes.Direction.Value != other.Attributes.Direction.Value {
return fmt.Errorf(
"directions differ: obj=%s, other=%s",
obj.Attributes.Direction.Value,
other.Attributes.Direction.Value,
)
}
if obj.Attributes.Label.Value != other.Attributes.Label.Value {
return fmt.Errorf(
"labels differ: obj=%s, other=%s",
obj.Attributes.Label.Value,
other.Attributes.Label.Value,
)
}
if obj.Attributes.NearKey != nil {
if other.Attributes.NearKey == nil {
return fmt.Errorf("other does not have near")
}
objKey := strings.Join(Key(obj.Attributes.NearKey), ".")
deserKey := strings.Join(Key(other.Attributes.NearKey), ".")
if objKey != deserKey {
return fmt.Errorf(
"near differs: obj=%s, other=%s",
objKey,
deserKey,
)
}
} else if other.Attributes.NearKey != nil {
return fmt.Errorf("other should not have near")
}
if d2target.IsShape(obj.Shape.Value) != d2target.IsShape(other.Shape.Value) {
return fmt.Errorf(
"shapes differ: obj=%s, other=%s",
obj.Shape.Value,
other.Shape.Value,
)
}
if obj.SQLTable == nil && other.SQLTable != nil {
return fmt.Errorf("other is not a sql table")
} else if obj.SQLTable != nil && other.SQLTable == nil {
return fmt.Errorf("obj is not a sql table")
if obj.Icon == nil && other.Icon != nil {
return fmt.Errorf("other does not have an icon")
} else if obj.Icon != nil && other.Icon == nil {
return fmt.Errorf("obj does not have an icon")
}
if obj.SQLTable != nil {
if len(obj.SQLTable.Columns) != len(other.SQLTable.Columns) {
if obj.Direction.Value != other.Direction.Value {
return fmt.Errorf(
"directions differ: obj=%s, other=%s",
obj.Direction.Value,
other.Direction.Value,
)
}
if obj.Label.Value != other.Label.Value {
return fmt.Errorf(
"labels differ: obj=%s, other=%s",
obj.Label.Value,
other.Label.Value,
)
}
if obj.NearKey != nil {
if other.NearKey == nil {
return fmt.Errorf("other does not have near")
}
objKey := strings.Join(Key(obj.NearKey), ".")
deserKey := strings.Join(Key(other.NearKey), ".")
if objKey != deserKey {
return fmt.Errorf(
"table columns count differ: obj=%d, other=%d",
len(obj.SQLTable.Columns),
len(other.SQLTable.Columns),
"near differs: obj=%s, other=%s",
objKey,
deserKey,
)
}
} else if other.NearKey != nil {
return fmt.Errorf("other should not have near")
}
if obj.LabelDimensions.Width != other.LabelDimensions.Width {
@ -350,6 +328,22 @@ func CompareSerializedObject(obj, other *Object) error {
)
}
if obj.SQLTable == nil && other.SQLTable != nil {
return fmt.Errorf("other is not a sql table")
} else if obj.SQLTable != nil && other.SQLTable == nil {
return fmt.Errorf("obj is not a sql table")
}
if obj.SQLTable != nil {
if len(obj.SQLTable.Columns) != len(other.SQLTable.Columns) {
return fmt.Errorf(
"table columns count differ: obj=%d, other=%d",
len(obj.SQLTable.Columns),
len(other.SQLTable.Columns),
)
}
}
return nil
}
@ -410,11 +404,11 @@ func CompareSerializedEdge(edge, other *Edge) error {
)
}
if edge.Attributes.Label.Value != other.Attributes.Label.Value {
if edge.Label.Value != other.Label.Value {
return fmt.Errorf(
"labels differ: edge=%s, other=%s",
edge.Attributes.Label.Value,
other.Attributes.Label.Value,
edge.Label.Value,
other.Label.Value,
)
}

View file

@ -93,7 +93,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
},
}
isHorizontal := false
switch g.Root.Attributes.Direction.Value {
switch g.Root.Direction.Value {
case "down":
rootAttrs.rankdir = "TB"
case "right":
@ -118,9 +118,9 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
maxContainerLabelHeight = go2.Max(maxContainerLabelHeight, obj.LabelDimensions.Height+label.PADDING)
}
if obj.Attributes.Icon != nil && obj.Attributes.Shape.Value != d2target.ShapeImage {
if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage {
contentBox := geo.NewBox(geo.NewPoint(0, 0), float64(obj.Width), float64(obj.Height))
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[obj.Attributes.Shape.Value]
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[obj.Shape.Value]
s := shape.NewShape(shapeType, contentBox)
iconSize := d2target.GetIconSize(s.GetInnerBox(), string(label.InsideTopLeft))
// Since dagre container labels are pushed up, we don't want a child container to collide
@ -161,7 +161,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
height := obj.Height
if obj.HasLabel() {
if obj.HasOutsideBottomLabel() || obj.Attributes.Icon != nil {
if obj.HasOutsideBottomLabel() || obj.Icon != nil {
height += float64(obj.LabelDimensions.Height) + label.PADDING
}
if len(obj.ChildrenArray) > 0 {
@ -189,7 +189,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
// We want to leave some gap between multiple edges
if numEdges > 1 {
switch g.Root.Attributes.Direction.Value {
switch g.Root.Direction.Value {
case "down", "up", "":
width += EDGE_LABEL_GAP
case "left", "right":
@ -242,13 +242,13 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
obj.LabelPosition = go2.Pointer(string(label.OutsideBottomCenter))
// remove the extra height we added to the node when passing to dagre
obj.Height -= float64(obj.LabelDimensions.Height) + label.PADDING
} else if obj.Attributes.Icon != nil {
} else if obj.Icon != nil {
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
} else {
obj.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}
if obj.Attributes.Icon != nil {
if obj.Icon != nil {
if len(obj.ChildrenArray) > 0 {
obj.IconPosition = go2.Pointer(string(label.OutsideTopLeft))
obj.LabelPosition = go2.Pointer(string(label.OutsideTopRight))
@ -453,15 +453,15 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
}
srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Attributes.Shape.Value)], edge.Src.Box)
dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Attributes.Shape.Value)], edge.Dst.Box)
srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Shape.Value)], edge.Src.Box)
dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Shape.Value)], edge.Dst.Box)
// trace the edge to the specific shape's border
points[startIndex] = shape.TraceToShapeBorder(srcShape, start, points[startIndex+1])
// if an edge to a container runs into its label, stop the edge at the label instead
overlapsContainerLabel := false
if edge.Dst.IsContainer() && edge.Dst.Attributes.Label.Value != "" && !dstShape.Is(shape.TEXT_TYPE) {
if edge.Dst.IsContainer() && edge.Dst.Label.Value != "" && !dstShape.Is(shape.TEXT_TYPE) {
// assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
labelWidth := float64(edge.Dst.LabelDimensions.Width)
labelHeight := float64(edge.Dst.LabelDimensions.Height)
@ -514,7 +514,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
edge.Route = path
// compile needs to assign edge label positions
if edge.Attributes.Label.Value != "" {
if edge.Label.Value != "" {
edge.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}

View file

@ -159,7 +159,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
},
},
}
switch g.Root.Attributes.Direction.Value {
switch g.Root.Direction.Value {
case "down":
elkGraph.LayoutOptions.Direction = "DOWN"
case "up":
@ -198,7 +198,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
}
if incoming >= 2 || outgoing >= 2 {
switch g.Root.Attributes.Direction.Value {
switch g.Root.Direction.Value {
case "right", "left":
obj.Height = math.Max(obj.Height, math.Max(incoming, outgoing)*port_spacing)
default:
@ -209,7 +209,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
height := obj.Height
width := obj.Width
if obj.HasLabel() {
if obj.HasOutsideBottomLabel() || obj.Attributes.Icon != nil {
if obj.HasOutsideBottomLabel() || obj.Icon != nil {
height += float64(obj.LabelDimensions.Height) + label.PADDING
}
width = go2.Max(width, float64(obj.LabelDimensions.Width))
@ -256,7 +256,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
n.Height += 100 + float64(labelHeight)
n.Width += 100
contentBox := geo.NewBox(geo.NewPoint(0, 0), float64(n.Width), float64(n.Height))
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[obj.Attributes.Shape.Value]
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[obj.Shape.Value]
s := shape.NewShape(shapeType, contentBox)
paddingTop := n.Height - s.GetInnerBox().Height
@ -264,7 +264,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
n.Width -= 100
iconHeight := 0
if obj.Attributes.Icon != nil && obj.Attributes.Shape.Value != d2target.ShapeImage {
if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage {
iconHeight = d2target.GetIconSize(s.GetInnerBox(), string(label.InsideTopLeft)) + label.PADDING*2
}
@ -283,7 +283,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
if obj.HasLabel() {
n.Labels = append(n.Labels, &ELKLabel{
Text: obj.Attributes.Label.Value,
Text: obj.Label.Value,
Width: float64(obj.LabelDimensions.Width),
Height: float64(obj.LabelDimensions.Height),
})
@ -303,9 +303,9 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
Sources: []string{edge.Src.AbsID()},
Targets: []string{edge.Dst.AbsID()},
}
if edge.Attributes.Label.Value != "" {
if edge.Label.Value != "" {
e.Labels = append(e.Labels, &ELKLabel{
Text: edge.Attributes.Label.Value,
Text: edge.Label.Value,
Width: float64(edge.LabelDimensions.Width),
Height: float64(edge.LabelDimensions.Height),
LayoutOptions: &elkOpts{
@ -397,13 +397,13 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
} else if obj.HasOutsideBottomLabel() {
obj.LabelPosition = go2.Pointer(string(label.OutsideBottomCenter))
obj.Height -= float64(obj.LabelDimensions.Height) + label.PADDING
} else if obj.Attributes.Icon != nil {
} else if obj.Icon != nil {
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
} else {
obj.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}
if obj.Attributes.Icon != nil {
if obj.Icon != nil {
if len(obj.ChildrenArray) > 0 {
obj.IconPosition = go2.Pointer(string(label.InsideTopLeft))
obj.LabelPosition = go2.Pointer(string(label.InsideTopRight))
@ -444,14 +444,14 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
startIndex, endIndex := 0, len(points)-1
srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Attributes.Shape.Value)], edge.Src.Box)
dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Attributes.Shape.Value)], edge.Dst.Box)
srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Shape.Value)], edge.Src.Box)
dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Shape.Value)], edge.Dst.Box)
// trace the edge to the specific shape's border
points[startIndex] = shape.TraceToShapeBorder(srcShape, points[startIndex], points[startIndex+1])
points[endIndex] = shape.TraceToShapeBorder(dstShape, points[endIndex], points[endIndex-1])
if edge.Attributes.Label.Value != "" {
if edge.Label.Value != "" {
edge.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
@ -519,7 +519,7 @@ func deleteBends(g *d2graph.Graph) {
newStart = geo.NewPoint(end.X, start.Y)
}
endpointShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(endpoint.Attributes.Shape.Value)], endpoint.Box)
endpointShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(endpoint.Shape.Value)], endpoint.Box)
newStart = shape.TraceToShapeBorder(endpointShape, newStart, end)
// Check that the new segment doesn't collide with anything new

View file

@ -32,11 +32,11 @@ func newGridDiagram(root *d2graph.Object) *gridDiagram {
horizontalGap: DEFAULT_GAP,
}
if root.Attributes.GridRows != nil {
gd.rows, _ = strconv.Atoi(root.Attributes.GridRows.Value)
if root.GridRows != nil {
gd.rows, _ = strconv.Atoi(root.GridRows.Value)
}
if root.Attributes.GridColumns != nil {
gd.columns, _ = strconv.Atoi(root.Attributes.GridColumns.Value)
if root.GridColumns != nil {
gd.columns, _ = strconv.Atoi(root.GridColumns.Value)
}
if gd.rows != 0 && gd.columns != 0 {
@ -47,7 +47,7 @@ func newGridDiagram(root *d2graph.Object) *gridDiagram {
// . │ g h i │ │ c f i │
// . └───────┘ └───────┘
// if keyword rows is first, make it row-directed, if columns is first it is column-directed
if root.Attributes.GridRows.MapKey.Range.Before(root.Attributes.GridColumns.MapKey.Range) {
if root.GridRows.MapKey.Range.Before(root.GridColumns.MapKey.Range) {
gd.rowDirected = true
}
@ -84,15 +84,15 @@ func newGridDiagram(root *d2graph.Object) *gridDiagram {
}
// grid gap sets both, but can be overridden
if root.Attributes.GridGap != nil {
gd.verticalGap, _ = strconv.Atoi(root.Attributes.GridGap.Value)
if root.GridGap != nil {
gd.verticalGap, _ = strconv.Atoi(root.GridGap.Value)
gd.horizontalGap = gd.verticalGap
}
if root.Attributes.VerticalGap != nil {
gd.verticalGap, _ = strconv.Atoi(root.Attributes.VerticalGap.Value)
if root.VerticalGap != nil {
gd.verticalGap, _ = strconv.Atoi(root.VerticalGap.Value)
}
if root.Attributes.HorizontalGap != nil {
gd.horizontalGap, _ = strconv.Atoi(root.Attributes.HorizontalGap.Value)
if root.HorizontalGap != nil {
gd.horizontalGap, _ = strconv.Atoi(root.HorizontalGap.Value)
}
return &gd

View file

@ -123,7 +123,7 @@ func layoutGrid(g *d2graph.Graph, obj *d2graph.Object) (*gridDiagram, error) {
// position labels and icons
for _, o := range gd.objects {
if o.Attributes.Icon != nil {
if o.Icon != nil {
o.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
o.IconPosition = go2.Pointer(string(label.InsideMiddleCenter))
} else {

View file

@ -33,7 +33,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, constantNearGraphs []*d2graph
for _, processCenters := range []bool{true, false} {
for _, tempGraph := range constantNearGraphs {
obj := tempGraph.Root.ChildrenArray[0]
if processCenters == strings.Contains(d2graph.Key(obj.Attributes.NearKey)[0], "-center") {
if processCenters == strings.Contains(d2graph.Key(obj.NearKey)[0], "-center") {
prevX, prevY := obj.TopLeft.X, obj.TopLeft.Y
obj.TopLeft = geo.NewPoint(place(obj))
dx, dy := obj.TopLeft.X-prevX, obj.TopLeft.Y-prevY
@ -56,7 +56,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, constantNearGraphs []*d2graph
}
for _, tempGraph := range constantNearGraphs {
obj := tempGraph.Root.ChildrenArray[0]
if processCenters == strings.Contains(d2graph.Key(obj.Attributes.NearKey)[0], "-center") {
if processCenters == strings.Contains(d2graph.Key(obj.NearKey)[0], "-center") {
// The z-index for constant nears does not matter, as it will not collide
g.Objects = append(g.Objects, tempGraph.Objects...)
if obj.Parent.Children == nil {
@ -78,7 +78,7 @@ func place(obj *d2graph.Object) (float64, float64) {
w := br.X - tl.X
h := br.Y - tl.Y
nearKeyStr := d2graph.Key(obj.Attributes.NearKey)[0]
nearKeyStr := d2graph.Key(obj.NearKey)[0]
var x, y float64
switch nearKeyStr {
case "top-left":
@ -139,14 +139,14 @@ func place(obj *d2graph.Object) (float64, float64) {
func WithoutConstantNears(ctx context.Context, g *d2graph.Graph) (constantNearGraphs []*d2graph.Graph) {
for i := 0; i < len(g.Objects); i++ {
obj := g.Objects[i]
if obj.Attributes.NearKey == nil {
if obj.NearKey == nil {
continue
}
_, isKey := g.Root.HasChild(d2graph.Key(obj.Attributes.NearKey))
_, isKey := g.Root.HasChild(d2graph.Key(obj.NearKey))
if isKey {
continue
}
_, isConst := d2graph.NearConstants[d2graph.Key(obj.Attributes.NearKey)[0]]
_, isConst := d2graph.NearConstants[d2graph.Key(obj.NearKey)[0]]
if isConst {
descendantObjects, edges := pluckObjAndEdges(g, obj)
@ -217,10 +217,10 @@ func boundingBox(g *d2graph.Graph) (tl, br *geo.Point) {
y2 := math.Inf(-1)
for _, obj := range g.Objects {
if obj.Attributes.NearKey != nil {
if obj.NearKey != nil {
// Top left should not be MORE top than top-center
// But it should go more left if top-center label extends beyond bounds of diagram
switch d2graph.Key(obj.Attributes.NearKey)[0] {
switch d2graph.Key(obj.NearKey)[0] {
case "top-center", "bottom-center":
x1 = math.Min(x1, obj.TopLeft.X)
x2 = math.Max(x2, obj.TopLeft.X+obj.Width)
@ -236,7 +236,7 @@ func boundingBox(g *d2graph.Graph) (tl, br *geo.Point) {
y1 = math.Min(y1, obj.TopLeft.Y)
x2 = math.Max(x2, obj.TopLeft.X+obj.Width)
y2 = math.Max(y2, obj.TopLeft.Y+obj.Height)
if obj.Attributes.Label.Value != "" && obj.LabelPosition != nil {
if obj.Label.Value != "" && obj.LabelPosition != nil {
labelPosition := label.Position(*obj.LabelPosition)
if labelPosition.IsOutside() {
labelTL := labelPosition.GetPointOnBox(obj.Box, label.PADDING, float64(obj.LabelDimensions.Width), float64(obj.LabelDimensions.Height))

View file

@ -54,7 +54,7 @@ func WithoutSequenceDiagrams(ctx context.Context, g *d2graph.Graph) (map[string]
if len(obj.ChildrenArray) == 0 {
continue
}
if obj.Attributes.Shape.Value != d2target.ShapeSequenceDiagram {
if obj.Shape.Value != d2target.ShapeSequenceDiagram {
queue = append(queue, obj.ChildrenArray...)
continue
}

View file

@ -180,7 +180,7 @@ b -> a.t2`
g, err := d2compiler.Compile("", strings.NewReader(input), nil)
assert.Nil(t, err)
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
g.Root.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
a, has := g.Root.HasChild([]string{"a"})
assert.True(t, has)
@ -217,14 +217,14 @@ b -> a.t2`
})
// check properties
assert.Equal(t, strings.ToLower(shape.PERSON_TYPE), strings.ToLower(a.Attributes.Shape.Value))
assert.Equal(t, strings.ToLower(shape.PERSON_TYPE), strings.ToLower(a.Shape.Value))
if a_t1.Attributes.Label.Value != "" {
t.Fatalf("expected no label for span, got %s", a_t1.Attributes.Label.Value)
if a_t1.Label.Value != "" {
t.Fatalf("expected no label for span, got %s", a_t1.Label.Value)
}
if a_t1.Attributes.Shape.Value != shape.SQUARE_TYPE {
t.Fatalf("expected square shape for span, got %s", a_t1.Attributes.Shape.Value)
if a_t1.Shape.Value != shape.SQUARE_TYPE {
t.Fatalf("expected square shape for span, got %s", a_t1.Shape.Value)
}
if a_t1.Height != b_t1.Height {
@ -323,7 +323,7 @@ container -> c: edge 1
c := g.Root.EnsureChild([]string{"c"})
c.Box = geo.NewBox(nil, 100, 100)
c.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSquare}
c.Shape = d2graph.Scalar{Value: d2target.ShapeSquare}
layoutFn := func(ctx context.Context, g *d2graph.Graph) error {
if len(g.Objects) != 2 {
@ -378,7 +378,7 @@ container -> c: edge 1
func TestSelfEdges(t *testing.T) {
g := d2graph.NewGraph()
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
g.Root.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
n1 := g.Root.EnsureChild([]string{"n1"})
n1.Box = geo.NewBox(nil, 100, 100)
@ -387,7 +387,7 @@ func TestSelfEdges(t *testing.T) {
Src: n1,
Dst: n1,
Index: 0,
Attributes: &d2graph.Attributes{
Attributes: d2graph.Attributes{
Label: d2graph.Scalar{Value: "left to right"},
},
},
@ -414,10 +414,10 @@ func TestSelfEdges(t *testing.T) {
func TestSequenceToDescendant(t *testing.T) {
g := d2graph.NewGraph()
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
g.Root.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
a := g.Root.EnsureChild([]string{"a"})
a.Box = geo.NewBox(nil, 100, 100)
a.Attributes = &d2graph.Attributes{
a.Attributes = d2graph.Attributes{
Shape: d2graph.Scalar{Value: shape.PERSON_TYPE},
}
a_t1 := a.EnsureChild([]string{"t1"})
@ -425,15 +425,13 @@ func TestSequenceToDescendant(t *testing.T) {
g.Edges = []*d2graph.Edge{
{
Src: a,
Dst: a_t1,
Index: 0,
Attributes: &d2graph.Attributes{},
Src: a,
Dst: a_t1,
Index: 0,
}, {
Src: a_t1,
Dst: a,
Index: 0,
Attributes: &d2graph.Attributes{},
Src: a_t1,
Dst: a,
Index: 0,
},
}

View file

@ -110,7 +110,7 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) (*s
sd.objectRank[actor] = rank
if actor.Width < MIN_ACTOR_WIDTH {
dslShape := strings.ToLower(actor.Attributes.Shape.Value)
dslShape := strings.ToLower(actor.Shape.Value)
switch dslShape {
case d2target.ShapePerson, d2target.ShapeOval, d2target.ShapeSquare, d2target.ShapeCircle:
// scale shape up to min width uniformly
@ -131,7 +131,7 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) (*s
// edge groups are children of actors with no edges and children edges
if child.IsSequenceDiagramNote() {
sd.verticalIndices[child.AbsID()] = getObjEarliestLineNum(child)
child.Attributes.Shape = d2graph.Scalar{Value: shape.PAGE_TYPE}
child.Shape = d2graph.Scalar{Value: shape.PAGE_TYPE}
sd.notes = append(sd.notes, child)
sd.objectRank[child] = rank
child.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
@ -139,8 +139,8 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) (*s
} else {
// spans have no labels
// TODO why not? Spans should be able to
child.Attributes.Label = d2graph.Scalar{Value: ""}
child.Attributes.Shape = d2graph.Scalar{Value: shape.SQUARE_TYPE}
child.Label = d2graph.Scalar{Value: ""}
child.Shape = d2graph.Scalar{Value: shape.SQUARE_TYPE}
sd.spans = append(sd.spans, child)
sd.objectRank[child] = rank
}
@ -390,15 +390,15 @@ func (sd *sequenceDiagram) addLifelineEdges() {
StrokeDash: &d2graph.Scalar{Value: fmt.Sprintf("%d", LIFELINE_STROKE_DASH)},
StrokeWidth: &d2graph.Scalar{Value: fmt.Sprintf("%d", LIFELINE_STROKE_WIDTH)},
}
if actor.Attributes.Style.StrokeDash != nil {
style.StrokeDash = &d2graph.Scalar{Value: actor.Attributes.Style.StrokeDash.Value}
if actor.Style.StrokeDash != nil {
style.StrokeDash = &d2graph.Scalar{Value: actor.Style.StrokeDash.Value}
}
if actor.Attributes.Style.Stroke != nil {
style.Stroke = &d2graph.Scalar{Value: actor.Attributes.Style.Stroke.Value}
if actor.Style.Stroke != nil {
style.Stroke = &d2graph.Scalar{Value: actor.Style.Stroke.Value}
}
sd.lifelines = append(sd.lifelines, &d2graph.Edge{
Attributes: &d2graph.Attributes{Style: style},
Attributes: d2graph.Attributes{Style: style},
Src: actor,
SrcArrow: false,
Dst: &d2graph.Object{
@ -581,7 +581,7 @@ func (sd *sequenceDiagram) routeMessages() error {
}
messageOffset += sd.yStep
if message.Attributes.Label.Value != "" {
if message.Label.Value != "" {
message.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}

View file

@ -159,12 +159,12 @@ func _set(g *d2graph.Graph, key string, tag, value *string) error {
}
}
if obj.Attributes.Label.MapKey != nil && obj.Map == nil && (!found || reserved || len(mk.Edges) > 0) {
if obj.Label.MapKey != nil && obj.Map == nil && (!found || reserved || len(mk.Edges) > 0) {
obj.Map = &d2ast.Map{
Range: d2ast.MakeRange(",1:0:0-1:0:0"),
}
obj.Attributes.Label.MapKey.Primary = obj.Attributes.Label.MapKey.Value.ScalarBox()
obj.Attributes.Label.MapKey.Value = d2ast.MakeValueBox(obj.Map)
obj.Label.MapKey.Primary = obj.Label.MapKey.Value.ScalarBox()
obj.Label.MapKey.Value = d2ast.MakeValueBox(obj.Map)
scope = obj.Map
mk.Key.Path = mk.Key.Path[toSkip-1:]
@ -247,10 +247,10 @@ func _set(g *d2graph.Graph, key string, tag, value *string) error {
if n.MapKey.Key.Path[0].Unbox().ScalarString() == mk.Key.Path[toSkip-1].Unbox().ScalarString() {
scope = n.MapKey.Value.Map
if mk.Key.Path[0].Unbox().ScalarString() == "source-arrowhead" && edge.SrcArrowhead != nil {
attrs = edge.SrcArrowhead
attrs = *edge.SrcArrowhead
}
if mk.Key.Path[0].Unbox().ScalarString() == "target-arrowhead" && edge.DstArrowhead != nil {
attrs = edge.DstArrowhead
attrs = *edge.DstArrowhead
}
reservedKey = mk.Key.Path[0].Unbox().ScalarString()
mk.Key.Path = mk.Key.Path[1:]
@ -295,13 +295,13 @@ func _set(g *d2graph.Graph, key string, tag, value *string) error {
return nil
}
case "width":
if attrs.Width != nil && attrs.Width.MapKey != nil {
attrs.Width.MapKey.SetScalar(mk.Value.ScalarBox())
if attrs.WidthAttr != nil && attrs.WidthAttr.MapKey != nil {
attrs.WidthAttr.MapKey.SetScalar(mk.Value.ScalarBox())
return nil
}
case "height":
if attrs.Height != nil && attrs.Height.MapKey != nil {
attrs.Height.MapKey.SetScalar(mk.Value.ScalarBox())
if attrs.HeightAttr != nil && attrs.HeightAttr.MapKey != nil {
attrs.HeightAttr.MapKey.SetScalar(mk.Value.ScalarBox())
return nil
}
case "top":
@ -340,12 +340,13 @@ func _set(g *d2graph.Graph, key string, tag, value *string) error {
return nil
}
case "source-arrowhead", "target-arrowhead":
var arrowhead *d2graph.Attributes
if reservedKey == "source-arrowhead" {
attrs = edge.SrcArrowhead
arrowhead = edge.SrcArrowhead
} else {
attrs = edge.DstArrowhead
arrowhead = edge.DstArrowhead
}
if attrs != nil {
if arrowhead != nil {
if reservedTargetKey == "" {
if len(mk.Key.Path[reservedIndex:]) != 2 {
return errors.New("malformed style setting, expected 2 part path")
@ -354,13 +355,13 @@ func _set(g *d2graph.Graph, key string, tag, value *string) error {
}
switch reservedTargetKey {
case "shape":
if attrs.Shape.MapKey != nil {
attrs.Shape.MapKey.SetScalar(mk.Value.ScalarBox())
if arrowhead.Shape.MapKey != nil {
arrowhead.Shape.MapKey.SetScalar(mk.Value.ScalarBox())
return nil
}
case "label":
if attrs.Label.MapKey != nil {
attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
if arrowhead.Label.MapKey != nil {
arrowhead.Label.MapKey.SetScalar(mk.Value.ScalarBox())
return nil
}
}
@ -664,7 +665,7 @@ func renameConflictsToParent(g *d2graph.Graph, key *d2ast.KeyPath) (*d2graph.Gra
if !ok {
return g, nil
}
if obj.Attributes.Shape.Value == d2target.ShapeSQLTable || obj.Attributes.Shape.Value == d2target.ShapeClass {
if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
return g, nil
}
@ -961,7 +962,7 @@ func deleteObject(g *d2graph.Graph, key *d2ast.KeyPath, obj *d2graph.Object) (*d
isSpecial := isReserved || x.Unbox().ScalarString() == "_"
return !isSpecial
})
if obj.Attributes.Shape.Value == d2target.ShapeSQLTable || obj.Attributes.Shape.Value == d2target.ShapeClass {
if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
deleteFromMap(ref.Scope, ref.MapKey)
} else if len(withoutSpecial) == 0 {
hoistRefChildren(g, key, ref)
@ -990,7 +991,7 @@ func deleteObject(g *d2graph.Graph, key *d2ast.KeyPath, obj *d2graph.Object) (*d
} else if ref.InEdge() {
edge := ref.MapKey.Edges[ref.MapKeyEdgeIndex]
if obj.Attributes.Shape.Value == d2target.ShapeSQLTable || obj.Attributes.Shape.Value == d2target.ShapeClass {
if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
if ref.MapKeyEdgeDest() {
ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, edge.Src, true)
} else {

View file

@ -50,11 +50,11 @@ func TestCreate(t *testing.T) {
if g.Objects[0].ID != "square" {
t.Fatalf("expected g.Objects[0].ID to be square: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[0].Attributes.Label.Node.Value.Unbox() == nil: %#v", g.Objects[0].Attributes.Label.MapKey.Value)
if g.Objects[0].Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[0].Label.Node.Value.Unbox() == nil: %#v", g.Objects[0].Label.MapKey.Value)
}
if d2format.Format(g.Objects[0].Attributes.Label.MapKey.Key) != "square" {
t.Fatalf("expected g.Objects[0].Attributes.Label.Node.Key to be square: %#v", g.Objects[0].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[0].Label.MapKey.Key) != "square" {
t.Fatalf("expected g.Objects[0].Label.Node.Key to be square: %#v", g.Objects[0].Label.MapKey.Key)
}
},
},
@ -92,11 +92,11 @@ x 2
if g.Objects[2].AbsID() != "b.c.square" {
t.Fatalf("bad absolute ID: %#v", g.Objects[2].AbsID())
}
if d2format.Format(g.Objects[2].Attributes.Label.MapKey.Key) != "b.c.square" {
t.Fatalf("bad mapkey: %#v", g.Objects[2].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[2].Label.MapKey.Key) != "b.c.square" {
t.Fatalf("bad mapkey: %#v", g.Objects[2].Label.MapKey.Key)
}
if g.Objects[2].Attributes.Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected nil mapkey value: %#v", g.Objects[2].Attributes.Label.MapKey.Value)
if g.Objects[2].Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected nil mapkey value: %#v", g.Objects[2].Label.MapKey.Value)
}
},
},
@ -116,11 +116,11 @@ square 2
if g.Objects[1].ID != "square 2" {
t.Fatalf("expected g.Objects[1].ID to be square 2: %#v", g.Objects[1])
}
if g.Objects[1].Attributes.Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[1].Attributes.Label.Node.Value.Unbox() == nil: %#v", g.Objects[1].Attributes.Label.MapKey.Value)
if g.Objects[1].Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[1].Label.Node.Value.Unbox() == nil: %#v", g.Objects[1].Label.MapKey.Value)
}
if d2format.Format(g.Objects[1].Attributes.Label.MapKey.Key) != "square 2" {
t.Fatalf("expected g.Objects[1].Attributes.Label.Node.Key to be square 2: %#v", g.Objects[1].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[1].Label.MapKey.Key) != "square 2" {
t.Fatalf("expected g.Objects[1].Label.Node.Key to be square 2: %#v", g.Objects[1].Label.MapKey.Key)
}
},
},
@ -160,11 +160,11 @@ x.y.z.square 2
if g.Objects[3].ID != "square" {
t.Fatalf("expected g.Objects[3].ID to be square: %#v", g.Objects[3])
}
if g.Objects[3].Attributes.Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[3].Attributes.Label.Node.Value.Unbox() == nil: %#v", g.Objects[3].Attributes.Label.MapKey.Value)
if g.Objects[3].Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[3].Label.Node.Value.Unbox() == nil: %#v", g.Objects[3].Label.MapKey.Value)
}
if d2format.Format(g.Objects[3].Attributes.Label.MapKey.Key) != "square" {
t.Fatalf("expected g.Objects[3].Attributes.Label.Node.Key to be square: %#v", g.Objects[3].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[3].Label.MapKey.Key) != "square" {
t.Fatalf("expected g.Objects[3].Label.Node.Key to be square: %#v", g.Objects[3].Label.MapKey.Key)
}
},
},
@ -188,11 +188,11 @@ x.y.z.square 2
if g.Objects[4].ID != "square 2" {
t.Fatalf("expected g.Objects[4].ID to be square 2: %#v", g.Objects[4])
}
if g.Objects[4].Attributes.Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[4].Attributes.Label.Node.Value.Unbox() == nil: %#v", g.Objects[4].Attributes.Label.MapKey.Value)
if g.Objects[4].Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[4].Label.Node.Value.Unbox() == nil: %#v", g.Objects[4].Label.MapKey.Value)
}
if d2format.Format(g.Objects[4].Attributes.Label.MapKey.Key) != "square 2" {
t.Fatalf("expected g.Objects[4].Attributes.Label.Node.Key to be square 2: %#v", g.Objects[4].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[4].Label.MapKey.Key) != "square 2" {
t.Fatalf("expected g.Objects[4].Label.Node.Key to be square 2: %#v", g.Objects[4].Label.MapKey.Key)
}
},
},
@ -234,8 +234,8 @@ x.y.z.square 2
if g.Objects[13].ID != "square 11" {
t.Fatalf("expected g.Objects[13].ID to be square 11: %#v", g.Objects[13])
}
if d2format.Format(g.Objects[13].Attributes.Label.MapKey.Key) != "square 11" {
t.Fatalf("expected g.Objects[13].Attributes.Label.Node.Key to be square 11: %#v", g.Objects[13].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[13].Label.MapKey.Key) != "square 11" {
t.Fatalf("expected g.Objects[13].Label.Node.Key to be square 11: %#v", g.Objects[13].Label.MapKey.Key)
}
},
},
@ -517,11 +517,11 @@ func TestSet(t *testing.T) {
if g.Objects[0].ID != "square" {
t.Fatalf("expected g.Objects[0].ID to be square: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[0].Attributes.Label.Node.Value.Unbox() == nil: %#v", g.Objects[0].Attributes.Label.MapKey.Value)
if g.Objects[0].Label.MapKey.Value.Unbox() != nil {
t.Fatalf("expected g.Objects[0].Label.Node.Value.Unbox() == nil: %#v", g.Objects[0].Label.MapKey.Value)
}
if d2format.Format(g.Objects[0].Attributes.Label.MapKey.Key) != "square" {
t.Fatalf("expected g.Objects[0].Attributes.Label.Node.Key to be square: %#v", g.Objects[0].Attributes.Label.MapKey.Key)
if d2format.Format(g.Objects[0].Label.MapKey.Key) != "square" {
t.Fatalf("expected g.Objects[0].Label.Node.Key to be square: %#v", g.Objects[0].Label.MapKey.Key)
}
},
},
@ -546,8 +546,8 @@ func TestSet(t *testing.T) {
if g.Edges[0].Dst.ID != "y" {
t.Fatalf("expected g.Edges[0].Dst.ID == y: %#v", g.Edges[0].Dst.ID)
}
if g.Edges[0].Attributes.Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Attributes.Label.Value == two: %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Label.Value == two: %#v", g.Edges[0].Label.Value)
}
},
},
@ -566,8 +566,8 @@ func TestSet(t *testing.T) {
if g.Objects[0].ID != "square" {
t.Fatalf("expected g.Objects[0].ID to be square: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value != d2target.ShapeSquare {
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value == square: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value != d2target.ShapeSquare {
t.Fatalf("expected g.Objects[0].Shape.Value == square: %#v", g.Objects[0].Shape.Value)
}
},
},
@ -586,8 +586,8 @@ func TestSet(t *testing.T) {
if g.Objects[0].ID != "square" {
t.Fatalf("expected g.Objects[0].ID to be square: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value != d2target.ShapeCircle {
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value == circle: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value != d2target.ShapeCircle {
t.Fatalf("expected g.Objects[0].Shape.Value == circle: %#v", g.Objects[0].Shape.Value)
}
},
},
@ -606,7 +606,7 @@ func TestSet(t *testing.T) {
if len(g.Objects) != 1 {
t.Fatalf("expected 1 object but got %#v", len(g.Objects))
}
f, err := strconv.ParseFloat(g.Objects[0].Attributes.Style.Opacity.Value, 64)
f, err := strconv.ParseFloat(g.Objects[0].Style.Opacity.Value, 64)
if err != nil || f != 0.2 {
t.Fatalf("expected g.Objects[0].Map.Nodes[0].MapKey.Value.Number.Value.Float64() == 0.2: %#v", f)
}
@ -652,7 +652,7 @@ func TestSet(t *testing.T) {
if len(g.AST.Nodes[0].MapKey.Value.Map.Nodes) != 1 {
t.Fatalf("expected 1 node within square but got %v", len(g.AST.Nodes[0].MapKey.Value.Map.Nodes))
}
f, err := strconv.ParseFloat(g.Objects[0].Attributes.Style.Opacity.Value, 64)
f, err := strconv.ParseFloat(g.Objects[0].Style.Opacity.Value, 64)
if err != nil || f != 0.2 {
t.Fatal(err, f)
}
@ -670,7 +670,7 @@ func TestSet(t *testing.T) {
if len(g.AST.Nodes) != 1 {
t.Fatal(g.AST)
}
f, err := strconv.ParseFloat(g.Objects[0].Attributes.Style.Opacity.Value, 64)
f, err := strconv.ParseFloat(g.Objects[0].Style.Opacity.Value, 64)
if err != nil || f != 0.2 {
t.Fatal(err, f)
}
@ -689,7 +689,7 @@ square.style.opacity: 0.2
if len(g.AST.Nodes) != 2 {
t.Fatal(g.AST)
}
f, err := strconv.ParseFloat(g.Objects[0].Attributes.Style.Opacity.Value, 64)
f, err := strconv.ParseFloat(g.Objects[0].Style.Opacity.Value, 64)
if err != nil || f != 0.2 {
t.Fatal(err, f)
}
@ -877,8 +877,8 @@ square.style.opacity: 0.2
if g.Objects[0].ID != "square" {
t.Fatalf("expected g.Objects[0].ID to be square: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value == d2target.ShapeSquare {
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value == square: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value == d2target.ShapeSquare {
t.Fatalf("expected g.Objects[0].Shape.Value == square: %#v", g.Objects[0].Shape.Value)
}
},
},
@ -897,8 +897,8 @@ square.style.opacity: 0.2
if g.Objects[0].ID != "square" {
t.Fatalf("expected g.Objects[0].ID to be square: %#v", g.Objects[0])
}
if g.Objects[0].Attributes.Shape.Value == d2target.ShapeSquare {
t.Fatalf("expected g.Objects[0].Attributes.Shape.Value == square: %#v", g.Objects[0].Attributes.Shape.Value)
if g.Objects[0].Shape.Value == d2target.ShapeSquare {
t.Fatalf("expected g.Objects[0].Shape.Value == square: %#v", g.Objects[0].Shape.Value)
}
},
},
@ -920,8 +920,8 @@ square.style.opacity: 0.2
if g.Objects[0].ID != "square" {
t.Fatal(g.Objects[0])
}
if g.Objects[0].Attributes.Label.Value == "I am deeply CONCERNED and I want something GOOD for BREAKFAST!" {
t.Fatal(g.Objects[0].Attributes.Label.Value)
if g.Objects[0].Label.Value == "I am deeply CONCERNED and I want something GOOD for BREAKFAST!" {
t.Fatal(g.Objects[0].Label.Value)
}
},
},
@ -1036,8 +1036,8 @@ z: {
if len(g.Edges) != 2 {
t.Fatalf("expected 2 edges: %#v", g.Edges)
}
if g.Edges[0].Attributes.Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Attributes.Label.Value == two: %#v", g.Edges[0].Attributes.Label.Value)
if g.Edges[0].Label.Value != "two" {
t.Fatalf("expected g.Edges[0].Label.Value == two: %#v", g.Edges[0].Label.Value)
}
},
},
@ -1054,8 +1054,8 @@ z: {
if len(g.Objects) != 1 {
t.Fatal(g.Objects)
}
if g.Objects[0].Attributes.Icon.String() != "https://icons.terrastruct.com/essentials/087-menu.svg" {
t.Fatal(g.Objects[0].Attributes.Icon.String())
if g.Objects[0].Icon.String() != "https://icons.terrastruct.com/essentials/087-menu.svg" {
t.Fatal(g.Objects[0].Icon.String())
}
},
},
@ -1133,7 +1133,7 @@ z: {
assert.JSON(t, 3, len(g.Objects))
assert.JSON(t, 1, len(g.Edges))
assert.JSON(t, "q", g.Edges[0].Src.ID)
assert.JSON(t, "0.4", g.Edges[0].Attributes.Style.Opacity.Value)
assert.JSON(t, "0.4", g.Edges[0].Style.Opacity.Value)
},
},
{
@ -1309,8 +1309,8 @@ a.b -> a.c: {style.animated: true}
if g.Edges[0].Src.ID != "q" {
t.Fatal(g.Edges[0].Src.ID)
}
if g.Edges[0].Attributes.Style.Opacity.Value != "0.4" {
t.Fatal(g.Edges[0].Attributes.Style.Opacity.Value)
if g.Edges[0].Style.Opacity.Value != "0.4" {
t.Fatal(g.Edges[0].Style.Opacity.Value)
}
},
},

View file

@ -33,19 +33,19 @@ func FeatureSupportCheck(info *PluginInfo, g *d2graph.Graph) error {
}
for _, obj := range g.Objects {
if obj.Attributes.Top != nil || obj.Attributes.Left != nil {
if obj.Top != nil || obj.Left != nil {
if _, ok := featureMap[TOP_LEFT]; !ok {
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)
}
}
if (obj.Attributes.Width != nil || obj.Attributes.Height != nil) && len(obj.ChildrenArray) > 0 {
if (obj.WidthAttr != nil || obj.HeightAttr != nil) && len(obj.ChildrenArray) > 0 {
if _, ok := featureMap[CONTAINER_DIMENSIONS]; !ok {
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)
}
}
if obj.Attributes.NearKey != nil {
_, isKey := g.Root.HasChild(d2graph.Key(obj.Attributes.NearKey))
if obj.NearKey != nil {
_, isKey := g.Root.HasChild(d2graph.Key(obj.NearKey))
if isKey {
if _, ok := featureMap[NEAR_OBJECT]; !ok {
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)