Repository: uber-go/dig
Pull request #426 (2025-02-19 13:36:33)

Simplify spacing in dot graph generated by Visualize
This is a follow-up of https://github.com/uber-go/dig/pull/425 to clean up spacing in the `Visualize` function.
I kept the indentation so that the dot graph is still clear and readable.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ba9f9ae..ca64671 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 ## Unreleased
 - No changes yet.
 
+## [1.18.2] - 2025-05-08
+### Fixed
+- The exported Version string incorrectly containing "-dev".
+
+## [1.18.1] - 2025-03-03
+### Changed
+- Dot graph generation's internal implementation was changed so that
+  Go linker can successfully perform dead code elimination for Go apps
+  that use Dig.
+
+Thanks to @pgimalac for their contribution to this releaase.
+
+[1.18.1]: https://github.com/uber-go/dig/compare/v1.18.0...v1.18.1
+
 ## [1.18.0] - 2024-08-07
 ### Added
 - Child scope constructors are now visualized via `Visualize`
diff --git a/visualize.go b/visualize.go
index 162bbc5..17561f2 100644
--- a/visualize.go
+++ b/visualize.go
@@ -116,7 +116,6 @@ func visualizeGraph(w io.Writer, dg *dot.Graph) {
 	for _, g := range dg.Groups {
 		visualizeGroup(w, g)
 	}
-	w.Write([]byte("\t\n"))
 	for idx, c := range dg.Ctors {
 		visualizeCtor(w, idx, c)
 	}
@@ -126,46 +125,40 @@ func visualizeGraph(w io.Writer, dg *dot.Graph) {
 	for _, f := range dg.Failed.RootCauses {
 		fmt.Fprintf(w, "\t%s [color=red];\n", strconv.Quote(f.String()))
 	}
-	w.Write([]byte("\t\n}"))
+	w.Write([]byte("}"))
 }
 
 func visualizeGroup(w io.Writer, g *dot.Group) {
 	fmt.Fprintf(w, "\t%s [%s];\n", strconv.Quote(g.String()), g.Attributes())
 	for _, r := range g.Results {
-		fmt.Fprintf(w, "\t\t%s -> %s;\n", strconv.Quote(g.String()), strconv.Quote(r.String()))
+		fmt.Fprintf(w, "\t%s -> %s;\n", strconv.Quote(g.String()), strconv.Quote(r.String()))
 	}
-	w.Write([]byte("\t\t\n"))
 }
 
 func visualizeCtor(w io.Writer, index int, c *dot.Ctor) {
-	fmt.Fprintf(w, "\t\tsubgraph cluster_%d {\n", index)
-	w.Write([]byte("\t\t\t"))
+	fmt.Fprintf(w, "\tsubgraph cluster_%d {\n", index)
 	if c.Package != "" {
-		fmt.Fprintf(w, "label = %s;", strconv.Quote(c.Package))
+		fmt.Fprintf(w, "\t\tlabel = %s;\n", strconv.Quote(c.Package))
 	}
-	w.Write([]byte("\n"))
-	fmt.Fprintf(w, "\t\t\tconstructor_%d [shape=plaintext label=%s];\n", index, strconv.Quote(c.Name))
+	fmt.Fprintf(w, "\t\tconstructor_%d [shape=plaintext label=%s];\n", index, strconv.Quote(c.Name))
 
-	w.Write([]byte("\t\t\t"))
 	if c.ErrorType != 0 {
-		fmt.Fprintf(w, "color=%s;", c.ErrorType.Color())
+		fmt.Fprintf(w, "\t\tcolor=%s;\n", c.ErrorType.Color())
 	}
-	w.Write([]byte("\n"))
 	for _, r := range c.Results {
-		fmt.Fprintf(w, "\t\t\t%s [%s];\n", strconv.Quote(r.String()), r.Attributes())
+		fmt.Fprintf(w, "\t\t%s [%s];\n", strconv.Quote(r.String()), r.Attributes())
 	}
-	fmt.Fprintf(w, "\t\t\t\n\t\t}\n\t\t\n")
+	fmt.Fprintf(w, "\t}\n")
 	for _, p := range c.Params {
 		var optionalStyle string
 		if p.Optional {
 			optionalStyle = " style=dashed"
 		}
 
-		fmt.Fprintf(w, "\t\t\tconstructor_%d -> %s [ltail=cluster_%d%s];\n\t\t\n", index, strconv.Quote(p.String()), index, optionalStyle)
+		fmt.Fprintf(w, "\tconstructor_%d -> %s [ltail=cluster_%d%s];\n", index, strconv.Quote(p.String()), index, optionalStyle)
 	}
-	w.Write([]byte("\t\t\n"))
 	for _, p := range c.GroupParams {
-		fmt.Fprintf(w, "\t\t\tconstructor_%d -> %s [ltail=cluster_%d];\n\t\t\n", index, strconv.Quote(p.String()), index)
+		fmt.Fprintf(w, "\tconstructor_%d -> %s [ltail=cluster_%d];\n", index, strconv.Quote(p.String()), index)
 	}
 }
 


Test patch:
diff --git a/testdata/dig_as_two.dot b/testdata/dig_as_two.dot
index 27a2304..f6bd379 100644
--- a/testdata/dig_as_two.dot
+++ b/testdata/dig_as_two.dot
@@ -1,16 +1,10 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func4.1"];
-			
-			"io.Reader" [label=<io.Reader>];
-			"io.Writer" [label=<io.Writer>];
-			
-		}
-		
-		
-	
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func4.1"];
+		"io.Reader" [label=<io.Reader>];
+		"io.Writer" [label=<io.Writer>];
+	}
 }
\ No newline at end of file
diff --git a/testdata/empty.dot b/testdata/empty.dot
index bc3761d..54d7fa3 100644
--- a/testdata/empty.dot
+++ b/testdata/empty.dot
@@ -1,6 +1,4 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-	
 }
\ No newline at end of file
diff --git a/testdata/error.dot b/testdata/error.dot
index bdf24f7..ad93bbc 100644
--- a/testdata/error.dot
+++ b/testdata/error.dot
@@ -2,50 +2,34 @@ digraph {
 	rankdir=RL;
 	graph [compound=true];
 	"[type=dig_test.t1 group=g1]" [shape=diamond label=<dig_test.t1<BR /><FONT POINT-SIZE="10">Group: g1</FONT>> color=red];
-		"[type=dig_test.t1 group=g1]" -> "dig_test.t1[group=g1]0";
-		
+	"[type=dig_test.t1 group=g1]" -> "dig_test.t1[group=g1]0";
 	"[type=dig_test.t2 group=g2]" [shape=diamond label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>> color=orange];
-		"[type=dig_test.t2 group=g2]" -> "dig_test.t2[group=g2]0";
-		"[type=dig_test.t2 group=g2]" -> "dig_test.t2[group=g2]2";
-		
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func7.1"];
-			color=orange;
-			"dig_test.t3[name=n3]" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Name: n3</FONT>>];
-			"dig_test.t2[group=g2]0" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>>];
-			
-		}
-		
-		
-			constructor_0 -> "[type=dig_test.t1 group=g1]" [ltail=cluster_0];
-		
-		subgraph cluster_1 {
-			label = "go.uber.org/dig_test";
-			constructor_1 [shape=plaintext label="TestVisualize.func7.2"];
-			color=orange;
-			"dig_test.t4" [label=<dig_test.t4>];
-			
-		}
-		
-			constructor_1 -> "dig_test.t3[name=n3]" [ltail=cluster_1];
-		
-		
-			constructor_1 -> "[type=dig_test.t2 group=g2]" [ltail=cluster_1];
-		
-		subgraph cluster_2 {
-			label = "go.uber.org/dig_test";
-			constructor_2 [shape=plaintext label="TestVisualize.func7.4"];
-			color=red;
-			"dig_test.t1[group=g1]0" [label=<dig_test.t1<BR /><FONT POINT-SIZE="10">Group: g1</FONT>>];
-			"dig_test.t2[group=g2]2" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>>];
-			
-		}
-		
-		
+	"[type=dig_test.t2 group=g2]" -> "dig_test.t2[group=g2]0";
+	"[type=dig_test.t2 group=g2]" -> "dig_test.t2[group=g2]2";
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func7.1"];
+		color=orange;
+		"dig_test.t3[name=n3]" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Name: n3</FONT>>];
+		"dig_test.t2[group=g2]0" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>>];
+	}
+	constructor_0 -> "[type=dig_test.t1 group=g1]" [ltail=cluster_0];
+	subgraph cluster_1 {
+		label = "go.uber.org/dig_test";
+		constructor_1 [shape=plaintext label="TestVisualize.func7.2"];
+		color=orange;
+		"dig_test.t4" [label=<dig_test.t4>];
+	}
+	constructor_1 -> "dig_test.t3[name=n3]" [ltail=cluster_1];
+	constructor_1 -> "[type=dig_test.t2 group=g2]" [ltail=cluster_1];
+	subgraph cluster_2 {
+		label = "go.uber.org/dig_test";
+		constructor_2 [shape=plaintext label="TestVisualize.func7.4"];
+		color=red;
+		"dig_test.t1[group=g1]0" [label=<dig_test.t1<BR /><FONT POINT-SIZE="10">Group: g1</FONT>>];
+		"dig_test.t2[group=g2]2" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>>];
+	}
 	"dig_test.t2[group=g2]0" [color=orange];
 	"dig_test.t4" [color=orange];
 	"dig_test.t1[group=g1]0" [color=red];
-	
 }
\ No newline at end of file
diff --git a/testdata/grouped.dot b/testdata/grouped.dot
index 73a0a70..e23ed71 100644
--- a/testdata/grouped.dot
+++ b/testdata/grouped.dot
@@ -2,38 +2,22 @@ digraph {
 	rankdir=RL;
 	graph [compound=true];
 	"[type=dig_test.t3 group=foo]" [shape=diamond label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Group: foo</FONT>>];
-		"[type=dig_test.t3 group=foo]" -> "dig_test.t3[group=foo]0";
-		"[type=dig_test.t3 group=foo]" -> "dig_test.t3[group=foo]1";
-		
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func6.1"];
-			
-			"dig_test.t3[group=foo]0" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Group: foo</FONT>>];
-			
-		}
-		
-		
-		subgraph cluster_1 {
-			label = "go.uber.org/dig_test";
-			constructor_1 [shape=plaintext label="TestVisualize.func6.2"];
-			
-			"dig_test.t3[group=foo]1" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Group: foo</FONT>>];
-			
-		}
-		
-		
-		subgraph cluster_2 {
-			label = "go.uber.org/dig_test";
-			constructor_2 [shape=plaintext label="TestVisualize.func6.3"];
-			
-			"dig_test.t2" [label=<dig_test.t2>];
-			
-		}
-		
-		
-			constructor_2 -> "[type=dig_test.t3 group=foo]" [ltail=cluster_2];
-		
-	
+	"[type=dig_test.t3 group=foo]" -> "dig_test.t3[group=foo]0";
+	"[type=dig_test.t3 group=foo]" -> "dig_test.t3[group=foo]1";
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func6.1"];
+		"dig_test.t3[group=foo]0" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Group: foo</FONT>>];
+	}
+	subgraph cluster_1 {
+		label = "go.uber.org/dig_test";
+		constructor_1 [shape=plaintext label="TestVisualize.func6.2"];
+		"dig_test.t3[group=foo]1" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Group: foo</FONT>>];
+	}
+	subgraph cluster_2 {
+		label = "go.uber.org/dig_test";
+		constructor_2 [shape=plaintext label="TestVisualize.func6.3"];
+		"dig_test.t2" [label=<dig_test.t2>];
+	}
+	constructor_2 -> "[type=dig_test.t3 group=foo]" [ltail=cluster_2];
 }
\ No newline at end of file
diff --git a/testdata/missing.dot b/testdata/missing.dot
index e91d6f5..5af7b8e 100644
--- a/testdata/missing.dot
+++ b/testdata/missing.dot
@@ -1,25 +1,17 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func8.1"];
-			color=orange;
-			"dig_test.t4" [label=<dig_test.t4>];
-			
-		}
-		
-			constructor_0 -> "dig_test.t1" [ltail=cluster_0];
-		
-			constructor_0 -> "dig_test.t2" [ltail=cluster_0];
-		
-			constructor_0 -> "dig_test.t3" [ltail=cluster_0];
-		
-		
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func8.1"];
+		color=orange;
+		"dig_test.t4" [label=<dig_test.t4>];
+	}
+	constructor_0 -> "dig_test.t1" [ltail=cluster_0];
+	constructor_0 -> "dig_test.t2" [ltail=cluster_0];
+	constructor_0 -> "dig_test.t3" [ltail=cluster_0];
 	"dig_test.t4" [color=orange];
 	"dig_test.t1" [color=red];
 	"dig_test.t2" [color=red];
 	"dig_test.t3" [color=red];
-	
 }
\ No newline at end of file
diff --git a/testdata/missingDep.dot b/testdata/missingDep.dot
index 1c884a8..49787ec 100644
--- a/testdata/missingDep.dot
+++ b/testdata/missingDep.dot
@@ -1,7 +1,5 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
 	"dig_test.t1" [color=red];
-	
 }
\ No newline at end of file
diff --git a/testdata/named.dot b/testdata/named.dot
index 99f2f1b..5b811d3 100644
--- a/testdata/named.dot
+++ b/testdata/named.dot
@@ -1,27 +1,16 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func3.1"];
-			
-			"dig_test.t1[name=bar]" [label=<dig_test.t1<BR /><FONT POINT-SIZE="10">Name: bar</FONT>>];
-			"dig_test.t2[name=baz]" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Name: baz</FONT>>];
-			
-		}
-		
-			constructor_0 -> "dig_test.t3[name=foo]" [ltail=cluster_0];
-		
-		
-		subgraph cluster_1 {
-			label = "go.uber.org/dig_test";
-			constructor_1 [shape=plaintext label="TestVisualize.func3.2"];
-			
-			"dig_test.t3[name=foo]" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Name: foo</FONT>>];
-			
-		}
-		
-		
-	
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func3.1"];
+		"dig_test.t1[name=bar]" [label=<dig_test.t1<BR /><FONT POINT-SIZE="10">Name: bar</FONT>>];
+		"dig_test.t2[name=baz]" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Name: baz</FONT>>];
+	}
+	constructor_0 -> "dig_test.t3[name=foo]" [ltail=cluster_0];
+	subgraph cluster_1 {
+		label = "go.uber.org/dig_test";
+		constructor_1 [shape=plaintext label="TestVisualize.func3.2"];
+		"dig_test.t3[name=foo]" [label=<dig_test.t3<BR /><FONT POINT-SIZE="10">Name: foo</FONT>>];
+	}
 }
\ No newline at end of file
diff --git a/testdata/optional.dot b/testdata/optional.dot
index 15aa9d0..011639c 100644
--- a/testdata/optional.dot
+++ b/testdata/optional.dot
@@ -1,26 +1,15 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func5.1"];
-			
-			"dig_test.t1" [label=<dig_test.t1>];
-			
-		}
-		
-		
-		subgraph cluster_1 {
-			label = "go.uber.org/dig_test";
-			constructor_1 [shape=plaintext label="TestVisualize.func5.2"];
-			
-			"dig_test.t2" [label=<dig_test.t2>];
-			
-		}
-		
-			constructor_1 -> "dig_test.t1" [ltail=cluster_1 style=dashed];
-		
-		
-	
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func5.1"];
+		"dig_test.t1" [label=<dig_test.t1>];
+	}
+	subgraph cluster_1 {
+		label = "go.uber.org/dig_test";
+		constructor_1 [shape=plaintext label="TestVisualize.func5.2"];
+		"dig_test.t2" [label=<dig_test.t2>];
+	}
+	constructor_1 -> "dig_test.t1" [ltail=cluster_1 style=dashed];
 }
\ No newline at end of file
diff --git a/testdata/prune_constructor_result.dot b/testdata/prune_constructor_result.dot
index f1b058d..0d41fbf 100644
--- a/testdata/prune_constructor_result.dot
+++ b/testdata/prune_constructor_result.dot
@@ -2,30 +2,20 @@ digraph {
 	rankdir=RL;
 	graph [compound=true];
 	"[type=dig_test.t2 group=g2]" [shape=diamond label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>> color=red];
-		"[type=dig_test.t2 group=g2]" -> "dig_test.t2[group=g2]1";
-		
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func7.6.1.2"];
-			color=orange;
-			"dig_test.t4" [label=<dig_test.t4>];
-			
-		}
-		
-		
-			constructor_0 -> "[type=dig_test.t2 group=g2]" [ltail=cluster_0];
-		
-		subgraph cluster_1 {
-			label = "go.uber.org/dig_test";
-			constructor_1 [shape=plaintext label="TestVisualize.func7.6.1.3"];
-			color=red;
-			"dig_test.t2[group=g2]1" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>>];
-			
-		}
-		
-		
+	"[type=dig_test.t2 group=g2]" -> "dig_test.t2[group=g2]1";
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func7.6.1.2"];
+		color=orange;
+		"dig_test.t4" [label=<dig_test.t4>];
+	}
+	constructor_0 -> "[type=dig_test.t2 group=g2]" [ltail=cluster_0];
+	subgraph cluster_1 {
+		label = "go.uber.org/dig_test";
+		constructor_1 [shape=plaintext label="TestVisualize.func7.6.1.3"];
+		color=red;
+		"dig_test.t2[group=g2]1" [label=<dig_test.t2<BR /><FONT POINT-SIZE="10">Group: g2</FONT>>];
+	}
 	"dig_test.t4" [color=orange];
 	"dig_test.t2[group=g2]1" [color=red];
-	
 }
\ No newline at end of file
diff --git a/testdata/prune_non_root_nodes.dot b/testdata/prune_non_root_nodes.dot
index a85144d..e954ca8 100644
--- a/testdata/prune_non_root_nodes.dot
+++ b/testdata/prune_non_root_nodes.dot
@@ -1,16 +1,11 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func7.6.2.2"];
-			color=red;
-			"dig_test.t4" [label=<dig_test.t4>];
-			
-		}
-		
-		
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func7.6.2.2"];
+		color=red;
+		"dig_test.t4" [label=<dig_test.t4>];
+	}
 	"dig_test.t4" [color=red];
-	
 }
\ No newline at end of file
diff --git a/testdata/simple.dot b/testdata/simple.dot
index bc33c97..c35c451 100644
--- a/testdata/simple.dot
+++ b/testdata/simple.dot
@@ -1,30 +1,18 @@
 digraph {
 	rankdir=RL;
 	graph [compound=true];
-	
-		subgraph cluster_0 {
-			label = "go.uber.org/dig_test";
-			constructor_0 [shape=plaintext label="TestVisualize.func2.1"];
-			
-			"dig_test.t1" [label=<dig_test.t1>];
-			"dig_test.t2" [label=<dig_test.t2>];
-			
-		}
-		
-		
-		subgraph cluster_1 {
-			label = "go.uber.org/dig_test";
-			constructor_1 [shape=plaintext label="TestVisualize.func2.2"];
-			
-			"dig_test.t3" [label=<dig_test.t3>];
-			"dig_test.t4" [label=<dig_test.t4>];
-			
-		}
-		
-			constructor_1 -> "dig_test.t1" [ltail=cluster_1];
-		
-			constructor_1 -> "dig_test.t2" [ltail=cluster_1];
-		
-		
-	
+	subgraph cluster_0 {
+		label = "go.uber.org/dig_test";
+		constructor_0 [shape=plaintext label="TestVisualize.func2.1"];
+		"dig_test.t1" [label=<dig_test.t1>];
+		"dig_test.t2" [label=<dig_test.t2>];
+	}
+	subgraph cluster_1 {
+		label = "go.uber.org/dig_test";
+		constructor_1 [shape=plaintext label="TestVisualize.func2.2"];
+		"dig_test.t3" [label=<dig_test.t3>];
+		"dig_test.t4" [label=<dig_test.t4>];
+	}
+	constructor_1 -> "dig_test.t1" [ltail=cluster_1];
+	constructor_1 -> "dig_test.t2" [ltail=cluster_1];
 }
\ No newline at end of file