diff --git a/d2chaos/d2chaos.go b/d2chaos/d2chaos.go index c6cf4937c..7729454a8 100644 --- a/d2chaos/d2chaos.go +++ b/d2chaos/d2chaos.go @@ -17,9 +17,10 @@ import ( func GenDSL(maxi int) (_ string, err error) { gs := &dslGenState{ - rand: mathrand.New(mathrand.NewSource(time.Now().UnixNano())), - g: d2graph.NewGraph(&d2ast.Map{}), - nodeShapes: make(map[string]string), + rand: mathrand.New(mathrand.NewSource(time.Now().UnixNano())), + g: d2graph.NewGraph(&d2ast.Map{}), + nodeShapes: make(map[string]string), + nodeContainer: make(map[string]string), } err = gs.gen(maxi) if err != nil { @@ -32,8 +33,9 @@ type dslGenState struct { rand *mathrand.Rand g *d2graph.Graph - nodesArr []string - nodeShapes map[string]string + nodesArr []string + nodeShapes map[string]string + nodeContainer map[string]string } func (gs *dslGenState) gen(maxi int) error { @@ -70,6 +72,7 @@ func (gs *dslGenState) genNode(containerID string) (string, error) { } gs.nodesArr = append(gs.nodesArr, nodeID) gs.nodeShapes[nodeID] = "square" + gs.nodeContainer[nodeID] = containerID return nodeID, nil } @@ -123,7 +126,7 @@ func (gs *dslGenState) edge() error { if err != nil { return err } - if src != dst { + if gs.findOuterSequenceDiagram(src) == gs.findOuterSequenceDiagram(dst) { break } err = gs.node() @@ -194,6 +197,16 @@ func randRune() rune { return mathrand.Int31n(128) + 1 } +func (gs *dslGenState) findOuterSequenceDiagram(nodeID string) string { + for { + containerID := gs.nodeContainer[nodeID] + if containerID == "" || gs.nodeShapes[containerID] == d2target.ShapeSequenceDiagram { + return containerID + } + nodeID = containerID + } +} + func String(n int, exclude []rune) string { var b strings.Builder for i := 0; i < n; i++ { @@ -233,10 +246,7 @@ func (gs *dslGenState) randStr(n int, inKey bool) string { func (gs *dslGenState) randShape() string { for { s := shapes[gs.rand.Intn(len(shapes))] - if s != "image" { - return s - } - if s != "sequence_diagram" { + if s != d2target.ShapeImage { return s } } diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index def678ee0..e1d29175e 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "math" + "regexp" "strings" "cdr.dev/slog" @@ -257,7 +258,11 @@ func setGraphAttrs(attrs dagreGraphAttrs) string { } func escapeID(id string) string { - id = strings.ReplaceAll(id, `\n`, `\\n`) + // 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 diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go index 8170bc359..373ee5acd 100644 --- a/e2etests/regression_test.go +++ b/e2etests/regression_test.go @@ -7,11 +7,14 @@ import ( func testRegression(t *testing.T) { tcs := []testCase{ { - name: "dagre_id_with_newline", + name: "dagre_special_ids", script: ` ninety\nnine eighty\reight seventy\r\nseven +a\\yode -> there +a\\"ode -> there +a\\node -> there `, }, { diff --git a/e2etests/testdata/regression/dagre_id_with_newline/dagre/board.exp.json b/e2etests/testdata/regression/dagre_id_with_newline/dagre/board.exp.json deleted file mode 100644 index 83a5c2112..000000000 --- a/e2etests/testdata/regression/dagre_id_with_newline/dagre/board.exp.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "name": "", - "shapes": [ - { - "id": "\"ninety\\nnine\"", - "type": "", - "pos": { - "x": 0, - "y": 0 - }, - "width": 151, - "height": 142, - "opacity": 1, - "strokeDash": 0, - "strokeWidth": 2, - "borderRadius": 0, - "fill": "#F7F8FE", - "stroke": "#0D32B2", - "shadow": false, - "3d": false, - "multiple": false, - "tooltip": "", - "link": "", - "icon": null, - "iconPosition": "", - "blend": false, - "fields": null, - "methods": null, - "columns": null, - "label": "ninety\nnine", - "fontSize": 16, - "fontFamily": "DEFAULT", - "language": "", - "color": "#0A0F25", - "italic": false, - "bold": true, - "underline": false, - "labelWidth": 51, - "labelHeight": 42, - "labelPosition": "INSIDE_MIDDLE_CENTER", - "zIndex": 0, - "level": 1 - }, - { - "id": "eighty\reight", - "type": "", - "pos": { - "x": 211, - "y": 8 - }, - "width": 151, - "height": 126, - "opacity": 1, - "strokeDash": 0, - "strokeWidth": 2, - "borderRadius": 0, - "fill": "#F7F8FE", - "stroke": "#0D32B2", - "shadow": false, - "3d": false, - "multiple": false, - "tooltip": "", - "link": "", - "icon": null, - "iconPosition": "", - "blend": false, - "fields": null, - "methods": null, - "columns": null, - "label": "eighty\reight", - "fontSize": 16, - "fontFamily": "DEFAULT", - "language": "", - "color": "#0A0F25", - "italic": false, - "bold": true, - "underline": false, - "labelWidth": 51, - "labelHeight": 26, - "labelPosition": "INSIDE_MIDDLE_CENTER", - "zIndex": 0, - "level": 1 - }, - { - "id": "\"seventy\r\\nseven\"", - "type": "", - "pos": { - "x": 422, - "y": 0 - }, - "width": 162, - "height": 142, - "opacity": 1, - "strokeDash": 0, - "strokeWidth": 2, - "borderRadius": 0, - "fill": "#F7F8FE", - "stroke": "#0D32B2", - "shadow": false, - "3d": false, - "multiple": false, - "tooltip": "", - "link": "", - "icon": null, - "iconPosition": "", - "blend": false, - "fields": null, - "methods": null, - "columns": null, - "label": "seventy\r\nseven", - "fontSize": 16, - "fontFamily": "DEFAULT", - "language": "", - "color": "#0A0F25", - "italic": false, - "bold": true, - "underline": false, - "labelWidth": 62, - "labelHeight": 42, - "labelPosition": "INSIDE_MIDDLE_CENTER", - "zIndex": 0, - "level": 1 - } - ], - "connections": [] -} diff --git a/e2etests/testdata/regression/dagre_id_with_newline/elk/board.exp.json b/e2etests/testdata/regression/dagre_id_with_newline/elk/board.exp.json deleted file mode 100644 index 16a7fb9d5..000000000 --- a/e2etests/testdata/regression/dagre_id_with_newline/elk/board.exp.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "name": "", - "shapes": [ - { - "id": "\"ninety\\nnine\"", - "type": "", - "pos": { - "x": 194, - "y": 12 - }, - "width": 151, - "height": 142, - "opacity": 1, - "strokeDash": 0, - "strokeWidth": 2, - "borderRadius": 0, - "fill": "#F7F8FE", - "stroke": "#0D32B2", - "shadow": false, - "3d": false, - "multiple": false, - "tooltip": "", - "link": "", - "icon": null, - "iconPosition": "", - "blend": false, - "fields": null, - "methods": null, - "columns": null, - "label": "ninety\nnine", - "fontSize": 16, - "fontFamily": "DEFAULT", - "language": "", - "color": "#0A0F25", - "italic": false, - "bold": true, - "underline": false, - "labelWidth": 51, - "labelHeight": 42, - "labelPosition": "INSIDE_MIDDLE_CENTER", - "zIndex": 0, - "level": 1 - }, - { - "id": "eighty\reight", - "type": "", - "pos": { - "x": 365, - "y": 20 - }, - "width": 151, - "height": 126, - "opacity": 1, - "strokeDash": 0, - "strokeWidth": 2, - "borderRadius": 0, - "fill": "#F7F8FE", - "stroke": "#0D32B2", - "shadow": false, - "3d": false, - "multiple": false, - "tooltip": "", - "link": "", - "icon": null, - "iconPosition": "", - "blend": false, - "fields": null, - "methods": null, - "columns": null, - "label": "eighty\reight", - "fontSize": 16, - "fontFamily": "DEFAULT", - "language": "", - "color": "#0A0F25", - "italic": false, - "bold": true, - "underline": false, - "labelWidth": 51, - "labelHeight": 26, - "labelPosition": "INSIDE_MIDDLE_CENTER", - "zIndex": 0, - "level": 1 - }, - { - "id": "\"seventy\r\\nseven\"", - "type": "", - "pos": { - "x": 12, - "y": 12 - }, - "width": 162, - "height": 142, - "opacity": 1, - "strokeDash": 0, - "strokeWidth": 2, - "borderRadius": 0, - "fill": "#F7F8FE", - "stroke": "#0D32B2", - "shadow": false, - "3d": false, - "multiple": false, - "tooltip": "", - "link": "", - "icon": null, - "iconPosition": "", - "blend": false, - "fields": null, - "methods": null, - "columns": null, - "label": "seventy\r\nseven", - "fontSize": 16, - "fontFamily": "DEFAULT", - "language": "", - "color": "#0A0F25", - "italic": false, - "bold": true, - "underline": false, - "labelWidth": 62, - "labelHeight": 42, - "labelPosition": "INSIDE_MIDDLE_CENTER", - "zIndex": 0, - "level": 1 - } - ], - "connections": [] -} diff --git a/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json b/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json new file mode 100644 index 000000000..3684ac8af --- /dev/null +++ b/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json @@ -0,0 +1,431 @@ +{ + "name": "", + "shapes": [ + { + "id": "\"ninety\\nnine\"", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 151, + "height": 142, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ninety\nnine", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 51, + "labelHeight": 42, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "eighty\reight", + "type": "", + "pos": { + "x": 211, + "y": 8 + }, + "width": 151, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "eighty\reight", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 51, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "\"seventy\r\\nseven\"", + "type": "", + "pos": { + "x": 422, + "y": 0 + }, + "width": 162, + "height": 142, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "seventy\r\nseven", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 62, + "labelHeight": 42, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "\"a\\\\yode\"", + "type": "", + "pos": { + "x": 644, + "y": 8 + }, + "width": 154, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a\\yode", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 54, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "there", + "type": "", + "pos": { + "x": 864, + "y": 242 + }, + "width": 143, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "there", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 43, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "'a\\\"ode'", + "type": "", + "pos": { + "x": 858, + "y": 8 + }, + "width": 154, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a\\\"ode", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 54, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "\"a\\\\node\"", + "type": "", + "pos": { + "x": 1072, + "y": 8 + }, + "width": 155, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a\\node", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 55, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(\"a\\\\yode\" -> there)[0]", + "src": "\"a\\\\yode\"", + "srcArrow": "none", + "srcLabel": "", + "dst": "there", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 721, + "y": 134 + }, + { + "x": 721, + "y": 180.4 + }, + { + "x": 749.5, + "y": 207.04906542056074 + }, + { + "x": 863.5, + "y": 267.24532710280374 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "('a\\\"ode' -> there)[0]", + "src": "'a\\\"ode'", + "srcArrow": "none", + "srcLabel": "", + "dst": "there", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 935, + "y": 134 + }, + { + "x": 935, + "y": 180.4 + }, + { + "x": 935, + "y": 202 + }, + { + "x": 935, + "y": 242 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(\"a\\\\node\" -> there)[0]", + "src": "\"a\\\\node\"", + "srcArrow": "none", + "srcLabel": "", + "dst": "there", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1149.5, + "y": 134 + }, + { + "x": 1149.5, + "y": 180.4 + }, + { + "x": 1120.9, + "y": 207 + }, + { + "x": 1006.5, + "y": 267 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/dagre_id_with_newline/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg similarity index 99% rename from e2etests/testdata/regression/dagre_id_with_newline/dagre/sketch.exp.svg rename to e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg index 89f85e41d..1fcf71c22 100644 --- a/e2etests/testdata/regression/dagre_id_with_newline/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg @@ -2,7 +2,7 @@