diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index b88e5e6b9..66ae6c8f3 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -6,9 +6,7 @@ import ( "encoding/json" "fmt" "math" - "regexp" "sort" - "strconv" "strings" "cdr.dev/slog" @@ -412,59 +410,6 @@ func setGraphAttrs(attrs dagreOpts) string { ) } -type objectMapper struct { - objToID map[*d2graph.Object]string - idToObj map[string]*d2graph.Object -} - -func NewObjectMapper() *objectMapper { - return &objectMapper{ - objToID: make(map[*d2graph.Object]string), - idToObj: make(map[string]*d2graph.Object), - } -} - -func (c *objectMapper) Register(obj *d2graph.Object) { - id := strconv.Itoa(len(c.idToObj)) - c.idToObj[id] = obj - c.objToID[obj] = id -} - -func (c *objectMapper) ToID(obj *d2graph.Object) string { - return c.objToID[obj] -} - -func (c *objectMapper) ToObj(id string) *d2graph.Object { - return c.idToObj[id] -} - -func escapeID(id string) string { - // fixes \\ - id = strings.ReplaceAll(id, "\\", `\\`) - // replaces \n with \\n whenever \n is not preceded by \ (does not replace \\n) - re := regexp.MustCompile(`[^\\]\n`) - id = re.ReplaceAllString(id, `\\n`) - // avoid an unescaped \r becoming a \n in the layout result - id = strings.ReplaceAll(id, "\r", `\r`) - return id -} - -func (c objectMapper) generateAddNodeLine(obj *d2graph.Object, width, height int) string { - id := c.ToID(obj) - return fmt.Sprintf("g.setNode(`%s`, { id: `%s`, width: %d, height: %d });\n", id, id, width, height) -} - -func (c objectMapper) generateAddParentLine(child, parent *d2graph.Object) string { - return fmt.Sprintf("g.setParent(`%s`, `%s`);\n", c.ToID(child), c.ToID(parent)) -} - -func (c objectMapper) generateAddEdgeLine(from, to *d2graph.Object, edgeID string, width, height int) string { - return fmt.Sprintf( - "g.setEdge({v:`%s`, w:`%s`, name:`%s`}, { width:%d, height:%d, labelpos: `c` });\n", - c.ToID(from), c.ToID(to), escapeID(edgeID), width, height, - ) -} - // getLongestEdgeChainHead finds the longest chain in a container and gets its head // If there are multiple chains of the same length, get the head closest to the center func getLongestEdgeChainHead(g *d2graph.Graph, container *d2graph.Object) *d2graph.Object { diff --git a/d2layouts/d2dagrelayout/object_mapper.go b/d2layouts/d2dagrelayout/object_mapper.go new file mode 100644 index 000000000..6ac2b637e --- /dev/null +++ b/d2layouts/d2dagrelayout/object_mapper.go @@ -0,0 +1,63 @@ +package d2dagrelayout + +import ( + "fmt" + "regexp" + "strconv" + "strings" + + "oss.terrastruct.com/d2/d2graph" +) + +type objectMapper struct { + objToID map[*d2graph.Object]string + idToObj map[string]*d2graph.Object +} + +func NewObjectMapper() *objectMapper { + return &objectMapper{ + objToID: make(map[*d2graph.Object]string), + idToObj: make(map[string]*d2graph.Object), + } +} + +func (c *objectMapper) Register(obj *d2graph.Object) { + id := strconv.Itoa(len(c.idToObj)) + c.idToObj[id] = obj + c.objToID[obj] = id +} + +func (c *objectMapper) ToID(obj *d2graph.Object) string { + return c.objToID[obj] +} + +func (c *objectMapper) ToObj(id string) *d2graph.Object { + return c.idToObj[id] +} + +func (c objectMapper) generateAddNodeLine(obj *d2graph.Object, width, height int) string { + id := c.ToID(obj) + return fmt.Sprintf("g.setNode(`%s`, { id: `%s`, width: %d, height: %d });\n", id, id, width, height) +} + +func (c objectMapper) generateAddParentLine(child, parent *d2graph.Object) string { + return fmt.Sprintf("g.setParent(`%s`, `%s`);\n", c.ToID(child), c.ToID(parent)) +} + +func (c objectMapper) generateAddEdgeLine(from, to *d2graph.Object, edgeID string, width, height int) string { + return fmt.Sprintf( + "g.setEdge({v:`%s`, w:`%s`, name:`%s`}, { width:%d, height:%d, labelpos: `c` });\n", + c.ToID(from), c.ToID(to), escapeID(edgeID), width, height, + ) +} + +func escapeID(id string) string { + // fixes \\ + id = strings.ReplaceAll(id, "\\", `\\`) + // replaces \n with \\n whenever \n is not preceded by \ (does not replace \\n) + re := regexp.MustCompile(`[^\\]\n`) + id = re.ReplaceAllString(id, `\\n`) + // avoid an unescaped \r becoming a \n in the layout result + id = strings.ReplaceAll(id, "\r", `\r`) + return id +}