1 package d2oracle
2
3 import (
4 "errors"
5 "fmt"
6 "strconv"
7 "strings"
8 "unicode"
9
10 "oss.terrastruct.com/util-go/xdefer"
11
12 "oss.terrastruct.com/util-go/xrand"
13
14 "oss.terrastruct.com/util-go/go2"
15
16 "oss.terrastruct.com/d2/d2ast"
17 "oss.terrastruct.com/d2/d2compiler"
18 "oss.terrastruct.com/d2/d2format"
19 "oss.terrastruct.com/d2/d2graph"
20 "oss.terrastruct.com/d2/d2ir"
21 "oss.terrastruct.com/d2/d2parser"
22 "oss.terrastruct.com/d2/d2target"
23 )
24
25 type OutsideScopeError struct{}
26
27 func (e OutsideScopeError) Error() string {
28 return "operation would modify AST outside of given scope"
29 }
30
31 func Create(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, newKey string, err error) {
32 defer xdefer.Errorf(&err, "failed to create %#v", key)
33
34 boardG := g
35 baseAST := g.AST
36
37 if len(boardPath) > 0 {
38
39 boardG = GetBoardGraph(g, boardPath)
40 if boardG == nil {
41 return nil, "", fmt.Errorf("board %v not found", boardPath)
42 }
43
44 baseAST = boardG.BaseAST
45 }
46
47 newKey, edge, err := generateUniqueKey(boardG, key, nil, nil)
48 if err != nil {
49 return nil, "", err
50 }
51
52 if edge {
53 err = _set(boardG, baseAST, key, nil, nil)
54 } else {
55 err = _set(boardG, baseAST, newKey, nil, nil)
56 }
57
58 if len(boardPath) > 0 {
59 replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
60 if !replaced {
61 return nil, "", fmt.Errorf("board %v AST not found", boardPath)
62 }
63 }
64
65 if err != nil {
66 return nil, "", err
67 }
68 g, err = recompile(g)
69 if err != nil {
70 return nil, "", err
71 }
72 return g, newKey, nil
73 }
74
75
76
77 func Set(g *d2graph.Graph, boardPath []string, key string, tag, value *string) (_ *d2graph.Graph, err error) {
78 var valueHelp string
79 if value == nil {
80 valueHelp = fmt.Sprintf("%#v", value)
81 } else {
82 valueHelp = fmt.Sprintf("%#v", *value)
83 }
84 if tag != nil {
85 defer xdefer.Errorf(&err, "failed to set %#v to %#v %#v", key, *tag, valueHelp)
86 } else {
87 defer xdefer.Errorf(&err, "failed to set %#v to %#v", key, valueHelp)
88 }
89
90 boardG := g
91 baseAST := g.AST
92
93 if len(boardPath) > 0 {
94
95 boardG = GetBoardGraph(g, boardPath)
96 if boardG == nil {
97 return nil, fmt.Errorf("board %v not found", boardPath)
98 }
99
100 baseAST = boardG.BaseAST
101 }
102
103 err = _set(boardG, baseAST, key, tag, value)
104 if err != nil {
105 return nil, err
106 }
107
108 if len(boardPath) > 0 {
109 replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
110 if !replaced {
111 return nil, fmt.Errorf("board %v AST not found", boardPath)
112 }
113 }
114
115 return recompile(g)
116 }
117
118 func ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey, dstKey *string) (_ *d2graph.Graph, err error) {
119 mk, err := d2parser.ParseMapKey(edgeKey)
120 if err != nil {
121 return nil, err
122 }
123
124 if len(mk.Edges) == 0 {
125 return nil, errors.New("edgeKey must be an edge")
126 }
127
128 if mk.EdgeIndex == nil {
129 return nil, errors.New("edgeKey must refer to an existing edge")
130 }
131
132 edgeTrimCommon(mk)
133
134 boardG := g
135 baseAST := g.AST
136
137 if len(boardPath) > 0 {
138
139 boardG = GetBoardGraph(g, boardPath)
140 if boardG == nil {
141 return nil, fmt.Errorf("board %v not found", boardPath)
142 }
143
144 baseAST = boardG.BaseAST
145 }
146
147 obj := boardG.Root
148 if mk.Key != nil {
149 var ok bool
150 obj, ok = boardG.Root.HasChild(d2graph.Key(mk.Key))
151 if !ok {
152 return nil, errors.New("edge not found")
153 }
154 }
155
156 edge, ok := obj.HasEdge(mk)
157 if !ok {
158 return nil, errors.New("edge not found")
159 }
160
161 if srcKey != nil {
162 if edge.Src.AbsID() == *srcKey {
163 srcKey = nil
164 }
165 }
166
167 if dstKey != nil {
168 if edge.Dst.AbsID() == *dstKey {
169 dstKey = nil
170 }
171 }
172
173 if srcKey == nil && dstKey == nil {
174 return g, nil
175 }
176
177 var src *d2graph.Object
178 var dst *d2graph.Object
179 if srcKey != nil {
180 srcmk, err := d2parser.ParseMapKey(*srcKey)
181 if err != nil {
182 return nil, err
183 }
184 src, ok = boardG.Root.HasChild(d2graph.Key(srcmk.Key))
185 if !ok {
186 return nil, errors.New("newSrc not found")
187 }
188 }
189 if dstKey != nil {
190 dstmk, err := d2parser.ParseMapKey(*dstKey)
191 if err != nil {
192 return nil, err
193 }
194 dst, ok = boardG.Root.HasChild(d2graph.Key(dstmk.Key))
195 if !ok {
196 return nil, errors.New("newDst not found")
197 }
198 }
199
200 refs := edge.References
201 if baseAST != g.AST {
202 refs = getWriteableEdgeRefs(edge, baseAST)
203 if len(refs) == 0 || refs[0].ScopeAST != baseAST {
204
205 return nil, OutsideScopeError{}
206 }
207 }
208 ref := refs[0]
209
210
211 if edge.Src != edge.Dst && (srcKey == nil || dstKey == nil) {
212 var refEdges []*d2ast.Edge
213 for _, ref := range refs {
214 refEdges = append(refEdges, ref.Edge)
215 }
216
217 if srcKey != nil {
218 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Src, true)
219 }
220 if dstKey != nil {
221 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Dst, false)
222 }
223 }
224
225 for i := range refs {
226 ref := refs[i]
227
228 if len(ref.MapKey.Edges) > 1 && ref.MapKey.EdgeIndex == nil {
229 splitChain := true
230
231 if ref.MapKeyEdgeIndex == 0 && dstKey == nil {
232 splitChain = false
233 }
234
235 if ref.MapKeyEdgeIndex == len(ref.MapKey.Edges)-1 && srcKey == nil {
236 splitChain = false
237 }
238 if splitChain {
239 tmp := *ref.MapKey
240 mk2 := &tmp
241 mk2.Edges = []*d2ast.Edge{ref.MapKey.Edges[ref.MapKeyEdgeIndex]}
242 ref.Scope.InsertAfter(ref.MapKey, mk2)
243
244 if ref.MapKeyEdgeIndex < len(ref.MapKey.Edges)-1 {
245 tmp := *ref.MapKey
246 mk2 := &tmp
247 mk2.Edges = ref.MapKey.Edges[ref.MapKeyEdgeIndex+1:]
248 ref.Scope.InsertAfter(ref.MapKey, mk2)
249 }
250 ref.MapKey.Edges = ref.MapKey.Edges[:ref.MapKeyEdgeIndex]
251 }
252 }
253
254 if src != nil {
255 srcmk, _ := d2parser.ParseMapKey(*srcKey)
256 ref.Edge.Src = srcmk.Key
257 newPath, err := pathFromScopeObj(boardG, srcmk, ref.ScopeObj)
258 if err != nil {
259 return nil, err
260 }
261 ref.Edge.Src.Path = newPath
262 }
263 if dst != nil {
264 dstmk, _ := d2parser.ParseMapKey(*dstKey)
265 ref.Edge.Dst = dstmk.Key
266 newPath, err := pathFromScopeObj(boardG, dstmk, ref.ScopeObj)
267 if err != nil {
268 return nil, err
269 }
270 ref.Edge.Dst.Path = newPath
271 }
272 }
273
274 return recompile(g)
275 }
276
277 func pathFromScopeKey(g *d2graph.Graph, key *d2ast.Key, scopeak []string) ([]*d2ast.StringBox, error) {
278 ak2 := d2graph.Key(key.Key)
279
280 commonPath := getCommonPath(scopeak, ak2)
281
282 var newPath []*d2ast.StringBox
283
284 for i := len(commonPath); i < len(scopeak); i++ {
285 newPath = append(newPath, d2ast.MakeValueBox(d2ast.RawString("_", true)).StringBox())
286 }
287
288 newPath = append(newPath, key.Key.Path[len(commonPath):]...)
289
290 return newPath, nil
291 }
292
293 func pathFromScopeObj(g *d2graph.Graph, key *d2ast.Key, fromScope *d2graph.Object) ([]*d2ast.StringBox, error) {
294
295 var scopeak []string
296 if fromScope != g.Root {
297 scopek, err := d2parser.ParseKey(fromScope.AbsID())
298 if err != nil {
299 return nil, err
300 }
301 scopeak = d2graph.Key(scopek)
302 }
303 return pathFromScopeKey(g, key, scopeak)
304 }
305
306 func recompile(g *d2graph.Graph) (*d2graph.Graph, error) {
307 s := d2format.Format(g.AST)
308 g2, _, err := d2compiler.Compile(g.AST.Range.Path, strings.NewReader(s), &d2compiler.CompileOptions{
309 FS: g.FS,
310 })
311 if err != nil {
312 return nil, fmt.Errorf("failed to recompile:\n%s\n%w", s, err)
313 }
314 return g2, nil
315 }
316
317
318 func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) error {
319 if tag != nil {
320 if hasSpace(*tag) {
321 return fmt.Errorf("spaces are not allowed in blockstring tags")
322 }
323 }
324
325 mk, err := d2parser.ParseMapKey(key)
326 if err != nil {
327 return err
328 }
329
330 if len(mk.Edges) > 1 {
331 return errors.New("can only set one edge at a time")
332 }
333
334 if value != nil {
335 mk.Value = d2ast.MakeValueBox(d2ast.RawString(*value, false))
336 } else {
337 mk.Value = d2ast.ValueBox{}
338 }
339 if tag != nil && value != nil {
340 mk.Value = d2ast.MakeValueBox(&d2ast.BlockString{
341 Tag: *tag,
342 Value: *value,
343 })
344 }
345
346 scope := baseAST
347 edgeTrimCommon(mk)
348 obj := g.Root
349 toSkip := 1
350
351 reserved := false
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 reservedKey := ""
370 reservedTargetKey := ""
371 if mk.Key != nil {
372 found := true
373 for _, idel := range d2graph.Key(mk.Key) {
374 _, ok := d2graph.ReservedKeywords[idel]
375 if ok {
376 reserved = true
377 break
378 }
379 o, ok := obj.HasChild([]string{idel})
380 if !ok {
381 found = false
382 break
383 }
384 obj = o
385
386 var maybeNewScope *d2ast.Map
387 if baseAST != g.AST {
388 writeableRefs := getWriteableRefs(obj, baseAST)
389 for _, ref := range writeableRefs {
390 if ref.MapKey != nil && ref.MapKey.Value.Map != nil {
391 maybeNewScope = ref.MapKey.Value.Map
392 }
393 }
394 } else {
395 maybeNewScope = obj.Map
396 }
397
398 if maybeNewScope == nil {
399
400 toSkip++
401 continue
402 }
403
404 scope = maybeNewScope
405 mk.Key.Path = mk.Key.Path[toSkip:]
406 toSkip = 1
407 if len(mk.Key.Path) == 0 {
408 mk.Key = nil
409 }
410 }
411
412 var objK *d2ast.Key
413 if baseAST != g.AST {
414 writeableRefs := getWriteableRefs(obj, baseAST)
415 if len(writeableRefs) > 0 {
416 objK = writeableRefs[0].MapKey
417 }
418 if objK == nil {
419 appendMapKey(scope, mk)
420 return nil
421 }
422 }
423 var m *d2ast.Map
424 if objK != nil {
425 m = objK.Value.Map
426 } else {
427 m = obj.Map
428 }
429
430 if obj.Label.MapKey != nil && m == nil && (!found || reserved || len(mk.Edges) > 0) {
431 m2 := &d2ast.Map{
432 Range: d2ast.MakeRange(",1:0:0-1:0:0"),
433 }
434 if objK == nil {
435 obj.Map = m2
436 objK = obj.Label.MapKey
437 } else {
438 objK.Value.Map = m2
439 }
440 objK.Primary = objK.Value.ScalarBox()
441 objK.Value = d2ast.MakeValueBox(m2)
442 scope = m2
443
444 mk.Key.Path = mk.Key.Path[toSkip-1:]
445 toSkip = 1
446 if len(mk.Key.Path) == 0 {
447 mk.Key = nil
448 }
449 }
450
451 if !found {
452 appendMapKey(scope, mk)
453 return nil
454 }
455 }
456 ir, err := d2ir.Compile(g.AST, &d2ir.CompileOptions{
457 FS: g.FS,
458 })
459 if err != nil {
460 return err
461 }
462 attrs := obj.Attributes
463 var edge *d2graph.Edge
464 if len(mk.Edges) == 1 {
465 if mk.EdgeIndex == nil {
466 appendMapKey(scope, mk)
467 return nil
468 }
469 var ok bool
470 edge, ok = obj.HasEdge(mk)
471 if !ok {
472 return errors.New("edge not found")
473 }
474 refs := edge.References
475 if baseAST != g.AST {
476 refs = getWriteableEdgeRefs(edge, baseAST)
477 }
478 onlyInChain := true
479 for _, ref := range refs {
480
481
482
483
484 if len(ref.MapKey.Edges) == 1 {
485 if ref.MapKey.EdgeIndex == nil || ref.MapKey.Value.Map != nil {
486 onlyInChain = false
487 }
488 }
489
490 tmp1 := *ref.MapKey
491 tmp2 := *mk
492 noVal1 := &tmp1
493 noVal2 := &tmp2
494 noVal1.Value = d2ast.ValueBox{}
495 noVal2.Value = d2ast.ValueBox{}
496 if noVal1.D2OracleEquals(noVal2) {
497 ref.MapKey.Value = mk.Value
498 return nil
499 }
500 }
501 if onlyInChain {
502 appendMapKey(scope, mk)
503 return nil
504 }
505 attrs = edge.Attributes
506
507 if mk.EdgeKey != nil {
508 if _, ok := d2graph.ReservedKeywords[mk.EdgeKey.Path[0].Unbox().ScalarString()]; !ok {
509 return errors.New("edge key must be reserved")
510 }
511 reserved = true
512
513 toSkip = 1
514 mk = &d2ast.Key{
515 Key: cloneKey(mk.EdgeKey),
516 Value: mk.Value,
517 }
518
519 foundMap := false
520 for _, ref := range refs {
521
522 if ref.MapKey.Value.Map != nil {
523 foundMap = true
524 scope = ref.MapKey.Value.Map
525 for _, n := range scope.Nodes {
526 if n.MapKey.Value.Map == nil {
527 continue
528 }
529 if n.MapKey.Key == nil || len(n.MapKey.Key.Path) != 1 {
530 continue
531 }
532 if n.MapKey.Key.Path[0].Unbox().ScalarString() == mk.Key.Path[toSkip-1].Unbox().ScalarString() {
533 scope = n.MapKey.Value.Map
534 if mk.Key.Path[0].Unbox().ScalarString() == "source-arrowhead" && edge.SrcArrowhead != nil {
535 attrs = *edge.SrcArrowhead
536 }
537 if mk.Key.Path[0].Unbox().ScalarString() == "target-arrowhead" && edge.DstArrowhead != nil {
538 attrs = *edge.DstArrowhead
539 }
540 reservedKey = mk.Key.Path[0].Unbox().ScalarString()
541 mk.Key.Path = mk.Key.Path[1:]
542 reservedTargetKey = mk.Key.Path[0].Unbox().ScalarString()
543 break
544 }
545 }
546 break
547 }
548 }
549 if !foundMap && attrs.Label.MapKey != nil {
550 attrs.Label.MapKey.Primary = attrs.Label.MapKey.Value.ScalarBox()
551 edgeMap := &d2ast.Map{
552 Range: d2ast.MakeRange(",1:0:0-1:0:0"),
553 }
554 attrs.Label.MapKey.Value = d2ast.MakeValueBox(edgeMap)
555 scope = edgeMap
556 }
557 }
558 }
559
560 if reserved {
561 inlined := func(s *d2graph.Scalar) bool {
562 if s != nil && s.MapKey != nil {
563
564 if s.MapKey.Range.Path != baseAST.Range.Path {
565 return false
566 }
567 }
568 return s != nil && s.MapKey != nil && !ir.InClass(s.MapKey)
569 }
570 reservedIndex := toSkip - 1
571 if mk.Key != nil && len(mk.Key.Path) > 0 {
572 if reservedKey == "" {
573 reservedKey = mk.Key.Path[reservedIndex].Unbox().ScalarString()
574 }
575 switch reservedKey {
576 case "shape":
577 if inlined(&attrs.Shape) {
578 attrs.Shape.MapKey.SetScalar(mk.Value.ScalarBox())
579 return nil
580 }
581 case "link":
582 if inlined(attrs.Link) {
583 attrs.Link.MapKey.SetScalar(mk.Value.ScalarBox())
584 return nil
585 }
586 case "tooltip":
587 if inlined(attrs.Tooltip) {
588 attrs.Tooltip.MapKey.SetScalar(mk.Value.ScalarBox())
589 return nil
590 }
591 case "width":
592 if inlined(attrs.WidthAttr) {
593 attrs.WidthAttr.MapKey.SetScalar(mk.Value.ScalarBox())
594 return nil
595 }
596 case "height":
597 if inlined(attrs.HeightAttr) {
598 attrs.HeightAttr.MapKey.SetScalar(mk.Value.ScalarBox())
599 return nil
600 }
601 case "top":
602 if inlined(attrs.Top) {
603 attrs.Top.MapKey.SetScalar(mk.Value.ScalarBox())
604 return nil
605 }
606 case "left":
607 if inlined(attrs.Left) {
608 attrs.Left.MapKey.SetScalar(mk.Value.ScalarBox())
609 return nil
610 }
611 case "grid-rows":
612 if inlined(attrs.GridRows) {
613 attrs.GridRows.MapKey.SetScalar(mk.Value.ScalarBox())
614 return nil
615 }
616 case "grid-columns":
617 if inlined(attrs.GridColumns) {
618 attrs.GridColumns.MapKey.SetScalar(mk.Value.ScalarBox())
619 return nil
620 }
621 case "grid-gap":
622 if inlined(attrs.GridGap) {
623 attrs.GridGap.MapKey.SetScalar(mk.Value.ScalarBox())
624 return nil
625 }
626 case "vertical-gap":
627 if inlined(attrs.VerticalGap) {
628 attrs.VerticalGap.MapKey.SetScalar(mk.Value.ScalarBox())
629 return nil
630 }
631 case "horizontal-gap":
632 if inlined(attrs.HorizontalGap) {
633 attrs.HorizontalGap.MapKey.SetScalar(mk.Value.ScalarBox())
634 return nil
635 }
636 case "source-arrowhead", "target-arrowhead":
637 var arrowhead *d2graph.Attributes
638 if reservedKey == "source-arrowhead" {
639 arrowhead = edge.SrcArrowhead
640 } else {
641 arrowhead = edge.DstArrowhead
642 }
643 if arrowhead != nil {
644 if reservedTargetKey == "" {
645 if len(mk.Key.Path[reservedIndex:]) != 2 {
646 return errors.New("malformed style setting, expected 2 part path")
647 }
648 reservedTargetKey = mk.Key.Path[reservedIndex+1].Unbox().ScalarString()
649 }
650 switch reservedTargetKey {
651 case "shape":
652 if inlined(&arrowhead.Shape) {
653 arrowhead.Shape.MapKey.SetScalar(mk.Value.ScalarBox())
654 return nil
655 }
656 case "label":
657 if inlined(&arrowhead.Label) {
658 arrowhead.Label.MapKey.SetScalar(mk.Value.ScalarBox())
659 return nil
660 }
661 }
662 }
663 case "style":
664 if reservedTargetKey == "" {
665 if len(mk.Key.Path[reservedIndex:]) != 2 {
666 return errors.New("malformed style setting, expected 2 part path")
667 }
668 reservedTargetKey = mk.Key.Path[reservedIndex+1].Unbox().ScalarString()
669 }
670 switch reservedTargetKey {
671 case "opacity":
672 if inlined(attrs.Style.Opacity) {
673 attrs.Style.Opacity.MapKey.SetScalar(mk.Value.ScalarBox())
674 return nil
675 }
676 case "stroke":
677 if inlined(attrs.Style.Stroke) {
678 attrs.Style.Stroke.MapKey.SetScalar(mk.Value.ScalarBox())
679 return nil
680 }
681 case "fill":
682 if inlined(attrs.Style.Fill) {
683 attrs.Style.Fill.MapKey.SetScalar(mk.Value.ScalarBox())
684 return nil
685 }
686 case "stroke-width":
687 if inlined(attrs.Style.StrokeWidth) {
688 attrs.Style.StrokeWidth.MapKey.SetScalar(mk.Value.ScalarBox())
689 return nil
690 }
691 case "stroke-dash":
692 if inlined(attrs.Style.StrokeDash) {
693 attrs.Style.StrokeDash.MapKey.SetScalar(mk.Value.ScalarBox())
694 return nil
695 }
696 case "border-radius":
697 if inlined(attrs.Style.BorderRadius) {
698 attrs.Style.BorderRadius.MapKey.SetScalar(mk.Value.ScalarBox())
699 return nil
700 }
701 case "shadow":
702 if inlined(attrs.Style.Shadow) {
703 attrs.Style.Shadow.MapKey.SetScalar(mk.Value.ScalarBox())
704 return nil
705 }
706 case "3d":
707 if inlined(attrs.Style.ThreeDee) {
708 attrs.Style.ThreeDee.MapKey.SetScalar(mk.Value.ScalarBox())
709 return nil
710 }
711 case "multiple":
712 if inlined(attrs.Style.Multiple) {
713 attrs.Style.Multiple.MapKey.SetScalar(mk.Value.ScalarBox())
714 return nil
715 }
716 case "double-border":
717 if inlined(attrs.Style.DoubleBorder) {
718 attrs.Style.DoubleBorder.MapKey.SetScalar(mk.Value.ScalarBox())
719 return nil
720 }
721 case "font":
722 if inlined(attrs.Style.Font) {
723 attrs.Style.Font.MapKey.SetScalar(mk.Value.ScalarBox())
724 return nil
725 }
726 case "font-size":
727 if inlined(attrs.Style.FontSize) {
728 attrs.Style.FontSize.MapKey.SetScalar(mk.Value.ScalarBox())
729 return nil
730 }
731 case "font-color":
732 if inlined(attrs.Style.FontColor) {
733 attrs.Style.FontColor.MapKey.SetScalar(mk.Value.ScalarBox())
734 return nil
735 }
736 case "animated":
737 if inlined(attrs.Style.Animated) {
738 attrs.Style.Animated.MapKey.SetScalar(mk.Value.ScalarBox())
739 return nil
740 }
741 case "bold":
742 if inlined(attrs.Style.Bold) {
743 attrs.Style.Bold.MapKey.SetScalar(mk.Value.ScalarBox())
744 return nil
745 }
746 case "italic":
747 if inlined(attrs.Style.Italic) {
748 attrs.Style.Italic.MapKey.SetScalar(mk.Value.ScalarBox())
749 return nil
750 }
751 case "underline":
752 if inlined(attrs.Style.Underline) {
753 attrs.Style.Underline.MapKey.SetScalar(mk.Value.ScalarBox())
754 return nil
755 }
756 case "fill-pattern":
757 if inlined(attrs.Style.FillPattern) {
758 attrs.Style.FillPattern.MapKey.SetScalar(mk.Value.ScalarBox())
759 return nil
760 }
761 }
762 case "label":
763 if inlined(&attrs.Label) {
764 attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
765 return nil
766 }
767 }
768 }
769 } else if attrs.Label.MapKey != nil {
770 attrs.Label.MapKey.SetScalar(mk.Value.ScalarBox())
771 return nil
772 }
773 appendMapKey(scope, mk)
774 return nil
775 }
776
777 func appendUniqueMapKey(m *d2ast.Map, mk *d2ast.Key) {
778 for _, n := range m.Nodes {
779 if n.MapKey != nil && n.MapKey.D2OracleEquals(mk) {
780 return
781 }
782 }
783 appendMapKey(m, mk)
784 }
785
786 func appendMapKey(m *d2ast.Map, mk *d2ast.Key) {
787 m.Nodes = append(m.Nodes, d2ast.MapNodeBox{
788 MapKey: mk,
789 })
790 if len(m.Nodes) == 1 &&
791 mk.Key != nil &&
792 len(mk.Key.Path) > 0 {
793 _, ok := d2graph.ReservedKeywords[mk.Key.Path[0].Unbox().ScalarString()]
794 if ok {
795
796
797
798
799 return
800 }
801 }
802 if !m.IsFileMap() && m.Range.OneLine() {
803
804
805
806 m.Range.End.Line++
807 }
808 }
809
810 func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, err error) {
811 defer xdefer.Errorf(&err, "failed to delete %#v", key)
812
813 mk, err := d2parser.ParseMapKey(key)
814 if err != nil {
815 return nil, err
816 }
817
818 if len(mk.Edges) > 1 {
819 return nil, errors.New("can only delete one edge at a time")
820 }
821
822 if len(mk.Edges) == 1 {
823 edgeTrimCommon(mk)
824 }
825
826 boardG := g
827 baseAST := g.AST
828
829 if len(boardPath) > 0 {
830
831 boardG = GetBoardGraph(g, boardPath)
832 if boardG == nil {
833 return nil, fmt.Errorf("board %v not found", boardPath)
834 }
835
836 baseAST = boardG.BaseAST
837 }
838
839 g2, err := deleteReserved(g, mk)
840 if err != nil {
841 return nil, err
842 }
843 if g != g2 {
844 return g2, nil
845 }
846
847 if len(mk.Edges) == 1 {
848 obj := boardG.Root
849 if mk.Key != nil {
850 var ok bool
851 obj, ok = boardG.Root.HasChild(d2graph.Key(mk.Key))
852 if !ok {
853 return g, nil
854 }
855 }
856 e, ok := obj.HasEdge(mk)
857 if !ok {
858 return g, nil
859 }
860
861 refs := e.References
862 if len(boardPath) > 0 {
863 refs := getWriteableEdgeRefs(e, baseAST)
864 if len(refs) != len(e.References) {
865 mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
866 }
867 }
868
869 if _, ok := mk.Value.Unbox().(*d2ast.Null); !ok {
870 ref := refs[0]
871 var refEdges []*d2ast.Edge
872 for _, ref := range refs {
873 refEdges = append(refEdges, ref.Edge)
874 }
875 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Src, true)
876 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, ref.MapKey.Edges[ref.MapKeyEdgeIndex].Dst, false)
877
878 for i := len(e.References) - 1; i >= 0; i-- {
879 ref := e.References[i]
880 deleteEdge(g, ref.Scope, ref.MapKey, ref.MapKeyEdgeIndex)
881 }
882
883 edges, ok := obj.FindEdges(mk)
884 if ok {
885 for _, e2 := range edges {
886 if e2.Index <= e.Index {
887 continue
888 }
889 for i := len(e2.References) - 1; i >= 0; i-- {
890 ref := e2.References[i]
891 if ref.MapKey.EdgeIndex != nil {
892 *ref.MapKey.EdgeIndex.Int--
893 }
894 }
895 }
896 }
897 } else {
898
899 appendMapKey(baseAST, mk)
900 }
901 if len(boardPath) > 0 {
902 replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
903 if !replaced {
904 return nil, fmt.Errorf("board %v AST not found", boardPath)
905 }
906 return recompile(g)
907 }
908 return recompile(boardG)
909 }
910
911 prevG, _ := recompile(boardG)
912
913 boardG, err = renameConflictsToParent(boardG, mk.Key)
914 if err != nil {
915 return nil, err
916 }
917
918 obj, ok := boardG.Root.HasChild(d2graph.Key(mk.Key))
919 if !ok {
920 return g, nil
921 }
922
923 if len(boardPath) > 0 {
924 writeableRefs := getWriteableRefs(obj, baseAST)
925 if len(writeableRefs) != len(obj.References) {
926 mk.Value = d2ast.MakeValueBox(&d2ast.Null{})
927 }
928 }
929
930 if _, ok := mk.Value.Unbox().(*d2ast.Null); !ok {
931 boardG, err = deleteObject(boardG, baseAST, mk.Key, obj)
932 if err != nil {
933 return nil, err
934 }
935
936 if err := updateNear(prevG, boardG, &key, nil, false); err != nil {
937 return nil, err
938 }
939 } else {
940 appendMapKey(baseAST, mk)
941 }
942
943 if len(boardPath) > 0 {
944 replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
945 if !replaced {
946 return nil, fmt.Errorf("board %v AST not found", boardPath)
947 }
948 return recompile(g)
949 }
950
951 return recompile(boardG)
952 }
953
954 func bumpChildrenUnderscores(m *d2ast.Map) {
955 for _, n := range m.Nodes {
956 if n.MapKey == nil {
957 continue
958 }
959 if n.MapKey.Key != nil {
960 if n.MapKey.Key.Path[0].Unbox().ScalarString() == "_" {
961 n.MapKey.Key.Path = n.MapKey.Key.Path[1:]
962 }
963 }
964 for _, e := range n.MapKey.Edges {
965 if e.Src.Path[0].Unbox().ScalarString() == "_" {
966 e.Src.Path = e.Src.Path[1:]
967 }
968 if e.Dst.Path[0].Unbox().ScalarString() == "_" {
969 e.Dst.Path = e.Dst.Path[1:]
970 }
971 }
972 if n.MapKey.Value.Map != nil {
973 bumpChildrenUnderscores(n.MapKey.Value.Map)
974 }
975 }
976 }
977
978 func hoistRefChildren(g *d2graph.Graph, key *d2ast.KeyPath, ref d2graph.Reference) {
979 if ref.MapKey.Value.Map == nil {
980 return
981 }
982
983 bumpChildrenUnderscores(ref.MapKey.Value.Map)
984 scopeKey, scope := findNearestParentScope(g, key)
985 for i := 0; i < len(ref.MapKey.Value.Map.Nodes); i++ {
986 n := ref.MapKey.Value.Map.Nodes[i]
987 if n.MapKey == nil {
988 continue
989 }
990 if n.MapKey.Key != nil {
991 _, ok := d2graph.ReservedKeywords[n.MapKey.Key.Path[0].Unbox().ScalarString()]
992 if ok {
993 continue
994 }
995 }
996 scopeKey := cloneKey(scopeKey)
997 scopeKey.Path = scopeKey.Path[:len(scopeKey.Path)-1]
998 if n.MapKey.Key != nil {
999 scopeKey.Path = append(scopeKey.Path, n.MapKey.Key.Path...)
1000 }
1001 if len(scopeKey.Path) > 0 {
1002 n.MapKey.Key = scopeKey
1003 }
1004 scope.InsertBefore(ref.MapKey, n.Unbox())
1005 }
1006 }
1007
1008
1009 func renameConflictsToParent(g *d2graph.Graph, key *d2ast.KeyPath) (*d2graph.Graph, error) {
1010 obj, ok := g.Root.HasChild(d2graph.Key(key))
1011 if !ok {
1012 return g, nil
1013 }
1014 if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
1015 return g, nil
1016 }
1017
1018
1019 ignored := obj
1020 for _, ch := range obj.ChildrenArray {
1021 if ch.ID == obj.ID {
1022 ignored = nil
1023 break
1024 }
1025 }
1026
1027
1028 var newIDs []string
1029
1030 dedupedRenames := map[string]struct{}{}
1031 for _, ref := range obj.References {
1032 var absKeys []*d2ast.KeyPath
1033
1034 if len(ref.Key.Path)-1 == ref.KeyPathIndex {
1035 if ref.MapKey.Value.Map == nil {
1036 continue
1037 }
1038 var mapKeys []*d2ast.KeyPath
1039 for _, n := range ref.MapKey.Value.Map.Nodes {
1040 if n.MapKey == nil {
1041 continue
1042 }
1043 if n.MapKey.Key != nil {
1044 _, ok := d2graph.ReservedKeywords[n.MapKey.Key.Path[0].Unbox().ScalarString()]
1045 if ok {
1046 continue
1047 }
1048 mapKeys = append(mapKeys, n.MapKey.Key)
1049 }
1050 for _, e := range n.MapKey.Edges {
1051 mapKeys = append(mapKeys, e.Src)
1052 mapKeys = append(mapKeys, e.Dst)
1053 }
1054 }
1055 for _, k := range mapKeys {
1056 absKey, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
1057 if err != nil {
1058 absKey = &d2ast.KeyPath{}
1059 }
1060 absKey.Path = append(absKey.Path, ref.Key.Path...)
1061 absKey.Path = append(absKey.Path, k.Path[0])
1062 absKeys = append(absKeys, absKey)
1063 }
1064 } else if _, ok := d2graph.ReservedKeywords[ref.Key.Path[len(ref.Key.Path)-1].Unbox().ScalarString()]; !ok {
1065 absKey, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
1066 if err != nil {
1067 absKey = &d2ast.KeyPath{}
1068 }
1069 absKey.Path = append(absKey.Path, ref.Key.Path[:ref.KeyPathIndex+2]...)
1070 absKeys = append(absKeys, absKey)
1071 }
1072
1073 renames := make(map[string]string)
1074 for _, absKey := range absKeys {
1075 ida := d2graph.Key(absKey)
1076 absKeyStr := strings.Join(ida, ".")
1077 if _, ok := dedupedRenames[absKeyStr]; ok {
1078 continue
1079 }
1080
1081 dedupedRenames[absKeyStr] = struct{}{}
1082
1083 if ida[len(ida)-1] == ida[len(ida)-2] {
1084 continue
1085 }
1086
1087 hoistedAbsKey, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
1088 if err != nil {
1089 hoistedAbsKey = &d2ast.KeyPath{}
1090 }
1091 hoistedAbsKey.Path = append(hoistedAbsKey.Path, ref.Key.Path[:ref.KeyPathIndex]...)
1092 hoistedAbsKey.Path = append(hoistedAbsKey.Path, absKey.Path[len(absKey.Path)-1])
1093
1094
1095 var siblingHoistedIDs []string
1096 for _, otherAbsKey := range absKeys {
1097 if absKey == otherAbsKey {
1098 continue
1099 }
1100 ida := d2graph.Key(otherAbsKey)
1101 absKeyStr := strings.Join(ida, ".")
1102 if _, ok := dedupedRenames[absKeyStr]; ok {
1103 continue
1104 }
1105 hoistedAbsKey, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
1106 if err != nil {
1107 hoistedAbsKey = &d2ast.KeyPath{}
1108 }
1109 hoistedAbsKey.Path = append(hoistedAbsKey.Path, ref.Key.Path[:ref.KeyPathIndex]...)
1110 hoistedAbsKey.Path = append(hoistedAbsKey.Path, otherAbsKey.Path[len(otherAbsKey.Path)-1])
1111 siblingHoistedIDs = append(siblingHoistedIDs, strings.Join(d2graph.Key(hoistedAbsKey), "."))
1112 }
1113
1114 uniqueKeyStr, _, err := generateUniqueKey(g, strings.Join(d2graph.Key(hoistedAbsKey), "."), ignored, append(newIDs, siblingHoistedIDs...))
1115 if err != nil {
1116 return nil, err
1117 }
1118 newIDs = append(newIDs, uniqueKeyStr)
1119 uniqueKey, err := d2parser.ParseKey(uniqueKeyStr)
1120 if err != nil {
1121 return nil, err
1122 }
1123
1124 renamedKey := cloneKey(absKey)
1125 renamedKey.Path[len(renamedKey.Path)-1].Unbox().SetString(uniqueKey.Path[len(uniqueKey.Path)-1].Unbox().ScalarString())
1126
1127 renamedKeyStr := strings.Join(d2graph.Key(renamedKey), ".")
1128 if absKeyStr != renamedKeyStr {
1129 renames[absKeyStr] = renamedKeyStr
1130 }
1131 dedupedRenames[renamedKeyStr] = struct{}{}
1132 }
1133
1134
1135
1136
1137
1138
1139 var renameOrder []string
1140 for k, v := range renames {
1141
1142 if _, ok := renames[v]; ok {
1143 renameOrder = append(renameOrder, k)
1144 } else {
1145 renameOrder = append([]string{k}, renameOrder...)
1146 }
1147 }
1148 for _, k := range renameOrder {
1149 var err error
1150
1151 g, err = move(g, nil, k, renames[k], false)
1152 if err != nil {
1153 return nil, err
1154 }
1155 }
1156 }
1157 return g, nil
1158 }
1159
1160 func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
1161 targetKey := mk.Key
1162 if len(mk.Edges) == 1 {
1163 if mk.EdgeKey == nil {
1164 return g, nil
1165 }
1166 targetKey = mk.EdgeKey
1167 }
1168 _, ok := d2graph.ReservedKeywords[targetKey.Path[len(targetKey.Path)-1].Unbox().ScalarString()]
1169 if !ok {
1170 return g, nil
1171 }
1172
1173 var e *d2graph.Edge
1174 obj := g.Root
1175 if len(mk.Edges) == 1 {
1176 if mk.Key != nil {
1177 var ok bool
1178 obj, ok = g.Root.HasChild(d2graph.Key(mk.Key))
1179 if !ok {
1180 return g, nil
1181 }
1182 }
1183 e, ok = obj.HasEdge(mk)
1184 if !ok {
1185 return g, nil
1186 }
1187
1188 if err := deleteEdgeField(g, e, targetKey.Path[len(targetKey.Path)-1].Unbox().ScalarString()); err != nil {
1189 return nil, err
1190 }
1191 return recompile(g)
1192 }
1193
1194 isStyleKey := false
1195 for _, id := range d2graph.Key(targetKey) {
1196 _, ok := d2graph.ReservedKeywords[id]
1197 if ok {
1198 if id == "style" {
1199 isStyleKey = true
1200 continue
1201 }
1202 if isStyleKey {
1203 err := deleteObjField(g, obj, id)
1204 if err != nil {
1205 return nil, err
1206 }
1207 }
1208
1209 if id == "near" ||
1210 id == "tooltip" ||
1211 id == "icon" ||
1212 id == "width" ||
1213 id == "height" ||
1214 id == "left" ||
1215 id == "top" ||
1216 id == "link" {
1217 err := deleteObjField(g, obj, id)
1218 if err != nil {
1219 return nil, err
1220 }
1221 }
1222 break
1223 }
1224 obj, ok = obj.HasChild([]string{id})
1225 if !ok {
1226 return nil, fmt.Errorf("object not found")
1227 }
1228 }
1229
1230 return recompile(g)
1231 }
1232
1233 func deleteMapField(m *d2ast.Map, field string) {
1234 for i := 0; i < len(m.Nodes); i++ {
1235 n := m.Nodes[i]
1236 if n.MapKey != nil && n.MapKey.Key != nil {
1237 if n.MapKey.Key.Path[0].Unbox().ScalarString() == field {
1238 deleteFromMap(m, n.MapKey)
1239 } else if n.MapKey.Key.Path[0].Unbox().ScalarString() == "style" ||
1240 n.MapKey.Key.Path[0].Unbox().ScalarString() == "source-arrowhead" ||
1241 n.MapKey.Key.Path[0].Unbox().ScalarString() == "target-arrowhead" {
1242 if n.MapKey.Value.Map != nil {
1243 deleteMapField(n.MapKey.Value.Map, field)
1244 if len(n.MapKey.Value.Map.Nodes) == 0 {
1245 deleteFromMap(m, n.MapKey)
1246 }
1247 } else if len(n.MapKey.Key.Path) == 2 && n.MapKey.Key.Path[1].Unbox().ScalarString() == field {
1248 deleteFromMap(m, n.MapKey)
1249 }
1250 }
1251 }
1252 }
1253 }
1254
1255 func deleteEdgeField(g *d2graph.Graph, e *d2graph.Edge, field string) error {
1256 for _, ref := range e.References {
1257
1258 if len(ref.MapKey.Edges) > 1 {
1259 continue
1260 }
1261 if ref.MapKey.Value.Map != nil {
1262 deleteMapField(ref.MapKey.Value.Map, field)
1263 } else if ref.MapKey.EdgeKey != nil && ref.MapKey.EdgeKey.Path[len(ref.MapKey.EdgeKey.Path)-1].Unbox().ScalarString() == field {
1264
1265 deleteFromMap(ref.Scope, ref.MapKey)
1266 }
1267 }
1268 return nil
1269 }
1270
1271 func deleteObjField(g *d2graph.Graph, obj *d2graph.Object, field string) error {
1272 objK, err := d2parser.ParseKey(obj.AbsID())
1273 if err != nil {
1274 return err
1275 }
1276 objGK := d2graph.Key(objK)
1277 for _, ref := range obj.References {
1278 if ref.InEdge() {
1279 continue
1280 }
1281 if ref.MapKey.Value.Map != nil {
1282 deleteMapField(ref.MapKey.Value.Map, field)
1283 } else if (len(ref.Key.Path) >= 2 &&
1284 ref.Key.Path[len(ref.Key.Path)-1].Unbox().ScalarString() == field &&
1285 ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == obj.ID) ||
1286 (len(ref.Key.Path) >= 3 &&
1287 ref.Key.Path[len(ref.Key.Path)-1].Unbox().ScalarString() == field &&
1288 ref.Key.Path[len(ref.Key.Path)-2].Unbox().ScalarString() == "style" &&
1289 ref.Key.Path[len(ref.Key.Path)-3].Unbox().ScalarString() == obj.ID) {
1290 tmpNodes := make([]d2ast.MapNodeBox, len(ref.Scope.Nodes))
1291 copy(tmpNodes, ref.Scope.Nodes)
1292
1293 deleteFromMap(ref.Scope, ref.MapKey)
1294 g2, err := recompile(g)
1295 if err != nil {
1296 return err
1297 }
1298 if _, ok := g2.Root.HasChild(objGK); !ok {
1299
1300 ref.Scope.Nodes = tmpNodes
1301 ref.MapKey.Value = d2ast.ValueBox{}
1302 ref.Key.Path = ref.Key.Path[:ref.KeyPathIndex+1]
1303 }
1304
1305 }
1306 }
1307 return nil
1308 }
1309
1310 func deleteObject(g *d2graph.Graph, baseAST *d2ast.Map, key *d2ast.KeyPath, obj *d2graph.Object) (*d2graph.Graph, error) {
1311 var refEdges []*d2ast.Edge
1312 for _, ref := range obj.References {
1313 if ref.InEdge() {
1314 refEdges = append(refEdges, ref.MapKey.Edges[ref.MapKeyEdgeIndex])
1315 }
1316 }
1317
1318 for i := len(obj.References) - 1; i >= 0; i-- {
1319 ref := obj.References[i]
1320
1321 if len(ref.MapKey.Edges) == 0 {
1322 isSuffix := ref.KeyPathIndex == len(ref.Key.Path)-1
1323 if isSuffix && ref.MapKey != nil {
1324 ref.MapKey.Primary = d2ast.ScalarBox{}
1325 }
1326 ref.Key.Path = append(ref.Key.Path[:ref.KeyPathIndex], ref.Key.Path[ref.KeyPathIndex+1:]...)
1327 withoutSpecial := go2.Filter(ref.Key.Path, func(x *d2ast.StringBox) bool {
1328 _, isReserved := d2graph.ReservedKeywords[x.Unbox().ScalarString()]
1329 isSpecial := isReserved || x.Unbox().ScalarString() == "_"
1330 return !isSpecial
1331 })
1332 if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
1333 deleteFromMap(ref.Scope, ref.MapKey)
1334 } else if len(withoutSpecial) == 0 {
1335 hoistRefChildren(g, key, ref)
1336 deleteFromMap(ref.Scope, ref.MapKey)
1337 } else if ref.MapKey.Value.Unbox() == nil &&
1338 obj.Parent != nil &&
1339 isSuffix &&
1340 len(obj.Parent.References) > 1 {
1341
1342 deleteFromMap(ref.Scope, ref.MapKey)
1343 } else if ref.MapKey.Value.Map != nil && isSuffix {
1344 for i := 0; i < len(ref.MapKey.Value.Map.Nodes); i++ {
1345 n := ref.MapKey.Value.Map.Nodes[i]
1346 if n.MapKey != nil && n.MapKey.Key != nil {
1347 _, ok := d2graph.ReservedKeywords[n.MapKey.Key.Path[0].Unbox().ScalarString()]
1348 if ok {
1349 deleteFromMap(ref.MapKey.Value.Map, n.MapKey)
1350 i--
1351 continue
1352 }
1353 }
1354 }
1355 } else if isSuffix {
1356 ref.MapKey.Value = d2ast.ValueBox{}
1357 }
1358 } else if ref.InEdge() {
1359 edge := ref.MapKey.Edges[ref.MapKeyEdgeIndex]
1360
1361 if obj.Shape.Value == d2target.ShapeSQLTable || obj.Shape.Value == d2target.ShapeClass {
1362 if ref.MapKeyEdgeDest() {
1363 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, edge.Src, true)
1364 } else {
1365 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, edge.Dst, false)
1366 }
1367 deleteEdge(g, ref.Scope, ref.MapKey, ref.MapKeyEdgeIndex)
1368 } else if ref.KeyPathIndex == len(ref.Key.Path)-1 {
1369 if ref.MapKeyEdgeDest() {
1370 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, edge.Src, true)
1371 } else {
1372 ensureNode(g, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, edge.Dst, false)
1373 }
1374 deleteEdge(g, ref.Scope, ref.MapKey, ref.MapKeyEdgeIndex)
1375 } else {
1376 ref.Key.Path = append(ref.Key.Path[:ref.KeyPathIndex], ref.Key.Path[ref.KeyPathIndex+1:]...)
1377
1378
1379 if !ref.MapKeyEdgeDest() && i > 0 {
1380 nextRef := obj.References[i-1]
1381 if nextRef.InEdge() && nextRef.MapKey == ref.MapKey {
1382 i--
1383 }
1384 }
1385 }
1386 } else {
1387
1388 ref.Key.Path = append(ref.Key.Path[:ref.KeyPathIndex], ref.Key.Path[ref.KeyPathIndex+1:]...)
1389 if len(ref.Key.Path) == 0 {
1390 ref.MapKey.Key = nil
1391 }
1392 }
1393 }
1394
1395 return g, nil
1396 }
1397
1398 func findNearestParentScope(g *d2graph.Graph, k *d2ast.KeyPath) (prefix *d2ast.KeyPath, _ *d2ast.Map) {
1399 for i := 1; i < len(k.Path); i++ {
1400 scopeKey := cloneKey(k)
1401 scopeKey.Path = scopeKey.Path[:len(k.Path)-i]
1402 obj, ok := g.Root.HasChild(d2graph.Key(scopeKey))
1403 if ok && obj.Map != nil {
1404 prefix := cloneKey(k)
1405 prefix.Path = prefix.Path[len(k.Path)-i:]
1406 return prefix, obj.Map
1407 }
1408 }
1409 return k, g.AST
1410 }
1411
1412 func deleteEdge(g *d2graph.Graph, scope *d2ast.Map, mk *d2ast.Key, i int) {
1413 edgesAfter := mk.Edges[i+1:]
1414 mk.Edges = mk.Edges[:i]
1415
1416 for _, obj := range g.Objects {
1417 for j := range obj.References {
1418 ref := obj.References[j]
1419 if ref.InEdge() {
1420 if ref.MapKey == mk && ref.MapKeyEdgeIndex >= i {
1421 obj.References[j].MapKeyEdgeIndex -= i
1422 }
1423 }
1424 }
1425 }
1426
1427 if len(edgesAfter) > 0 {
1428 tmp := *mk
1429 mk2 := &tmp
1430 mk2.Edges = edgesAfter
1431 scope.InsertAfter(mk, mk2)
1432 }
1433 if len(mk.Edges) == 0 {
1434 deleteFromMap(scope, mk)
1435 }
1436 }
1437
1438
1439 func ensureNode(g *d2graph.Graph, excludedEdges []*d2ast.Edge, scopeObj *d2graph.Object, scope *d2ast.Map, cursor *d2ast.Key, k *d2ast.KeyPath, before bool) {
1440 if k == nil || len(k.Path) == 0 {
1441 return
1442 }
1443 if cursor.Key != nil && len(cursor.Key.Path) > 0 {
1444 k = cloneKey(k)
1445 k.Path = append(cursor.Key.Path, k.Path...)
1446 }
1447
1448 obj, ok := scopeObj.HasChild(d2graph.Key(k))
1449 if ok {
1450
1451 hasPersistingRef := false
1452 for _, ref := range obj.References {
1453 if !ref.InEdge() {
1454 hasPersistingRef = true
1455 break
1456 }
1457 if len(ref.MapKey.Edges) == 0 {
1458 continue
1459 }
1460 if !go2.Contains(excludedEdges, ref.MapKey.Edges[ref.MapKeyEdgeIndex]) {
1461 hasPersistingRef = true
1462 break
1463 }
1464 }
1465 if hasPersistingRef {
1466 return
1467 }
1468 }
1469 mk := &d2ast.Key{
1470 Key: k,
1471 }
1472
1473 for _, n := range scope.Nodes {
1474 if n.MapKey != nil && n.MapKey.D2OracleEquals(mk) {
1475 return
1476 }
1477 }
1478
1479 if before {
1480 scope.InsertBefore(cursor, mk)
1481 } else {
1482 scope.InsertAfter(cursor, mk)
1483 }
1484 }
1485
1486 func Rename(g *d2graph.Graph, boardPath []string, key, newName string) (_ *d2graph.Graph, newKey string, err error) {
1487 defer xdefer.Errorf(&err, "failed to rename %#v to %#v", key, newName)
1488
1489 mk, err := d2parser.ParseMapKey(key)
1490 if err != nil {
1491 return nil, "", err
1492 }
1493
1494 boardG := g
1495
1496 if len(boardPath) > 0 {
1497 boardG = GetBoardGraph(g, boardPath)
1498 if boardG == nil {
1499 return nil, "", fmt.Errorf("board %v not found", boardPath)
1500 }
1501 }
1502
1503 if len(mk.Edges) > 0 && mk.EdgeKey == nil {
1504
1505
1506 mk2, err := d2parser.ParseMapKey(newName)
1507 if err != nil {
1508 return nil, "", err
1509 }
1510
1511 mk2.Key = mk.Key
1512 mk = mk2
1513 } else {
1514 _, ok := d2graph.ReservedKeywords[newName]
1515 if ok {
1516 return nil, "", fmt.Errorf("cannot rename to reserved keyword: %#v", newName)
1517 }
1518 if mk.Key != nil {
1519 obj, ok := boardG.Root.HasChild(d2graph.Key(mk.Key))
1520 if !ok {
1521 return nil, "", fmt.Errorf("key does not exist")
1522 }
1523
1524 generatedName, _, err := generateUniqueKey(boardG, newName, obj, nil)
1525 if err == nil {
1526 newName = generatedName
1527 }
1528 }
1529
1530 mk.Key.Path[len(mk.Key.Path)-1] = d2ast.MakeValueBox(d2ast.RawString(newName, true)).StringBox()
1531 }
1532
1533 g, err = move(g, boardPath, key, d2format.Format(mk), false)
1534 return g, newName, err
1535 }
1536
1537 func trimReservedSuffix(path []*d2ast.StringBox) []*d2ast.StringBox {
1538 for i, p := range path {
1539 if _, ok := d2graph.ReservedKeywords[p.Unbox().ScalarString()]; ok {
1540 return path[:i]
1541 }
1542 }
1543 return path
1544 }
1545
1546
1547 func Move(g *d2graph.Graph, boardPath []string, key, newKey string, includeDescendants bool) (_ *d2graph.Graph, err error) {
1548 defer xdefer.Errorf(&err, "failed to move: %#v to %#v", key, newKey)
1549 return move(g, boardPath, key, newKey, includeDescendants)
1550 }
1551
1552 func move(g *d2graph.Graph, boardPath []string, key, newKey string, includeDescendants bool) (*d2graph.Graph, error) {
1553 if key == newKey {
1554 return g, nil
1555 }
1556
1557 boardG := g
1558 baseAST := g.AST
1559
1560 if len(boardPath) > 0 {
1561
1562 boardG = GetBoardGraph(g, boardPath)
1563 if boardG == nil {
1564 return nil, fmt.Errorf("board %v not found", boardPath)
1565 }
1566
1567 baseAST = boardG.BaseAST
1568 }
1569
1570 newKey, _, err := generateUniqueKey(boardG, newKey, nil, nil)
1571 if err != nil {
1572 return nil, err
1573 }
1574
1575 mk, err := d2parser.ParseMapKey(key)
1576 if err != nil {
1577 return nil, err
1578 }
1579
1580 mk2, err := d2parser.ParseMapKey(newKey)
1581 if err != nil {
1582 return nil, err
1583 }
1584 edgeTrimCommon(mk)
1585 edgeTrimCommon(mk2)
1586
1587 if len(mk.Edges) > 0 && mk.EdgeKey == nil {
1588 if d2format.Format(mk.Key) != d2format.Format(mk2.Key) {
1589
1590 return nil, errors.New("moving across scopes isn't supported for edges")
1591 }
1592 obj := g.Root
1593 if mk.Key != nil {
1594 var ok bool
1595 obj, ok = g.Root.HasChild(d2graph.Key(mk.Key))
1596 if !ok {
1597 return nil, fmt.Errorf("edge referenced by from does not exist")
1598 }
1599 }
1600 e, ok := obj.HasEdge(mk)
1601 if !ok {
1602 return nil, fmt.Errorf("edge referenced by to does not exist")
1603 }
1604 _, ok = obj.HasEdge(mk2)
1605 if ok {
1606 return nil, fmt.Errorf("to edge already exists")
1607 }
1608
1609 for i := len(e.References) - 1; i >= 0; i-- {
1610 ref := e.References[i]
1611 ref.MapKey.Edges[ref.MapKeyEdgeIndex].SrcArrow = mk2.Edges[0].SrcArrow
1612 ref.MapKey.Edges[ref.MapKeyEdgeIndex].DstArrow = mk2.Edges[0].DstArrow
1613 }
1614 return recompile(g)
1615 }
1616
1617 prevG, _ := recompile(boardG)
1618
1619 ak := d2graph.Key(mk.Key)
1620 ak2 := d2graph.Key(mk2.Key)
1621
1622 isCrossScope := strings.Join(ak[:len(ak)-1], ".") != strings.Join(ak2[:len(ak2)-1], ".")
1623
1624 if isCrossScope && !includeDescendants {
1625 boardG, err = renameConflictsToParent(boardG, mk.Key)
1626 if err != nil {
1627 return nil, err
1628 }
1629 }
1630
1631 obj, ok := boardG.Root.HasChild(ak)
1632 if !ok {
1633 return nil, fmt.Errorf("key referenced by from does not exist")
1634 }
1635
1636 if len(boardPath) > 0 {
1637 writeableRefs := getWriteableRefs(obj, baseAST)
1638 if len(writeableRefs) != len(obj.References) {
1639 return nil, OutsideScopeError{}
1640 }
1641 }
1642
1643 toParent := boardG.Root
1644 if isCrossScope && len(ak2) > 1 {
1645 toParent, ok = boardG.Root.HasChild(ak2[:len(ak2)-1])
1646 if !ok {
1647 return nil, fmt.Errorf("key referenced by to parent does not exist")
1648 }
1649 }
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669 needsLandingMap := false
1670 if isCrossScope {
1671 for _, ref := range obj.References {
1672 if !ref.InEdge() {
1673 needsLandingMap = true
1674 break
1675 }
1676 if ref.KeyPathIndex != len(ref.Key.Path)-1 {
1677 needsLandingMap = true
1678 break
1679 }
1680 }
1681 }
1682 if isCrossScope && len(ak2) > 1 && needsLandingMap {
1683 parentExistsAsKey := false
1684 for _, ref := range toParent.References {
1685 if len(ref.MapKey.Edges) == 0 {
1686 parentExistsAsKey = true
1687 break
1688 }
1689 }
1690 if !parentExistsAsKey {
1691
1692 var mostNestedRef d2graph.Reference
1693 for _, ref := range toParent.References {
1694 if mostNestedRef == (d2graph.Reference{}) || len(ref.ScopeObj.AbsIDArray()) > len(mostNestedRef.ScopeObj.AbsIDArray()) {
1695 mostNestedRef = ref
1696 }
1697 }
1698 detachedMK := &d2ast.Key{
1699 Key: cloneKey(mostNestedRef.MapKey.Key),
1700 }
1701 detachedMK.Key.Path = mostNestedRef.Key.Path[:mostNestedRef.KeyPathIndex+1]
1702 detachedMK.Range = d2ast.MakeRange(",1:0:0-1:0:0")
1703 mostNestedRef.Scope.InsertAfter(mostNestedRef.MapKey, detachedMK)
1704
1705 mostNestedRef.ScopeObj.AppendReferences(d2graph.Key(detachedMK.Key), d2graph.Reference{
1706 Key: detachedMK.Key,
1707 MapKey: detachedMK,
1708 Scope: mostNestedRef.Scope,
1709 }, mostNestedRef.ScopeObj)
1710 }
1711 }
1712
1713
1714
1715 toScope := boardG.AST
1716 if isCrossScope && len(ak2) > 1 && needsLandingMap {
1717 mostNestedParentRefs := getMostNestedRefs(toParent)
1718 mapExists := false
1719 for _, ref := range mostNestedParentRefs {
1720 if ref.KeyPathIndex == len(ref.Key.Path)-1 && ref.MapKey.Value.Map != nil {
1721 toScope = ref.MapKey.Value.Map
1722 mapExists = true
1723 break
1724 }
1725 }
1726
1727 if !mapExists {
1728 toScope = &d2ast.Map{
1729 Range: d2ast.MakeRange(",1:0:0-1:0:0"),
1730 }
1731
1732 ref := mostNestedParentRefs[len(mostNestedParentRefs)-1]
1733
1734 if ref.KeyPathIndex < len(ref.Key.Path)-1 {
1735 detachedMK := &d2ast.Key{
1736 Key: cloneKey(ref.MapKey.Key),
1737 }
1738 detachedMK.Value = ref.MapKey.Value
1739 detachedMK.Key.Path = ref.Key.Path[ref.KeyPathIndex+1:]
1740 detachedMK.Range = d2ast.MakeRange(",1:0:0-1:0:0")
1741
1742 ref.Key.Path = ref.Key.Path[:ref.KeyPathIndex+1]
1743 appendUniqueMapKey(toScope, detachedMK)
1744 } else {
1745 ref.MapKey.Primary = ref.MapKey.Value.ScalarBox()
1746 }
1747 ref.MapKey.Value = d2ast.MakeValueBox(toScope)
1748 }
1749 }
1750 mostNestedRefs := getMostNestedRefs(obj)
1751 for _, ref := range obj.References {
1752 isExplicit := ref.KeyPathIndex == len(trimReservedSuffix(ref.Key.Path))-1 && ref.MapKey.Value.Map == nil
1753
1754
1755 if ak[len(ak)-1] != ak2[len(ak2)-1] {
1756 ref.Key.Path[ref.KeyPathIndex] = d2ast.MakeValueBox(d2ast.RawString(
1757 mk2.Key.Path[len(mk2.Key.Path)-1].Unbox().ScalarString(),
1758 true,
1759 )).StringBox()
1760 }
1761
1762
1763 if len(ref.MapKey.Edges) != 0 {
1764 continue
1765 }
1766
1767 firstNonUnderscoreIndex := 0
1768 ida := d2graph.Key(ref.Key)
1769 for i, id := range ida {
1770 if id != "_" {
1771 firstNonUnderscoreIndex = i
1772 break
1773 }
1774 }
1775 resolvedObj, resolvedIDA, err := d2graph.ResolveUnderscoreKey(ida, ref.ScopeObj)
1776 if err != nil {
1777 return nil, err
1778 }
1779 if resolvedObj != obj {
1780 ida = resolvedIDA
1781 }
1782
1783 _, endsWithReserved := d2graph.ReservedKeywords[ida[len(ida)-1]]
1784 ida = go2.Filter(ida, func(x string) bool {
1785 _, ok := d2graph.ReservedKeywords[x]
1786 return !ok
1787 })
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798 if isCrossScope {
1799 if (!includeDescendants && len(ida) == 1) || (includeDescendants && ref.KeyPathIndex == firstNonUnderscoreIndex) {
1800
1801 absKey, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
1802 if err != nil {
1803 absKey = &d2ast.KeyPath{}
1804 }
1805 absKey.Path = append(absKey.Path, ref.Key.Path...)
1806 if !includeDescendants {
1807 hoistRefChildren(boardG, absKey, ref)
1808 }
1809 deleteFromMap(ref.Scope, ref.MapKey)
1810 detachedMK := &d2ast.Key{Primary: ref.MapKey.Primary, Key: cloneKey(ref.MapKey.Key)}
1811 detachedMK.Key.Path = go2.Filter(detachedMK.Key.Path, func(x *d2ast.StringBox) bool {
1812 return x.Unbox().ScalarString() != "_"
1813 })
1814 detachedMK.Value = ref.MapKey.Value
1815 if ref.MapKey != nil && ref.MapKey.Value.Map != nil {
1816
1817 if !includeDescendants {
1818 detachedMK.Value.Map = &d2ast.Map{
1819 Range: ref.MapKey.Value.Map.Range,
1820 }
1821 for _, n := range ref.MapKey.Value.Map.Nodes {
1822 if n.MapKey == nil {
1823 continue
1824 }
1825 if n.MapKey.Key != nil {
1826 _, ok := d2graph.ReservedKeywords[n.MapKey.Key.Path[0].Unbox().ScalarString()]
1827 if ok {
1828 detachedMK.Value.Map.Nodes = append(detachedMK.Value.Map.Nodes, n)
1829 }
1830 }
1831 }
1832 if len(detachedMK.Value.Map.Nodes) == 0 {
1833 detachedMK.Value.Map = nil
1834 }
1835 } else {
1836
1837
1838 for _, n := range ref.MapKey.Value.Map.Nodes {
1839 if n.MapKey == nil {
1840 continue
1841 }
1842 if n.MapKey.Key != nil {
1843 if n.MapKey.Key.Path[0].Unbox().ScalarString() == "_" {
1844 resolvedParent, resolvedScopeKey, err := d2graph.ResolveUnderscoreKey(d2graph.Key(n.MapKey.Key), obj)
1845 if err != nil {
1846 return nil, err
1847 }
1848
1849 newPath, err := pathFromScopeKey(boardG, &d2ast.Key{Key: d2ast.MakeKeyPath(append(resolvedParent.AbsIDArray(), resolvedScopeKey...))}, ak2)
1850 if err != nil {
1851 return nil, err
1852 }
1853 n.MapKey.Key.Path = newPath
1854 }
1855 }
1856 for _, e := range n.MapKey.Edges {
1857 if e.Src.Path[0].Unbox().ScalarString() == "_" {
1858 resolvedParent, resolvedScopeKey, err := d2graph.ResolveUnderscoreKey(d2graph.Key(e.Src), obj)
1859 if err != nil {
1860 return nil, err
1861 }
1862
1863 newPath, err := pathFromScopeKey(boardG, &d2ast.Key{Key: d2ast.MakeKeyPath(append(resolvedParent.AbsIDArray(), resolvedScopeKey...))}, ak2)
1864 if err != nil {
1865 return nil, err
1866 }
1867 e.Src.Path = newPath
1868 }
1869 if e.Dst.Path[0].Unbox().ScalarString() == "_" {
1870 resolvedParent, resolvedScopeKey, err := d2graph.ResolveUnderscoreKey(d2graph.Key(e.Dst), obj)
1871 if err != nil {
1872 return nil, err
1873 }
1874
1875 newPath, err := pathFromScopeKey(boardG, &d2ast.Key{Key: d2ast.MakeKeyPath(append(resolvedParent.AbsIDArray(), resolvedScopeKey...))}, ak2)
1876 if err != nil {
1877 return nil, err
1878 }
1879 e.Dst.Path = newPath
1880 }
1881 }
1882 }
1883 }
1884 }
1885 appendUniqueMapKey(toScope, detachedMK)
1886 } else if len(ida) > 1 && (endsWithReserved || !isExplicit || go2.Contains(mostNestedRefs, ref)) {
1887
1888 detachedMK := &d2ast.Key{Key: cloneKey(ref.MapKey.Key)}
1889 if includeDescendants {
1890 detachedMK.Key.Path = append([]*d2ast.StringBox{}, ref.Key.Path[ref.KeyPathIndex:]...)
1891 } else {
1892 detachedMK.Key.Path = []*d2ast.StringBox{ref.Key.Path[ref.KeyPathIndex]}
1893 }
1894 if includeDescendants {
1895 detachedMK.Value = ref.MapKey.Value
1896 ref.MapKey.Value = d2ast.ValueBox{}
1897 } else if ref.KeyPathIndex == len(filterReservedPath(ref.Key.Path))-1 {
1898 withReserved, withoutReserved := filterReserved(ref.MapKey.Value)
1899 detachedMK.Value = withReserved
1900 ref.MapKey.Value = withoutReserved
1901 detachedMK.Key.Path = append([]*d2ast.StringBox{}, ref.Key.Path[ref.KeyPathIndex:]...)
1902 ref.Key.Path = ref.Key.Path[:ref.KeyPathIndex+1]
1903 }
1904 if includeDescendants {
1905 ref.Key.Path = ref.Key.Path[:ref.KeyPathIndex]
1906 } else {
1907 ref.Key.Path = append(ref.Key.Path[:ref.KeyPathIndex], ref.Key.Path[ref.KeyPathIndex+1:]...)
1908 }
1909 appendUniqueMapKey(toScope, detachedMK)
1910 } else if len(getCommonPath(ak, ak2)) > 0 {
1911
1912
1913 newKeyPath := ref.Key.Path[:ref.KeyPathIndex]
1914 newKeyPath = append(newKeyPath, mk2.Key.Path[len(getCommonPath(ak, ak2)):]...)
1915 ref.Key.Path = append(newKeyPath, ref.Key.Path[ref.KeyPathIndex+1:]...)
1916 } else {
1917
1918 scopePath := ref.ScopeObj.AbsIDArray()
1919 if len(getCommonPath(scopePath, ak2)) != len(scopePath) {
1920 deleteFromMap(ref.Scope, ref.MapKey)
1921 } else {
1922 ref.Key.Path = ref.Key.Path[ref.KeyPathIndex:]
1923 exists := false
1924 for _, n := range toScope.Nodes {
1925 if n.MapKey != nil && n.MapKey != ref.MapKey && n.MapKey.D2OracleEquals(ref.MapKey) {
1926 exists = true
1927 }
1928 }
1929 if exists {
1930 deleteFromMap(ref.Scope, ref.MapKey)
1931 }
1932 }
1933 }
1934 }
1935 }
1936 var refEdges []*d2ast.Edge
1937 for _, ref := range obj.References {
1938 if ref.InEdge() {
1939 refEdges = append(refEdges, ref.MapKey.Edges[ref.MapKeyEdgeIndex])
1940 }
1941 }
1942 for i := 0; i < len(obj.References); i++ {
1943 if !isCrossScope {
1944 break
1945 }
1946
1947 ref := obj.References[i]
1948
1949 if len(ref.MapKey.Edges) == 0 {
1950 continue
1951 }
1952
1953 if i > 0 && ref.Key == obj.References[i-1].Key {
1954 continue
1955 }
1956
1957 firstNonUnderscoreIndex := 0
1958 ida := d2graph.Key(ref.Key)
1959 for i, id := range ida {
1960 if id != "_" {
1961 firstNonUnderscoreIndex = i
1962 break
1963 }
1964 }
1965
1966 if ref.KeyPathIndex != len(ref.Key.Path)-1 {
1967
1968
1969
1970 detachedMK := &d2ast.Key{
1971 Key: cloneKey(ref.Key),
1972 }
1973 oldPath, err := pathFromScopeObj(boardG, mk, ref.ScopeObj)
1974 if err != nil {
1975 return nil, err
1976 }
1977 newPath, err := pathFromScopeObj(boardG, mk2, ref.ScopeObj)
1978 if err != nil {
1979 return nil, err
1980 }
1981 if includeDescendants {
1982
1983
1984 diff := len(oldPath) - len(newPath)
1985
1986 if diff == 0 {
1987 diff = len(getUncommonPath(d2graph.Key(&d2ast.KeyPath{Path: oldPath}), d2graph.Key(&d2ast.KeyPath{Path: newPath})))
1988 }
1989
1990 if diff > 0 && ref.KeyPathIndex != firstNonUnderscoreIndex {
1991 detachedMK.Key.Path = append([]*d2ast.StringBox{}, ref.Key.Path[ref.KeyPathIndex-diff:ref.KeyPathIndex]...)
1992 appendUniqueMapKey(ref.Scope, detachedMK)
1993 }
1994 } else {
1995 detachedMK.Key.Path = []*d2ast.StringBox{ref.Key.Path[ref.KeyPathIndex]}
1996 appendUniqueMapKey(toScope, detachedMK)
1997 }
1998
1999 if includeDescendants {
2000 ref.Key.Path = append(ref.Key.Path[:ref.KeyPathIndex-len(oldPath)+1], append(newPath, ref.Key.Path[ref.KeyPathIndex+1:]...)...)
2001 } else {
2002 ref.Key.Path = append(ref.Key.Path[:ref.KeyPathIndex], ref.Key.Path[ref.KeyPathIndex+1:]...)
2003 }
2004 } else {
2005
2006
2007
2008 newPath, err := pathFromScopeObj(boardG, mk2, ref.ScopeObj)
2009 if err != nil {
2010 return nil, err
2011 }
2012 if len(go2.Filter(ref.Key.Path, func(x *d2ast.StringBox) bool { return x.Unbox().ScalarString() != "_" })) > 1 {
2013 detachedK := cloneKey(ref.Key)
2014 detachedK.Path = detachedK.Path[:len(detachedK.Path)-1]
2015 ensureNode(boardG, refEdges, ref.ScopeObj, ref.Scope, ref.MapKey, detachedK, false)
2016 }
2017
2018 if includeDescendants {
2019 ref.Key.Path = append(newPath, ref.Key.Path[go2.Min(len(ref.Key.Path), ref.KeyPathIndex+len(newPath)):]...)
2020 } else {
2021 ref.Key.Path = newPath
2022 }
2023 }
2024 }
2025
2026 if err := updateNear(prevG, boardG, &key, &newKey, includeDescendants); err != nil {
2027 return nil, err
2028 }
2029
2030 if len(boardPath) > 0 {
2031 replaced := ReplaceBoardNode(g.AST, baseAST, boardPath)
2032 if !replaced {
2033 return nil, fmt.Errorf("board %v AST not found", boardPath)
2034 }
2035 return recompile(g)
2036 }
2037
2038 return recompile(boardG)
2039 }
2040
2041
2042
2043
2044
2045 func filterReserved(value d2ast.ValueBox) (with, without d2ast.ValueBox) {
2046 with, without = d2ast.MakeValueBox(value.Unbox()), d2ast.ValueBox{}
2047
2048 if value.Map != nil {
2049 var forWith []d2ast.MapNodeBox
2050 var forWithout []d2ast.MapNodeBox
2051
2052
2053
2054 var commentBatch []d2ast.MapNodeBox
2055 flushComments := func(to *[]d2ast.MapNodeBox) {
2056 *to = append(*to, commentBatch...)
2057 commentBatch = nil
2058 }
2059
2060 for _, n := range value.Map.Nodes {
2061 if n.MapKey == nil {
2062 if n.Comment != nil || n.BlockComment != nil {
2063 commentBatch = append(commentBatch, n)
2064 }
2065 continue
2066 }
2067 if n.MapKey.Key == nil || (len(n.MapKey.Key.Path) > 1) {
2068 flushComments(&forWithout)
2069 forWithout = append(forWithout, n)
2070 continue
2071 }
2072 _, ok := d2graph.ReservedKeywords[n.MapKey.Key.Path[0].Unbox().ScalarString()]
2073 if !ok {
2074 flushComments(&forWithout)
2075 forWithout = append(forWithout, n)
2076 continue
2077 }
2078 flushComments(&forWith)
2079 forWith = append(forWith, n)
2080 }
2081
2082 if len(forWith) > 0 {
2083 if with.Map == nil {
2084 with.Map = &d2ast.Map{
2085 Range: d2ast.MakeRange(",1:0:0-1:0:0"),
2086 }
2087 }
2088 with.Map.Nodes = forWith
2089 } else {
2090 with.Map = nil
2091 }
2092 if len(forWithout) > 0 {
2093 if without.Map == nil {
2094 without.Map = &d2ast.Map{
2095 Range: value.Map.Range,
2096 }
2097 }
2098 without.Map.Nodes = forWithout
2099 } else {
2100 without.Map = nil
2101 }
2102 }
2103
2104 return
2105 }
2106
2107
2108
2109 func updateNear(prevG, g *d2graph.Graph, from, to *string, includeDescendants bool) error {
2110 mk, _ := d2parser.ParseMapKey(*from)
2111 if len(mk.Edges) > 0 {
2112 return nil
2113 }
2114 if mk.Key == nil {
2115 return nil
2116 }
2117 if len(mk.Key.Path) == 0 {
2118 return nil
2119 }
2120
2121
2122
2123
2124
2125
2126
2127 for _, obj := range g.Objects {
2128 if obj.Map == nil {
2129 continue
2130 }
2131 for _, n := range obj.Map.Nodes {
2132 if n.MapKey == nil {
2133 continue
2134 }
2135 if n.MapKey.Key == nil {
2136 continue
2137 }
2138 if len(n.MapKey.Key.Path) == 0 {
2139 continue
2140 }
2141 if n.MapKey.Key.Path[len(n.MapKey.Key.Path)-1].Unbox().ScalarString() == "near" {
2142 k := n.MapKey.Value.ScalarBox().Unbox().ScalarString()
2143 if strings.EqualFold(k, *from) && to == nil {
2144 deleteFromMap(obj.Map, n.MapKey)
2145 } else {
2146 valueMK, err := d2parser.ParseMapKey(k)
2147 if err != nil {
2148 return err
2149 }
2150 tmpG, _ := recompile(prevG)
2151 appendMapKey(tmpG.AST, valueMK)
2152 if to == nil {
2153 deltas, err := DeleteIDDeltas(tmpG, nil, *from)
2154 if err != nil {
2155 return err
2156 }
2157 if v, ok := deltas[k]; ok {
2158 n.MapKey.Value = d2ast.MakeValueBox(d2ast.RawString(v, false))
2159 }
2160 } else {
2161 deltas, err := MoveIDDeltas(tmpG, *from, *to, includeDescendants)
2162 if err != nil {
2163 return err
2164 }
2165 if v, ok := deltas[k]; ok {
2166 n.MapKey.Value = d2ast.MakeValueBox(d2ast.RawString(v, false))
2167 }
2168 }
2169 }
2170 }
2171 }
2172 }
2173
2174
2175 for _, obj := range g.Objects {
2176 for _, ref := range obj.References {
2177 if ref.MapKey == nil {
2178 continue
2179 }
2180 if ref.MapKey.Key == nil {
2181 continue
2182 }
2183 if len(ref.MapKey.Key.Path) == 0 {
2184 continue
2185 }
2186 if ref.MapKey.Key.Path[len(ref.MapKey.Key.Path)-1].Unbox().ScalarString() == "near" {
2187 k := ref.MapKey.Value.ScalarBox().Unbox().ScalarString()
2188 if strings.EqualFold(k, *from) && to == nil {
2189 deleteFromMap(obj.Map, ref.MapKey)
2190 } else {
2191 valueMK, err := d2parser.ParseMapKey(k)
2192 if err != nil {
2193 return err
2194 }
2195 tmpG, _ := recompile(prevG)
2196 appendMapKey(tmpG.AST, valueMK)
2197 if to == nil {
2198 deltas, err := DeleteIDDeltas(tmpG, nil, *from)
2199 if err != nil {
2200 return err
2201 }
2202 if v, ok := deltas[k]; ok {
2203 ref.MapKey.Value = d2ast.MakeValueBox(d2ast.RawString(v, false))
2204 }
2205 } else {
2206 deltas, err := MoveIDDeltas(tmpG, *from, *to, includeDescendants)
2207 if err != nil {
2208 return err
2209 }
2210 if v, ok := deltas[k]; ok {
2211 ref.MapKey.Value = d2ast.MakeValueBox(d2ast.RawString(v, false))
2212 }
2213 }
2214 }
2215 }
2216 }
2217 }
2218
2219 return nil
2220 }
2221
2222 func deleteFromMap(m *d2ast.Map, mk *d2ast.Key) bool {
2223 for i, n := range m.Nodes {
2224 if n.MapKey == mk {
2225 m.Nodes = append(m.Nodes[:i], m.Nodes[i+1:]...)
2226 return true
2227 }
2228 }
2229 return false
2230 }
2231
2232 func ReparentIDDelta(g *d2graph.Graph, boardPath []string, key, parentKey string) (string, error) {
2233 mk, err := d2parser.ParseMapKey(key)
2234 if err != nil {
2235 return "", err
2236 }
2237
2238 boardG := g
2239
2240 if len(boardPath) > 0 {
2241
2242 boardG = GetBoardGraph(g, boardPath)
2243 if boardG == nil {
2244 return "", fmt.Errorf("board %v not found", boardPath)
2245 }
2246 }
2247
2248 obj, ok := boardG.Root.HasChild(d2graph.Key(mk.Key))
2249 if !ok {
2250 return "", errors.New("not found")
2251 }
2252
2253 parent := boardG.Root
2254 if parentKey != "" {
2255 mk2, err := d2parser.ParseMapKey(parentKey)
2256 if err != nil {
2257 return "", err
2258 }
2259 parent, ok = boardG.Root.HasChild(d2graph.Key(mk2.Key))
2260 if !ok {
2261 return "", errors.New("not found")
2262 }
2263 }
2264
2265 prevParent := obj.Parent
2266 obj.Parent = parent
2267 id := obj.AbsID()
2268 obj.Parent = prevParent
2269 return id, nil
2270 }
2271
2272 func ReconnectEdgeIDDeltas(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey, dstKey *string) (deltas map[string]string, err error) {
2273 defer xdefer.Errorf(&err, "failed to get deltas for reconnect edge %#v", edgeKey)
2274 deltas = make(map[string]string)
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284 mk, err := d2parser.ParseMapKey(edgeKey)
2285 if err != nil {
2286 return nil, err
2287 }
2288
2289 if len(mk.Edges) == 0 {
2290 return nil, errors.New("edgeKey must be an edge")
2291 }
2292
2293 if mk.EdgeIndex == nil {
2294 return nil, errors.New("edgeKey must refer to an existing edge")
2295 }
2296
2297 edgeTrimCommon(mk)
2298
2299 boardG := g
2300
2301 if len(boardPath) > 0 {
2302
2303 boardG = GetBoardGraph(g, boardPath)
2304 if boardG == nil {
2305 return nil, fmt.Errorf("board %v not found", boardPath)
2306 }
2307 }
2308
2309 obj := boardG.Root
2310 if mk.Key != nil {
2311 var ok bool
2312 obj, ok = boardG.Root.HasChild(d2graph.Key(mk.Key))
2313 if !ok {
2314 return nil, errors.New("edge not found")
2315 }
2316 }
2317 edge, ok := obj.HasEdge(mk)
2318 if !ok {
2319 return nil, errors.New("edge not found")
2320 }
2321
2322 if srcKey != nil {
2323 if edge.Src.AbsID() == *srcKey {
2324 srcKey = nil
2325 }
2326 }
2327
2328 if dstKey != nil {
2329 if edge.Dst.AbsID() == *dstKey {
2330 dstKey = nil
2331 }
2332 }
2333
2334 if srcKey == nil && dstKey == nil {
2335 return nil, nil
2336 }
2337
2338 newSrc := edge.Src
2339 newDst := edge.Dst
2340 var src *d2graph.Object
2341 var dst *d2graph.Object
2342 if srcKey != nil {
2343 srcmk, err := d2parser.ParseMapKey(*srcKey)
2344 if err != nil {
2345 return nil, err
2346 }
2347 src, ok = boardG.Root.HasChild(d2graph.Key(srcmk.Key))
2348 if !ok {
2349 return nil, errors.New("newSrc not found")
2350 }
2351 newSrc = src
2352 }
2353 if dstKey != nil {
2354 dstmk, err := d2parser.ParseMapKey(*dstKey)
2355 if err != nil {
2356 return nil, err
2357 }
2358 dst, ok = boardG.Root.HasChild(d2graph.Key(dstmk.Key))
2359 if !ok {
2360 return nil, errors.New("newDst not found")
2361 }
2362 newDst = dst
2363 }
2364
2365
2366 firstRef := edge.References[0]
2367 line := firstRef.MapKey.Range.Start.Line
2368 newIndex := 0
2369
2370
2371 for _, otherEdge := range boardG.Edges {
2372 if otherEdge.Src == newSrc && otherEdge.Dst == newDst {
2373 firstRef := otherEdge.References[0]
2374 if firstRef.MapKey.Range.Start.Line <= line {
2375 newIndex++
2376 }
2377 }
2378 if otherEdge.Src == edge.Src && otherEdge.Dst == edge.Dst && otherEdge.Index > edge.Index {
2379 before := otherEdge.AbsID()
2380 otherEdge.Index--
2381 after := otherEdge.AbsID()
2382 deltas[before] = after
2383 otherEdge.Index++
2384 }
2385 }
2386
2387 for _, otherEdge := range g.Edges {
2388 if otherEdge.Src == newSrc && otherEdge.Dst == newDst {
2389 if otherEdge.Index >= newIndex {
2390 before := otherEdge.AbsID()
2391 otherEdge.Index++
2392 after := otherEdge.AbsID()
2393 deltas[before] = after
2394 otherEdge.Index--
2395 }
2396 }
2397 }
2398
2399 newEdge := &d2graph.Edge{
2400 Src: newSrc,
2401 Dst: newDst,
2402 SrcArrow: edge.SrcArrow,
2403 DstArrow: edge.DstArrow,
2404 Index: newIndex,
2405 }
2406
2407 deltas[edge.AbsID()] = newEdge.AbsID()
2408
2409 return deltas, nil
2410 }
2411
2412
2413
2414
2415
2416
2417
2418 func generateUniqueKey(g *d2graph.Graph, prefix string, ignored *d2graph.Object, included []string) (key string, edge bool, _ error) {
2419 mk, err := d2parser.ParseMapKey(prefix)
2420 if err != nil {
2421 return "", false, err
2422 }
2423
2424 if len(mk.Edges) > 1 {
2425 return "", false, errors.New("cannot generate unique key for edge chain")
2426 }
2427
2428 if len(mk.Edges) == 1 {
2429 if mk.EdgeIndex == nil || mk.EdgeIndex.Int == nil {
2430 mk.EdgeIndex = &d2ast.EdgeIndex{
2431 Int: go2.Pointer(0),
2432 }
2433 }
2434
2435 edgeTrimCommon(mk)
2436 obj := g.Root
2437 if mk.Key != nil {
2438 var ok bool
2439 obj, ok = g.Root.HasChild(d2graph.Key(mk.Key))
2440 if !ok {
2441 return d2format.Format(mk), true, nil
2442 }
2443 }
2444 for {
2445 _, ok := obj.HasEdge(mk)
2446 if !ok {
2447 return d2format.Format(mk), true, nil
2448 }
2449 mk.EdgeIndex.Int = go2.Pointer(*mk.EdgeIndex.Int + 1)
2450 }
2451 }
2452
2453
2454 if mk.Key == nil {
2455 mk.Key = &d2ast.KeyPath{
2456 Path: []*d2ast.StringBox{d2ast.MakeValueBox(d2ast.RawString(xrand.Base64(16), true)).StringBox()},
2457 }
2458 } else if obj, ok := g.Root.HasChild(d2graph.Key(mk.Key)); ok && obj != ignored {
2459
2460 spaced := strings.Split(prefix, " ")
2461 if len(spaced) > 1 {
2462 if _, err := strconv.Atoi(spaced[len(spaced)-1]); err == nil {
2463 withoutIndex := strings.Join(spaced[:len(spaced)-1], " ")
2464 mk, err = d2parser.ParseMapKey(withoutIndex)
2465 if err != nil {
2466 return "", false, err
2467 }
2468 }
2469 }
2470 }
2471
2472 k2 := cloneKey(mk.Key)
2473 i := 0
2474 for {
2475 conflictsWithIncluded := false
2476 for _, s := range included {
2477 if d2format.Format(k2) == s {
2478 conflictsWithIncluded = true
2479 break
2480 }
2481 }
2482 if !conflictsWithIncluded {
2483 obj, ok := g.Root.HasChild(d2graph.Key(k2))
2484 if !ok || obj == ignored {
2485 return d2format.Format(k2), false, nil
2486 }
2487 }
2488
2489 rr := fmt.Sprintf("%s %d", mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString(), i+2)
2490 k2.Path[len(k2.Path)-1] = d2ast.MakeValueBox(d2ast.RawString(rr, true)).StringBox()
2491 i++
2492 }
2493 }
2494
2495 func cloneKey(k *d2ast.KeyPath) *d2ast.KeyPath {
2496 if k == nil {
2497 return &d2ast.KeyPath{}
2498 }
2499 tmp := *k
2500 k2 := &tmp
2501 k2.Path = nil
2502 for _, p := range k.Path {
2503 k2.Path = append(k2.Path, d2ast.MakeValueBox(p.Unbox().Copy()).StringBox())
2504 }
2505 return k2
2506 }
2507
2508 func getCommonPath(a, b []string) []string {
2509 var out []string
2510 for i := 0; i < len(a) && i < len(b); i++ {
2511 if a[i] == b[i] {
2512 out = a[:i+1]
2513 }
2514 }
2515 return out
2516 }
2517
2518 func getUncommonPath(a, b []string) []string {
2519 var out []string
2520 for i := 0; i < len(a) && i < len(b); i++ {
2521 if a[i] != b[i] {
2522 out = a[:i+1]
2523 }
2524 }
2525 return out
2526 }
2527
2528 func edgeTrimCommon(mk *d2ast.Key) {
2529 if len(mk.Edges) != 1 {
2530 return
2531 }
2532 e := mk.Edges[0]
2533 for len(e.Src.Path) > 1 && len(e.Dst.Path) > 1 {
2534 if !strings.EqualFold(e.Src.Path[0].Unbox().ScalarString(), e.Dst.Path[0].Unbox().ScalarString()) {
2535 return
2536 }
2537 if mk.Key == nil {
2538 mk.Key = &d2ast.KeyPath{}
2539 }
2540 mk.Key.Path = append(mk.Key.Path, e.Src.Path[0])
2541 e.Src.Path = e.Src.Path[1:]
2542 e.Dst.Path = e.Dst.Path[1:]
2543 }
2544 }
2545
2546 func MoveIDDeltas(g *d2graph.Graph, key, newKey string, includeDescendants bool) (deltas map[string]string, err error) {
2547 defer xdefer.Errorf(&err, "failed to get deltas for move from %#v to %#v", key, newKey)
2548 deltas = make(map[string]string)
2549
2550 if key == newKey {
2551 return deltas, nil
2552 }
2553
2554 mk, err := d2parser.ParseMapKey(key)
2555 if err != nil {
2556 return nil, err
2557 }
2558
2559 newKey, _, err = generateUniqueKey(g, newKey, nil, nil)
2560 if err != nil {
2561 return nil, err
2562 }
2563
2564 mk2, err := d2parser.ParseMapKey(newKey)
2565 if err != nil {
2566 return nil, err
2567 }
2568
2569 ak := d2graph.Key(mk.Key)
2570 ak2 := d2graph.Key(mk2.Key)
2571 isCrossScope := strings.Join(ak[:len(ak)-1], ".") != strings.Join(ak2[:len(ak2)-1], ".")
2572
2573 edgeTrimCommon(mk)
2574 obj := g.Root
2575
2576
2577 conflictNewIDs := make(map[*d2graph.Object]string)
2578 conflictOldIDs := make(map[*d2graph.Object]string)
2579 var newIDs []string
2580 if mk.Key != nil {
2581 var ok bool
2582 obj, ok = g.Root.HasChild(d2graph.Key(mk.Key))
2583 if !ok {
2584 return nil, nil
2585 }
2586
2587 ignored := obj
2588 for _, ch := range obj.ChildrenArray {
2589 if ch.ID == obj.ID {
2590 ignored = nil
2591 break
2592 }
2593 }
2594
2595 if !includeDescendants {
2596 for _, ch := range obj.ChildrenArray {
2597 chMK, err := d2parser.ParseMapKey(ch.AbsID())
2598 if err != nil {
2599 return nil, err
2600 }
2601 ida := d2graph.Key(chMK.Key)
2602 if ida[len(ida)-1] == ida[len(ida)-2] {
2603 continue
2604 }
2605
2606 hoistedAbsID := ch.ID
2607 if obj.Parent != g.Root {
2608 hoistedAbsID = obj.Parent.AbsID() + "." + ch.ID
2609 }
2610 hoistedMK, err := d2parser.ParseMapKey(hoistedAbsID)
2611 if err != nil {
2612 return nil, err
2613 }
2614
2615 conflictsWithNewID := false
2616 for _, id := range newIDs {
2617 if id == d2format.Format(hoistedMK.Key) {
2618 conflictsWithNewID = true
2619 break
2620 }
2621 }
2622
2623 if _, ok := g.Root.HasChild(d2graph.Key(hoistedMK.Key)); ok || conflictsWithNewID {
2624 newKey, _, err := generateUniqueKey(g, hoistedAbsID, ignored, newIDs)
2625 if err != nil {
2626 return nil, err
2627 }
2628 newMK, err := d2parser.ParseMapKey(newKey)
2629 if err != nil {
2630 return nil, err
2631 }
2632 newAK := d2graph.Key(newMK.Key)
2633 conflictOldIDs[ch] = ch.ID
2634 conflictNewIDs[ch] = newAK[len(newAK)-1]
2635 newIDs = append(newIDs, d2format.Format(newMK.Key))
2636 } else {
2637 newIDs = append(newIDs, d2format.Format(hoistedMK.Key))
2638 }
2639 }
2640 }
2641 }
2642
2643 if len(mk.Edges) > 1 {
2644 return nil, nil
2645 }
2646 if len(mk.Edges) == 1 {
2647 if len(mk.Edges) == 0 {
2648 return nil, errors.New("cannot rename edge to node")
2649 }
2650 if len(mk.Edges) > 1 {
2651 return nil, errors.New("cannot rename edge to edge chain")
2652 }
2653
2654 e, ok := obj.HasEdge(mk)
2655 if !ok {
2656 return nil, nil
2657 }
2658 beforeID := e.AbsID()
2659 tmp := *e
2660 e2 := &tmp
2661 e2.SrcArrow = mk2.Edges[0].SrcArrow == "<"
2662 e2.DstArrow = mk2.Edges[0].DstArrow == ">"
2663 deltas[beforeID] = e2.AbsID()
2664 return deltas, nil
2665 }
2666
2667 beforeObjID := obj.ID
2668
2669 toParent := g.Root
2670 if len(ak2) > 1 {
2671 var ok bool
2672 toParent, ok = g.Root.HasChild(ak2[:len(ak2)-1])
2673 if !ok {
2674 return nil, errors.New("to parent not found")
2675 }
2676 }
2677 id := ak2[len(ak2)-1]
2678
2679 tmpRenames := func() func() {
2680 if isCrossScope && !includeDescendants {
2681 for _, ch := range obj.ChildrenArray {
2682 ch.Parent = obj.Parent
2683 }
2684 }
2685
2686 prevParent := obj.Parent
2687 obj.Parent = toParent
2688 obj.ID = id
2689
2690 for k, v := range conflictNewIDs {
2691 k.ID = v
2692 }
2693 return func() {
2694 for k, v := range conflictOldIDs {
2695 k.ID = v
2696 }
2697 obj.ID = beforeObjID
2698 obj.Parent = prevParent
2699
2700 if isCrossScope && !includeDescendants {
2701 for _, ch := range obj.ChildrenArray {
2702 ch.Parent = obj
2703 }
2704 }
2705 }
2706 }
2707
2708 appendNodeDelta := func(ch *d2graph.Object) {
2709 beforeID := ch.AbsID()
2710 revert := tmpRenames()
2711 deltas[beforeID] = ch.AbsID()
2712 revert()
2713 }
2714
2715 appendEdgeDelta := func(ch *d2graph.Object) {
2716 for _, e := range obj.Graph.Edges {
2717 if e.Src == ch || e.Dst == ch {
2718 beforeID := e.AbsID()
2719 revert := tmpRenames()
2720 deltas[beforeID] = e.AbsID()
2721 revert()
2722 }
2723 }
2724 }
2725
2726 var recurse func(ch *d2graph.Object)
2727 recurse = func(ch *d2graph.Object) {
2728 for _, ch := range ch.ChildrenArray {
2729 appendNodeDelta(ch)
2730 appendEdgeDelta(ch)
2731 recurse(ch)
2732 }
2733 }
2734 appendNodeDelta(obj)
2735 appendEdgeDelta(obj)
2736 recurse(obj)
2737 return deltas, nil
2738 }
2739
2740 func DeleteIDDeltas(g *d2graph.Graph, boardPath []string, key string) (deltas map[string]string, err error) {
2741 defer xdefer.Errorf(&err, "failed to get deltas for deletion of %#v", key)
2742 deltas = make(map[string]string)
2743
2744 mk, err := d2parser.ParseMapKey(key)
2745 if err != nil {
2746 return nil, err
2747 }
2748
2749 edgeTrimCommon(mk)
2750
2751 boardG := g
2752 if len(boardPath) > 0 {
2753 boardG = GetBoardGraph(g, boardPath)
2754 if boardG == nil {
2755 return nil, fmt.Errorf("board %v not found", boardPath)
2756 }
2757 }
2758
2759 obj := boardG.Root
2760 conflictNewIDs := make(map[*d2graph.Object]string)
2761 conflictOldIDs := make(map[*d2graph.Object]string)
2762 var newIDs []string
2763 if mk.Key != nil {
2764 ida := d2graph.Key(mk.Key)
2765
2766 if _, ok := d2graph.ReservedKeywords[ida[len(ida)-1]]; ok {
2767 return nil, nil
2768 }
2769
2770 var ok bool
2771 obj, ok = boardG.Root.HasChild(d2graph.Key(mk.Key))
2772 if !ok {
2773 return nil, nil
2774 }
2775
2776 ignored := obj
2777 for _, ch := range obj.ChildrenArray {
2778 if ch.ID == obj.ID {
2779 ignored = nil
2780 break
2781 }
2782 }
2783
2784 for _, ch := range obj.ChildrenArray {
2785
2786 var siblingsToBeHoisted []string
2787 for _, ch2 := range obj.ChildrenArray {
2788 if ch2 != ch {
2789 chMK, err := d2parser.ParseMapKey(ch2.AbsID())
2790 if err != nil {
2791 return nil, err
2792 }
2793 ida := d2graph.Key(chMK.Key)
2794 if ida[len(ida)-1] == ida[len(ida)-2] {
2795 continue
2796 }
2797 hoistedAbsID := ch2.ID
2798 if obj.Parent != boardG.Root {
2799 hoistedAbsID = obj.Parent.AbsID() + "." + ch2.ID
2800 }
2801 siblingsToBeHoisted = append(siblingsToBeHoisted, hoistedAbsID)
2802 }
2803 }
2804 chMK, err := d2parser.ParseMapKey(ch.AbsID())
2805 if err != nil {
2806 return nil, err
2807 }
2808 ida := d2graph.Key(chMK.Key)
2809 if ida[len(ida)-1] == ida[len(ida)-2] {
2810 continue
2811 }
2812 hoistedAbsID := ch.ID
2813 if obj.Parent != boardG.Root {
2814 hoistedAbsID = obj.Parent.AbsID() + "." + ch.ID
2815 }
2816 hoistedMK, err := d2parser.ParseMapKey(hoistedAbsID)
2817 if err != nil {
2818 return nil, err
2819 }
2820
2821 conflictsWithNewID := false
2822 for _, id := range newIDs {
2823 if id == d2format.Format(hoistedMK.Key) {
2824 conflictsWithNewID = true
2825 break
2826 }
2827 }
2828
2829 if conflictingObj, ok := boardG.Root.HasChild(d2graph.Key(hoistedMK.Key)); (ok && conflictingObj != obj) || conflictsWithNewID {
2830 newKey, _, err := generateUniqueKey(boardG, hoistedAbsID, ignored, append(newIDs, siblingsToBeHoisted...))
2831 if err != nil {
2832 return nil, err
2833 }
2834 newMK, err := d2parser.ParseMapKey(newKey)
2835 if err != nil {
2836 return nil, err
2837 }
2838 newAK := d2graph.Key(newMK.Key)
2839 conflictOldIDs[ch] = ch.ID
2840 conflictNewIDs[ch] = newAK[len(newAK)-1]
2841 newIDs = append(newIDs, d2format.Format(newMK.Key))
2842 } else {
2843 newIDs = append(newIDs, d2format.Format(hoistedMK.Key))
2844 }
2845 }
2846 }
2847 if len(mk.Edges) > 1 {
2848 return nil, nil
2849 }
2850 if len(mk.Edges) == 1 {
2851
2852 if mk.EdgeKey != nil {
2853 return nil, nil
2854 }
2855 e, ok := obj.HasEdge(mk)
2856 if !ok {
2857 return nil, nil
2858 }
2859 ea, ok := obj.FindEdges(mk)
2860 if !ok {
2861 return nil, nil
2862 }
2863 for _, e2 := range ea {
2864 if e2.Index > e.Index {
2865 beforeID := e2.AbsID()
2866 e2.Index--
2867 deltas[beforeID] = e2.AbsID()
2868 e2.Index++
2869 }
2870 }
2871 return deltas, nil
2872 }
2873
2874 for _, ch := range obj.ChildrenArray {
2875 tmpRenames := func() func() {
2876 prevIDs := make(map[*d2graph.Object]string)
2877 for _, ch := range obj.ChildrenArray {
2878 prevIDs[ch] = ch.ID
2879 ch.Parent = obj.Parent
2880 }
2881 for k, v := range conflictNewIDs {
2882 k.ID = v
2883 }
2884
2885 return func() {
2886 for k, v := range conflictOldIDs {
2887 k.ID = v
2888 }
2889 for _, ch := range obj.ChildrenArray {
2890 ch.Parent = obj
2891 ch.ID = prevIDs[ch]
2892 }
2893 }
2894 }
2895
2896 appendNodeDelta := func(ch2 *d2graph.Object) {
2897 beforeAbsID := ch2.AbsID()
2898 revert := tmpRenames()
2899 deltas[beforeAbsID] = ch2.AbsID()
2900 revert()
2901
2902 }
2903 appendEdgeDelta := func(ch2 *d2graph.Object) {
2904 for _, e := range obj.Graph.Edges {
2905 if e.Src == ch2 || e.Dst == ch2 {
2906 beforeAbsID := e.AbsID()
2907 revert := tmpRenames()
2908 deltas[beforeAbsID] = e.AbsID()
2909 revert()
2910
2911 }
2912 }
2913 }
2914
2915 var recurse func(ch2 *d2graph.Object)
2916 recurse = func(ch2 *d2graph.Object) {
2917 for _, ch2 := range ch2.ChildrenArray {
2918 appendNodeDelta(ch2)
2919 appendEdgeDelta(ch2)
2920 recurse(ch2)
2921 }
2922 }
2923
2924 appendNodeDelta(ch)
2925 appendEdgeDelta(ch)
2926 recurse(ch)
2927 }
2928 return deltas, nil
2929 }
2930
2931 func RenameIDDeltas(g *d2graph.Graph, boardPath []string, key, newName string) (deltas map[string]string, err error) {
2932 defer xdefer.Errorf(&err, "failed to get deltas for renaming of %#v to %#v", key, newName)
2933 deltas = make(map[string]string)
2934
2935 mk, err := d2parser.ParseMapKey(key)
2936 if err != nil {
2937 return nil, err
2938 }
2939
2940 boardG := g
2941 if len(boardPath) > 0 {
2942 boardG = GetBoardGraph(g, boardPath)
2943 if boardG == nil {
2944 return nil, fmt.Errorf("board %v not found", boardPath)
2945 }
2946 }
2947
2948 edgeTrimCommon(mk)
2949 obj := boardG.Root
2950 if mk.Key != nil {
2951 var ok bool
2952 obj, ok = boardG.Root.HasChild(d2graph.Key(mk.Key))
2953 if !ok {
2954 return nil, nil
2955 }
2956 }
2957 if len(mk.Edges) > 1 {
2958 return nil, nil
2959 }
2960 if len(mk.Edges) == 1 {
2961 mk2, err := d2parser.ParseMapKey(newName)
2962 if err != nil {
2963 return nil, err
2964 }
2965 if len(mk.Edges) == 0 {
2966 return nil, errors.New("cannot rename edge to node")
2967 }
2968 if len(mk.Edges) > 1 {
2969 return nil, errors.New("cannot rename edge to edge chain")
2970 }
2971
2972 e, ok := obj.HasEdge(mk)
2973 if !ok {
2974 return nil, nil
2975 }
2976 beforeID := e.AbsID()
2977 tmp := *e
2978 e2 := &tmp
2979 e2.SrcArrow = mk2.Edges[0].SrcArrow == "<"
2980 e2.DstArrow = mk2.Edges[0].DstArrow == ">"
2981 deltas[beforeID] = e2.AbsID()
2982 return deltas, nil
2983 }
2984
2985 if mk.Key.Path[len(mk.Key.Path)-1].Unbox().ScalarString() == newName {
2986 return deltas, nil
2987 }
2988
2989 mk.Key.Path[len(mk.Key.Path)-1].Unbox().SetString(newName)
2990 uniqueKeyStr, _, err := generateUniqueKey(boardG, strings.Join(d2graph.Key(mk.Key), "."), obj, nil)
2991 if err != nil {
2992 return nil, err
2993 }
2994 uniqueKey, err := d2parser.ParseKey(uniqueKeyStr)
2995 if err != nil {
2996 return nil, err
2997 }
2998 newNameKey := uniqueKey.Path[len(uniqueKey.Path)-1].Unbox().ScalarString()
2999 newNameKey = d2format.Format(d2ast.RawString(newNameKey, true))
3000
3001 beforeObjID := obj.ID
3002
3003 appendNodeDelta := func(ch *d2graph.Object) {
3004 if obj.ID != newNameKey {
3005 beforeID := ch.AbsID()
3006 obj.ID = newNameKey
3007 deltas[beforeID] = ch.AbsID()
3008 obj.ID = beforeObjID
3009 }
3010 }
3011
3012 appendEdgeDelta := func(ch *d2graph.Object) {
3013 for _, e := range obj.Graph.Edges {
3014 if e.Src == ch || e.Dst == ch {
3015 if obj.ID != newNameKey {
3016 beforeID := e.AbsID()
3017 obj.ID = newNameKey
3018 deltas[beforeID] = e.AbsID()
3019 obj.ID = beforeObjID
3020 }
3021 }
3022 }
3023 }
3024
3025 var recurse func(ch *d2graph.Object)
3026 recurse = func(ch *d2graph.Object) {
3027 for _, ch := range ch.ChildrenArray {
3028 appendNodeDelta(ch)
3029 appendEdgeDelta(ch)
3030 recurse(ch)
3031 }
3032 }
3033 appendNodeDelta(obj)
3034 appendEdgeDelta(obj)
3035 recurse(obj)
3036 return deltas, nil
3037 }
3038
3039 func hasSpace(tag string) bool {
3040 for _, r := range tag {
3041 if unicode.IsSpace(r) {
3042 return true
3043 }
3044 }
3045 return false
3046 }
3047
3048 func getMostNestedRefs(obj *d2graph.Object) []d2graph.Reference {
3049 var most d2graph.Reference
3050 for _, ref := range obj.References {
3051 if len(ref.MapKey.Edges) == 0 {
3052 most = ref
3053 break
3054 }
3055 }
3056 for _, ref := range obj.References {
3057 if len(ref.MapKey.Edges) != 0 {
3058 continue
3059 }
3060
3061 scopeKey, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
3062 if err != nil {
3063 scopeKey = &d2ast.KeyPath{}
3064 }
3065 mostKey, err := d2parser.ParseKey(most.ScopeObj.AbsID())
3066 if err != nil {
3067 mostKey = &d2ast.KeyPath{}
3068 }
3069 _, resolvedScopeKey, err := d2graph.ResolveUnderscoreKey(d2graph.Key(scopeKey), ref.ScopeObj)
3070 if err != nil {
3071 continue
3072 }
3073 _, resolvedMostKey, err := d2graph.ResolveUnderscoreKey(d2graph.Key(mostKey), ref.ScopeObj)
3074 if err != nil {
3075 continue
3076 }
3077 if len(resolvedScopeKey) > len(resolvedMostKey) {
3078 most = ref
3079 }
3080 }
3081
3082 var out []d2graph.Reference
3083 for _, ref := range obj.References {
3084 if len(ref.MapKey.Edges) != 0 {
3085 continue
3086 }
3087 if ref.ScopeObj.AbsID() == most.ScopeObj.AbsID() {
3088 out = append(out, ref)
3089 }
3090 }
3091
3092 return out
3093 }
3094
3095 func filterReservedPath(path []*d2ast.StringBox) (filtered []*d2ast.StringBox) {
3096 for _, box := range path {
3097 if _, ok := d2graph.ReservedKeywords[strings.ToLower(box.Unbox().ScalarString())]; ok {
3098 return
3099 }
3100 filtered = append(filtered, box)
3101 }
3102 return
3103 }
3104
3105 func getWriteableRefs(obj *d2graph.Object, writeableAST *d2ast.Map) (out []d2graph.Reference) {
3106 for i, ref := range obj.References {
3107 if ref.ScopeAST == writeableAST {
3108 out = append(out, obj.References[i])
3109 }
3110 }
3111 return
3112 }
3113
3114 func getWriteableEdgeRefs(edge *d2graph.Edge, writeableAST *d2ast.Map) (out []d2graph.EdgeReference) {
3115 for i, ref := range edge.References {
3116 if ref.ScopeAST == writeableAST {
3117 out = append(out, edge.References[i])
3118 }
3119 }
3120 return
3121 }
3122
View as plain text