2022-11-03 13:54:49 +00:00
|
|
|
package d2oracle
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
|
2023-05-19 23:08:23 +00:00
|
|
|
"oss.terrastruct.com/d2/d2ast"
|
|
|
|
|
"oss.terrastruct.com/d2/d2format"
|
2022-11-03 13:54:49 +00:00
|
|
|
"oss.terrastruct.com/d2/d2graph"
|
|
|
|
|
"oss.terrastruct.com/d2/d2parser"
|
|
|
|
|
)
|
|
|
|
|
|
2023-06-16 23:23:08 +00:00
|
|
|
func GetBoardGraph(g *d2graph.Graph, boardPath []string) *d2graph.Graph {
|
|
|
|
|
if len(boardPath) == 0 {
|
|
|
|
|
return g
|
|
|
|
|
}
|
2023-06-21 21:26:13 +00:00
|
|
|
for i, b := range g.Layers {
|
|
|
|
|
if b.Name == boardPath[0] {
|
2023-08-05 20:25:30 +00:00
|
|
|
g2 := GetBoardGraph(g.Layers[i], boardPath[1:])
|
|
|
|
|
if g2 != nil {
|
|
|
|
|
g2.FS = g.FS
|
|
|
|
|
}
|
|
|
|
|
return g2
|
2023-06-16 23:23:08 +00:00
|
|
|
}
|
2023-06-21 21:26:13 +00:00
|
|
|
}
|
|
|
|
|
for i, b := range g.Scenarios {
|
|
|
|
|
if b.Name == boardPath[0] {
|
2023-08-05 20:25:30 +00:00
|
|
|
g2 := GetBoardGraph(g.Scenarios[i], boardPath[1:])
|
|
|
|
|
if g2 != nil {
|
|
|
|
|
g2.FS = g.FS
|
|
|
|
|
}
|
|
|
|
|
return g2
|
2023-06-16 23:23:08 +00:00
|
|
|
}
|
2023-06-21 21:26:13 +00:00
|
|
|
}
|
|
|
|
|
for i, b := range g.Steps {
|
|
|
|
|
if b.Name == boardPath[0] {
|
2023-08-05 20:25:30 +00:00
|
|
|
g2 := GetBoardGraph(g.Steps[i], boardPath[1:])
|
|
|
|
|
if g2 != nil {
|
|
|
|
|
g2.FS = g.FS
|
|
|
|
|
}
|
|
|
|
|
return g2
|
2023-06-16 23:23:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-19 06:57:29 +00:00
|
|
|
func ReplaceBoardNode(ast, ast2 *d2ast.Map, boardPath []string) bool {
|
|
|
|
|
if len(boardPath) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2023-06-21 21:26:13 +00:00
|
|
|
|
2025-04-27 15:20:11 +00:00
|
|
|
return replaceBoardNodeInMap(ast, ast2, boardPath, "layers") ||
|
|
|
|
|
replaceBoardNodeInMap(ast, ast2, boardPath, "scenarios") ||
|
|
|
|
|
replaceBoardNodeInMap(ast, ast2, boardPath, "steps")
|
|
|
|
|
}
|
2023-06-21 21:26:13 +00:00
|
|
|
|
2025-04-27 15:20:11 +00:00
|
|
|
func replaceBoardNodeInMap(ast, ast2 *d2ast.Map, boardPath []string, boardType string) bool {
|
|
|
|
|
var matches []*d2ast.Map
|
2023-06-21 21:26:13 +00:00
|
|
|
|
2025-04-27 15:20:11 +00:00
|
|
|
for _, n := range ast.Nodes {
|
|
|
|
|
if n.MapKey != nil && n.MapKey.Key != nil &&
|
|
|
|
|
n.MapKey.Key.Path[0].Unbox().ScalarString() == boardType &&
|
|
|
|
|
n.MapKey.Value.Map != nil {
|
|
|
|
|
matches = append(matches, n.MapKey.Value.Map)
|
2023-06-19 06:57:29 +00:00
|
|
|
}
|
2023-06-21 21:26:13 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-27 15:20:11 +00:00
|
|
|
for _, boardMap := range matches {
|
|
|
|
|
for _, n := range boardMap.Nodes {
|
|
|
|
|
if n.MapKey != nil && n.MapKey.Key != nil &&
|
|
|
|
|
n.MapKey.Key.Path[0].Unbox().ScalarString() == boardPath[0] &&
|
|
|
|
|
n.MapKey.Value.Map != nil {
|
|
|
|
|
if len(boardPath) > 1 {
|
|
|
|
|
if ReplaceBoardNode(n.MapKey.Value.Map, ast2, boardPath[1:]) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
n.MapKey.Value.Map.Nodes = ast2.Nodes
|
|
|
|
|
return true
|
|
|
|
|
}
|
2023-06-19 06:57:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 22:43:26 +00:00
|
|
|
func GetChildrenIDs(g *d2graph.Graph, boardPath []string, absID string) (ids []string, _ error) {
|
|
|
|
|
g = GetBoardGraph(g, boardPath)
|
|
|
|
|
if g == nil {
|
|
|
|
|
return nil, fmt.Errorf("board at path %v not found", boardPath)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 23:17:59 +00:00
|
|
|
mk, err := d2parser.ParseMapKey(absID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
obj, ok := g.Root.HasChild(d2graph.Key(mk.Key))
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, fmt.Errorf("%v not found", absID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, ch := range obj.ChildrenArray {
|
|
|
|
|
ids = append(ids, ch.AbsID())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ids, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 22:43:26 +00:00
|
|
|
func GetParentID(g *d2graph.Graph, boardPath []string, absID string) (string, error) {
|
|
|
|
|
g = GetBoardGraph(g, boardPath)
|
|
|
|
|
if g == nil {
|
|
|
|
|
return "", fmt.Errorf("board at path %v not found", boardPath)
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
mk, err := d2parser.ParseMapKey(absID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
obj, ok := g.Root.HasChild(d2graph.Key(mk.Key))
|
|
|
|
|
if !ok {
|
2023-03-20 03:50:53 +00:00
|
|
|
return "", fmt.Errorf("%v not found", absID)
|
2022-11-03 13:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj.Parent.AbsID(), nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-09 18:34:25 +00:00
|
|
|
func IsImportedObj(ast *d2ast.Map, obj *d2graph.Object) bool {
|
2024-01-02 21:15:53 +00:00
|
|
|
for _, ref := range obj.References {
|
2024-03-05 01:51:05 +00:00
|
|
|
if ref.Key.HasGlob() {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2024-01-04 19:46:36 +00:00
|
|
|
if ref.Key.Range.Path != ast.Range.Path {
|
|
|
|
|
return true
|
2024-01-02 21:15:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-04 19:46:36 +00:00
|
|
|
return false
|
2024-01-02 21:15:53 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-05 18:59:21 +00:00
|
|
|
// Glob creations count as imported for now
|
2024-03-05 01:51:05 +00:00
|
|
|
// TODO Probably rename later
|
2024-02-09 18:34:25 +00:00
|
|
|
func IsImportedEdge(ast *d2ast.Map, edge *d2graph.Edge) bool {
|
|
|
|
|
for _, ref := range edge.References {
|
2024-06-05 18:59:21 +00:00
|
|
|
// If edge index, the glob is just setting something, not responsible for creating the edge
|
|
|
|
|
if (ref.Edge.Src.HasGlob() || ref.Edge.Dst.HasGlob()) && ref.MapKey.EdgeIndex == nil {
|
2024-03-05 01:51:05 +00:00
|
|
|
return true
|
|
|
|
|
}
|
2024-02-09 18:34:25 +00:00
|
|
|
if ref.Edge.Range.Path != ast.Range.Path {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 22:43:26 +00:00
|
|
|
func GetObj(g *d2graph.Graph, boardPath []string, absID string) *d2graph.Object {
|
|
|
|
|
g = GetBoardGraph(g, boardPath)
|
|
|
|
|
if g == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
mk, _ := d2parser.ParseMapKey(absID)
|
|
|
|
|
obj, _ := g.Root.HasChild(d2graph.Key(mk.Key))
|
|
|
|
|
return obj
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 22:43:26 +00:00
|
|
|
func GetEdge(g *d2graph.Graph, boardPath []string, absID string) *d2graph.Edge {
|
|
|
|
|
g = GetBoardGraph(g, boardPath)
|
|
|
|
|
if g == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
for _, e := range g.Edges {
|
|
|
|
|
if e.AbsID() == absID {
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 22:43:26 +00:00
|
|
|
func GetObjOrder(g *d2graph.Graph, boardPath []string) ([]string, error) {
|
|
|
|
|
g = GetBoardGraph(g, boardPath)
|
|
|
|
|
if g == nil {
|
|
|
|
|
return nil, fmt.Errorf("board at path %v not found", boardPath)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-10 23:39:42 +00:00
|
|
|
var order []string
|
|
|
|
|
|
|
|
|
|
queue := []*d2graph.Object{g.Root}
|
|
|
|
|
for len(queue) > 0 {
|
|
|
|
|
curr := queue[0]
|
|
|
|
|
queue = queue[1:]
|
2023-05-11 03:25:40 +00:00
|
|
|
if curr != g.Root {
|
|
|
|
|
order = append(order, curr.AbsID())
|
|
|
|
|
}
|
2023-05-10 23:39:42 +00:00
|
|
|
for _, ch := range curr.ChildrenArray {
|
|
|
|
|
queue = append(queue, ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 22:43:26 +00:00
|
|
|
return order, nil
|
2023-05-10 23:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
func IsLabelKeyID(key, label string) bool {
|
|
|
|
|
mk, err := d2parser.ParseMapKey(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if len(mk.Edges) > 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if mk.Key == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString() == label
|
|
|
|
|
}
|
2023-05-19 21:26:17 +00:00
|
|
|
|
|
|
|
|
func GetID(key string) string {
|
|
|
|
|
mk, err := d2parser.ParseMapKey(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
if len(mk.Edges) > 0 {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
if mk.Key == nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 23:08:23 +00:00
|
|
|
return d2format.Format(d2ast.RawString(mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString(), true))
|
2023-05-19 21:26:17 +00:00
|
|
|
}
|
2024-03-20 22:52:15 +00:00
|
|
|
|
|
|
|
|
func GetWriteableRefs(obj *d2graph.Object, writeableAST *d2ast.Map) (out []d2graph.Reference) {
|
|
|
|
|
for i, ref := range obj.References {
|
2024-12-12 21:52:21 +00:00
|
|
|
if ref.ScopeAST == writeableAST && ref.Key.Range.Path == writeableAST.Range.Path && len(ref.MapKey.Edges) == 0 {
|
2024-03-20 22:52:15 +00:00
|
|
|
out = append(out, obj.References[i])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GetWriteableEdgeRefs(edge *d2graph.Edge, writeableAST *d2ast.Map) (out []d2graph.EdgeReference) {
|
|
|
|
|
for i, ref := range edge.References {
|
|
|
|
|
if ref.ScopeAST == writeableAST {
|
|
|
|
|
out = append(out, edge.References[i])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|