package graph import ( "context" _ "embed" "fmt" "oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2layouts/d2elklayout" "oss.terrastruct.com/d2/d2lib" "oss.terrastruct.com/d2/d2oracle" "oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/lib/textmeasure" ) var ( //go:embed style.d2 style string ) type d2 struct { g *d2graph.Graph d *d2target.Diagram } func (g *graph) toD2(ctx context.Context, providerLabels bool) (*d2, error) { // Initialize a ruler to measure font glyphs ruler, err := textmeasure.NewRuler() if err != nil { return nil, err } d, d2g, err := d2lib.Compile(ctx, style, &d2lib.CompileOptions{ LayoutResolver: func(_ string) (d2graph.LayoutGraph, error) { return d2elklayout.DefaultLayout, nil }, Ruler: ruler, }, nil) if err != nil { return nil, err } // First create all nodes, then connections, so we don't implicitly create the // same node twice due to `Create()` creating any pieces that dont exist when // creating edges or containers. for _, key := range g.keys { n := g.nodes[key] id := d2NodeID(n) d2g, id, err = d2oracle.Create(d2g, nil, id) if err != nil { return nil, err } d2g, err = d2oracle.Set(d2g, nil, fmt.Sprintf("%s.class", id), nil, &n.nodeType) if err != nil { return nil, err } if n.nodeType == objectsNode { y := "yaml" d2g, err = d2oracle.Set(d2g, nil, id, &y, &n.data) if err != nil { return nil, err } continue } label := n.label() d2g, err = d2oracle.Set(d2g, nil, fmt.Sprintf("%s.label", id), nil, &label) if err != nil { return nil, err } } for _, key := range g.keys { n := g.nodes[key] id := d2NodeID(n) for _, d := range n.deps { id := fmt.Sprintf("%s -> %s", id, d2NodeID(d)) d2g, id, err = d2oracle.Create(d2g, nil, id) if err != nil { return nil, err } if providerLabels && n.nodeType == idxNode && d.nodeType == imgNode && d.labels["providers"] != "" { p := d.labels["providers"] d2g, err = d2oracle.Set(d2g, nil, id, nil, &p) if err != nil { return nil, err } } } } return &d2{d2g, d}, nil } // d2NodeID creates an ID for d2 graphs separate from the visible label func d2NodeID(n *node) string { return fmt.Sprintf("%s-%s-%s", n.name, n.nodeType, n.digest.Hex[:4]) }