diff --git a/dixhttp/README.md b/dixhttp/README.md
index adf7cd9..3e679f7 100644
--- a/dixhttp/README.md
+++ b/dixhttp/README.md
@@ -12,7 +12,11 @@ This module provides an HTTP server to visualize dependency relationships in the
- 🔄 **Bidirectional Dependency Tracking** - Show both upstream (dependencies) and downstream (dependents)
- 📏 **Depth Control** - Limit dependency graph display levels (1-5 or all)
- 🎨 **Multiple Layouts** - Support hierarchical and force-directed layouts
+- 🧩 **Group Rules (Prefix Aggregation)** - Aggregate nodes by package/prefix rules
+- 🔎 **Prefix Filter** - Show only nodes/providers matching a prefix
+- 🧭 **Group Subgraph** - View a group's internal + upstream/downstream dependencies
- 📡 **RESTful API** - Provide JSON format dependency data
+- 🧩 **Mermaid Export/Preview** - Generate Mermaid flowcharts for current graph (respects grouping/filtering)
## Quick Start
@@ -54,6 +58,18 @@ func main() {
Open browser and visit `http://localhost:8080` to view the dependency graph.
+### Base Path / Prefix
+
+If you need to mount the UI and API under a path prefix (e.g. behind a gateway), use `WithBasePath`:
+
+```go
+server := dixhttp.NewServerWithOptions(
+ (*dixinternal.Dix)(di),
+ dixhttp.WithBasePath("/dix"),
+)
+// Visit http://localhost:8080/dix/
+```
+
## UI Layout
```
@@ -143,6 +159,52 @@ Search `UserService` with different depths:
- Depth 1: `Database ← UserService → Handler`
- Depth 2: `Config ← Database ← UserService → Handler`
+### 🧩 Group Rules (Prefix Aggregation)
+
+You can aggregate nodes by **package or prefix** using group rules. Rules can be configured:
+
+- **In UI** (group list)
+- **From backend** via `RegisterGroupRules` (recommended for production)
+
+Backend registration:
+
+```go
+import "github.com/pubgo/dix/v2/dixhttp"
+
+dixhttp.RegisterGroupRules(
+ dixhttp.GroupRule{
+ Name: "service",
+ Prefixes: []string{
+ "github.com/acme/app/service",
+ "github.com/acme/app/internal/service",
+ },
+ },
+ dixhttp.GroupRule{
+ Name: "router",
+ Prefixes: []string{"github.com/acme/app/router"},
+ },
+)
+```
+
+The UI will auto-load `/api/group-rules` if local rules are empty.
+
+### 🔎 Prefix Filter
+
+The toolbar provides a **Prefix Filter** field. It filters the current graph to show only nodes/providers
+whose package/type/function name contains the given prefix. This works in:
+
+- Providers/Types view
+- Type-focused dependency view
+- Group subgraph view
+
+### 🧭 Group Subgraph
+
+Click a virtual group node to open the **group detail panel**, then click **View group graph** to see:
+
+- Internal nodes
+- Upstream & downstream dependencies
+- Depth control applied from the toolbar
+
### 📦 Package Grouping
Left panel features:
@@ -161,6 +223,15 @@ Left panel features:
| **Scroll Zoom** | Zoom in/out graph |
| **Click Type in Details** | Jump to view that type's dependencies |
+## Mermaid Support
+
+The toolbar includes a **Mermaid** button. It generates a Mermaid `flowchart` from the **current graph view** (including grouping, depth, and prefix filters), opens a preview modal, and lets you copy the Mermaid source.
+
+**Typical usage**:
+1. Adjust view / grouping / filters.
+2. Click **Mermaid**.
+3. Copy the generated Mermaid text or use the preview.
+
## API Endpoints
### GET `/`
@@ -200,8 +271,11 @@ Returns dependency data, supports package filtering
{
"id": "provider_*main.ServiceA_0",
"output_type": "*main.ServiceA",
+ "output_pkg": "github.com/example/app/service",
"function_name": "main.NewServiceA",
- "input_types": ["*main.Config"]
+ "function_pkg": "github.com/example/app",
+ "input_types": ["*main.Config"],
+ "input_pkgs": ["github.com/example/app/config"]
}
],
"objects": [...],
@@ -226,6 +300,15 @@ Returns dependency chain for specified type
{"from": "*db.Database", "to": "*service.UserService", "type": "dependency"}
]
}
+
+### GET `/api/group-rules`
+Returns backend-registered group rules (used as UI defaults)
+
+```json
+[
+ {"name": "service", "prefixes": ["github.com/acme/app/service"]}
+]
+```
```
## Tech Stack
diff --git a/dixhttp/README_zh.md b/dixhttp/README_zh.md
index e3e709b..228133f 100644
--- a/dixhttp/README_zh.md
+++ b/dixhttp/README_zh.md
@@ -12,7 +12,11 @@
- 🔄 **双向依赖追踪** - 同时展示依赖(上游)和被依赖(下游)关系
- 📏 **深度控制** - 限制依赖图的展示层级(1-5级或全部)
- 🎨 **多种布局** - 支持层级布局和力导向布局
+- 🧩 **分组清单(前缀聚合)** - 通过包路径/前缀聚合节点
+- 🔎 **前缀过滤** - 只显示匹配前缀的节点/Provider
+- 🧭 **组内子图** - 查看组内及上下游依赖
- 📡 **RESTful API** - 提供 JSON 格式的依赖关系数据
+- 🧩 **Mermaid 预览/导出** - 将当前图生成 Mermaid 流程图(支持分组/过滤)
## 快速开始
@@ -54,6 +58,18 @@ func main() {
打开浏览器访问 `http://localhost:8080` 即可查看依赖关系图。
+### 配置访问前缀
+
+如果需要将页面和 API 挂载到一个前缀路径(例如网关转发),可以使用 `WithBasePath`:
+
+```go
+server := dixhttp.NewServerWithOptions(
+ (*dixinternal.Dix)(di),
+ dixhttp.WithBasePath("/dix"),
+)
+// 访问 http://localhost:8080/dix/
+```
+
## 界面布局
```
@@ -143,6 +159,51 @@ func main() {
- 深度 1: `Database ← UserService → Handler`
- 深度 2: `Config ← Database ← UserService → Handler`
+### 🧩 分组清单(前缀聚合)
+
+支持通过**包路径/前缀**聚合节点,规则来源:
+
+- **前端分组清单**
+- **后端全局注册**(推荐生产使用)
+
+后端注册示例:
+
+```go
+import "github.com/pubgo/dix/v2/dixhttp"
+
+dixhttp.RegisterGroupRules(
+ dixhttp.GroupRule{
+ Name: "service",
+ Prefixes: []string{
+ "github.com/acme/app/service",
+ "github.com/acme/app/internal/service",
+ },
+ },
+ dixhttp.GroupRule{
+ Name: "router",
+ Prefixes: []string{"github.com/acme/app/router"},
+ },
+)
+```
+
+当本地未配置分组清单时,前端会自动加载 `/api/group-rules`。
+
+### 🔎 前缀过滤
+
+工具栏提供“前缀过滤”,可按包路径/类型名/函数名过滤当前图:
+
+- Providers/类型视图
+- 类型依赖视图
+- 组内依赖视图
+
+### 🧭 组内子图
+
+点击虚拟组节点 → 详情面板 → “查看组内依赖图”,可以看到:
+
+- 组内节点
+- 上下游依赖
+- 受工具栏“深度”控制
+
### 📦 按包分组
左侧面板功能:
@@ -161,6 +222,15 @@ func main() {
| **滚轮缩放** | 放大/缩小图形 |
| **点击详情中的类型** | 跳转查看该类型的依赖 |
+## Mermaid 支持
+
+工具栏新增 **Mermaid** 按钮,会基于**当前视图**生成 Mermaid `flowchart`,并弹出预览窗口,支持一键复制源码。
+
+**典型用法**:
+1. 调整视图/分组/过滤条件。
+2. 点击 **Mermaid**。
+3. 复制生成的 Mermaid 文本或直接预览。
+
## API 端点
### GET `/`
@@ -200,8 +270,11 @@ func main() {
{
"id": "provider_*main.ServiceA_0",
"output_type": "*main.ServiceA",
+ "output_pkg": "github.com/example/app/service",
"function_name": "main.NewServiceA",
- "input_types": ["*main.Config"]
+ "function_pkg": "github.com/example/app",
+ "input_types": ["*main.Config"],
+ "input_pkgs": ["github.com/example/app/config"]
}
],
"objects": [...],
@@ -226,6 +299,15 @@ func main() {
{"from": "*db.Database", "to": "*service.UserService", "type": "dependency"}
]
}
+
+### GET `/api/group-rules`
+返回后端注册的分组清单(前端默认配置)
+
+```json
+[
+ {"name": "service", "prefixes": ["github.com/acme/app/service"]}
+]
+```
```
## 技术栈
diff --git a/dixhttp/server.go b/dixhttp/server.go
index 5ef068e..eeaf73a 100644
--- a/dixhttp/server.go
+++ b/dixhttp/server.go
@@ -7,6 +7,7 @@ import (
"net/http"
"strconv"
"strings"
+ "sync"
"github.com/pubgo/dix/v2/dixinternal"
)
@@ -18,13 +19,92 @@ var htmlTemplate string
type Server struct {
dix *dixinternal.Dix
mux *http.ServeMux
+ // basePath is an optional URL prefix (no trailing slash). Example: "/dix"
+ basePath string
+}
+
+// GroupRule defines a group name with prefix list for aggregation.
+type GroupRule struct {
+ Name string `json:"name"`
+ Prefixes []string `json:"prefixes"`
+}
+
+var (
+ groupRulesMu sync.RWMutex
+ groupRules []GroupRule
+)
+
+// RegisterGroupRules registers global group rules for visualization.
+// This can be called by business code to predefine group rules.
+func RegisterGroupRules(rules ...GroupRule) {
+ groupRulesMu.Lock()
+ defer groupRulesMu.Unlock()
+ groupRules = sanitizeGroupRules(rules)
+}
+
+func getGroupRules() []GroupRule {
+ groupRulesMu.RLock()
+ defer groupRulesMu.RUnlock()
+ if len(groupRules) == 0 {
+ return nil
+ }
+ result := make([]GroupRule, 0, len(groupRules))
+ for _, r := range groupRules {
+ result = append(result, GroupRule{Name: r.Name, Prefixes: append([]string{}, r.Prefixes...)})
+ }
+ return result
+}
+
+func sanitizeGroupRules(rules []GroupRule) []GroupRule {
+ var result []GroupRule
+ seen := make(map[string]bool)
+ for _, r := range rules {
+ name := strings.TrimSpace(r.Name)
+ if name == "" || seen[name] {
+ continue
+ }
+ seen[name] = true
+ var prefixes []string
+ prefixSeen := make(map[string]bool)
+ for _, p := range r.Prefixes {
+ pp := strings.TrimSpace(p)
+ if pp == "" || prefixSeen[pp] {
+ continue
+ }
+ prefixSeen[pp] = true
+ prefixes = append(prefixes, pp)
+ }
+ result = append(result, GroupRule{Name: name, Prefixes: prefixes})
+ }
+ return result
}
// NewServer creates a new HTTP server for dependency visualization
func NewServer(dix *dixinternal.Dix) *Server {
+ return NewServerWithOptions(dix)
+}
+
+// ServerOption customizes the HTTP server behavior.
+type ServerOption func(*Server)
+
+// WithBasePath sets an optional URL prefix for all routes. Example: "/dix".
+func WithBasePath(basePath string) ServerOption {
+ return func(s *Server) {
+ s.basePath = normalizeBasePath(basePath)
+ }
+}
+
+// NewServerWithOptions creates a new HTTP server with options.
+func NewServerWithOptions(dix *dixinternal.Dix, opts ...ServerOption) *Server {
s := &Server{
- dix: dix,
- mux: http.NewServeMux(),
+ dix: dix,
+ mux: http.NewServeMux(),
+ basePath: "",
+ }
+ for _, opt := range opts {
+ if opt != nil {
+ opt(s)
+ }
}
s.setupRoutes()
return s
@@ -32,12 +112,27 @@ func NewServer(dix *dixinternal.Dix) *Server {
// setupRoutes configures all HTTP routes
func (s *Server) setupRoutes() {
- s.mux.HandleFunc("/", s.HandleIndex)
- s.mux.HandleFunc("/api/dependencies", s.HandleDependencies)
- s.mux.HandleFunc("/api/stats", s.HandleStats)
- s.mux.HandleFunc("/api/packages", s.HandlePackages)
- s.mux.HandleFunc("/api/package/", s.HandlePackageDetails)
- s.mux.HandleFunc("/api/type/", s.HandleTypeDetails)
+ base := s.basePath
+ indexPath := "/"
+ if base != "" {
+ indexPath = base + "/"
+ // Redirect /base -> /base/
+ s.mux.HandleFunc(base, func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path == base {
+ http.Redirect(w, r, indexPath, http.StatusMovedPermanently)
+ return
+ }
+ http.NotFound(w, r)
+ })
+ }
+
+ s.mux.HandleFunc(indexPath, s.HandleIndex)
+ s.mux.HandleFunc(base+"/api/dependencies", s.HandleDependencies)
+ s.mux.HandleFunc(base+"/api/stats", s.HandleStats)
+ s.mux.HandleFunc(base+"/api/packages", s.HandlePackages)
+ s.mux.HandleFunc(base+"/api/package/", s.HandlePackageDetails)
+ s.mux.HandleFunc(base+"/api/type/", s.HandleTypeDetails)
+ s.mux.HandleFunc(base+"/api/group-rules", s.HandleGroupRules)
}
// ServeHTTP implements http.Handler interface
@@ -54,7 +149,8 @@ func (s *Server) ListenAndServe(addr string) error {
func (s *Server) HandleIndex(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
- fmt.Fprint(w, htmlTemplate)
+ html := strings.ReplaceAll(htmlTemplate, "__DIX_BASE_PATH__", s.basePath)
+ fmt.Fprint(w, html)
}
// HandleStats returns summary statistics
@@ -298,6 +394,15 @@ func (s *Server) HandleDependencies(w http.ResponseWriter, r *http.Request) {
writeJSON(w, data)
}
+// HandleGroupRules returns global group rules for visualization.
+func (s *Server) HandleGroupRules(w http.ResponseWriter, r *http.Request) {
+ rules := getGroupRules()
+ if rules == nil {
+ rules = []GroupRule{}
+ }
+ writeJSON(w, rules)
+}
+
// extractDependencyData extracts structured data from the Dix container
func (s *Server) extractDependencyData(pkgFilter string, limit int) *DependencyData {
data := &DependencyData{
@@ -329,8 +434,11 @@ func (s *Server) extractDependencyData(pkgFilter string, limit int) *DependencyD
providerInfo := ProviderInfo{
ID: providerID,
OutputType: detail.OutputType,
+ OutputPkg: detail.OutputPkg,
FunctionName: detail.FunctionName,
+ FunctionPkg: detail.FunctionPkg,
InputTypes: detail.InputTypes,
+ InputPkgs: detail.InputPkgs,
}
// Add edges from input types to provider output
@@ -434,8 +542,11 @@ type DependencyData struct {
type ProviderInfo struct {
ID string `json:"id"`
OutputType string `json:"output_type"`
+ OutputPkg string `json:"output_pkg"`
FunctionName string `json:"function_name"`
+ FunctionPkg string `json:"function_pkg"`
InputTypes []string `json:"input_types"`
+ InputPkgs []string `json:"input_pkgs"`
}
// ObjectInfo contains information about an object instance
@@ -501,3 +612,15 @@ func writeJSON(w http.ResponseWriter, data any) {
http.Error(w, fmt.Sprintf("Failed to encode JSON: %v", err), http.StatusInternalServerError)
}
}
+
+func normalizeBasePath(basePath string) string {
+ base := strings.TrimSpace(basePath)
+ if base == "" || base == "/" {
+ return ""
+ }
+ if !strings.HasPrefix(base, "/") {
+ base = "/" + base
+ }
+ base = strings.TrimRight(base, "/")
+ return base
+}
diff --git a/dixhttp/template.html b/dixhttp/template.html
index fc4efcb..6a43b10 100644
--- a/dixhttp/template.html
+++ b/dixhttp/template.html
@@ -7,6 +7,7 @@
+
diff --git a/dixinternal/api.go b/dixinternal/api.go
index 6b88242..08b5fa9 100644
--- a/dixinternal/api.go
+++ b/dixinternal/api.go
@@ -3,6 +3,7 @@ package dixinternal
import (
"errors"
"reflect"
+ "strings"
)
// New Dix new
@@ -95,8 +96,11 @@ func (dix *Dix) GetObjects() map[reflect.Type]map[string][]reflect.Value {
// ProviderDetails contains detailed information about a provider
type ProviderDetails struct {
OutputType string
+ OutputPkg string
FunctionName string
+ FunctionPkg string
InputTypes []string
+ InputPkgs []string
}
// GetProviderDetails returns detailed information about all providers
@@ -106,15 +110,66 @@ func (dix *Dix) GetProviderDetails() []ProviderDetails {
for _, providerFn := range providerList {
fnName := GetFnName(providerFn.fn)
var inputTypes []string
+ var inputPkgs []string
+ seen := make(map[string]bool)
for _, input := range providerFn.inputList {
- inputTypes = append(inputTypes, input.typ.String())
+ if input.isStruct || input.typ.Kind() == reflect.Struct {
+ for _, in := range getProvideAllInputs(input.typ) {
+ name := in.typ.String()
+ if name == "" || seen[name] {
+ continue
+ }
+ seen[name] = true
+ inputTypes = append(inputTypes, name)
+ inputPkgs = append(inputPkgs, resolveTypePkgPath(in.typ))
+ }
+ continue
+ }
+
+ name := input.typ.String()
+ if name == "" || seen[name] {
+ continue
+ }
+ seen[name] = true
+ inputTypes = append(inputTypes, name)
+ inputPkgs = append(inputPkgs, resolveTypePkgPath(input.typ))
}
details = append(details, ProviderDetails{
OutputType: outputType.String(),
+ OutputPkg: resolveTypePkgPath(outputType),
FunctionName: fnName,
+ FunctionPkg: resolveFuncPkgPath(fnName),
InputTypes: inputTypes,
+ InputPkgs: inputPkgs,
})
}
}
return details
}
+
+func resolveTypePkgPath(typ reflect.Type) string {
+ if typ == nil {
+ return ""
+ }
+ for typ.Kind() == reflect.Ptr || typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array {
+ typ = typ.Elem()
+ if typ == nil {
+ return ""
+ }
+ }
+ if typ.Kind() == reflect.Map {
+ return resolveTypePkgPath(typ.Elem())
+ }
+ return typ.PkgPath()
+}
+
+func resolveFuncPkgPath(fnName string) string {
+ name := strings.TrimSpace(fnName)
+ if name == "" {
+ return ""
+ }
+ if idx := strings.LastIndex(name, "."); idx > 0 {
+ return name[:idx]
+ }
+ return ""
+}
diff --git a/dixrender/renderer.go b/dixrender/renderer.go
deleted file mode 100644
index 2fbcfcc..0000000
--- a/dixrender/renderer.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package dixrender
-
-import (
- "bytes"
- "fmt"
- "sort"
- "strings"
-)
-
-// DotRenderer implements DOT format graph rendering
-type DotRenderer struct {
- Buf *bytes.Buffer // Exported for testing
- indent string
- cache map[string]string
-}
-
-func NewDotRenderer() *DotRenderer {
- return &DotRenderer{
- Buf: &bytes.Buffer{},
- indent: "",
- cache: make(map[string]string),
- }
-}
-
-// Writef writes a formatted string to the renderer buffer
-func (d *DotRenderer) Writef(format string, args ...any) {
- _, _ = fmt.Fprintf(d.Buf, d.indent+format+"\n", args...)
-}
-
-func (d *DotRenderer) writef(format string, args ...any) {
- d.Writef(format, args...)
-}
-
-// escapeDotString escapes special characters for DOT format
-func escapeDotString(s string) string {
- s = strings.ReplaceAll(s, "\\", "\\\\")
- s = strings.ReplaceAll(s, "\"", "\\\"")
- s = strings.ReplaceAll(s, "\n", "\\n")
- s = strings.ReplaceAll(s, "\r", "\\r")
- s = strings.ReplaceAll(s, "\t", "\\t")
- return s
-}
-
-func (d *DotRenderer) RenderNode(name string, attrs map[string]string) {
- escapedName := escapeDotString(name)
- d.writef(`"%s" [label="%s"%s]`, escapedName, escapedName, d.formatAttrs(attrs))
-}
-
-func (d *DotRenderer) RenderEdge(from, to string, attrs map[string]string) {
- d.writef(`"%s" -> "%s" %s`, escapeDotString(from), escapeDotString(to), d.formatAttrs(attrs))
-}
-
-func (d *DotRenderer) BeginSubgraph(name, label string) {
- d.writef("subgraph %s {", escapeDotString(name))
- d.indent += "\t"
- d.writef("label=\"%s\"", escapeDotString(label))
-}
-
-func (d *DotRenderer) EndSubgraph() {
- d.indent = d.indent[:len(d.indent)-1]
- d.writef("}")
-}
-
-func (d *DotRenderer) String() string {
- return d.Buf.String()
-}
-
-// FormatAttrs formats attributes map into DOT format string
-func (d *DotRenderer) FormatAttrs(attrs map[string]string) string {
- return d.formatAttrs(attrs)
-}
-
-func (d *DotRenderer) formatAttrs(attrs map[string]string) string {
- if len(attrs) == 0 {
- return ""
- }
-
- // Sort keys to ensure consistent ordering
- keys := make([]string, 0, len(attrs))
- for k := range attrs {
- keys = append(keys, k)
- }
- sort.Strings(keys)
-
- var result bytes.Buffer
- result.WriteString(" [")
- first := true
- for _, k := range keys {
- if !first {
- result.WriteString(",")
- }
- first = false
- v := attrs[k]
- fmt.Fprintf(&result, "%s=\"%s\"", k, v)
- }
- result.WriteString("]")
- return result.String()
-}
-
-// Graph represents dependency graphs in DOT format
-type Graph struct {
- Objects string `json:"objects"`
- Providers string `json:"providers"`
- ProviderTypes string `json:"provider_types"`
-}
-
-// GraphOptions holds configuration options for graph rendering
-type GraphOptions struct {
- // MaxDepth limits the depth of dependencies to show (0 = unlimited)
- MaxDepth int
-
- // GroupByPackage enables grouping nodes by package
- GroupByPackage bool
-
- // ShowStructFields controls whether to show struct field dependencies
- ShowStructFields bool
-
- // FilterPackages allows filtering by specific packages
- FilterPackages []string
-}
-
-// NewGraphOptions creates GraphOptions with sensible defaults
-func NewGraphOptions() *GraphOptions {
- return &GraphOptions{
- MaxDepth: 0, // Unlimited by default
- GroupByPackage: true,
- ShowStructFields: false,
- FilterPackages: []string{},
- }
-}
-
-// ShouldIncludeType checks if a type should be included in the graph based on filters
-func (opts *GraphOptions) ShouldIncludeType(typ string) bool {
- if len(opts.FilterPackages) == 0 {
- return true
- }
-
- for _, pkg := range opts.FilterPackages {
- if strings.Contains(typ, pkg) {
- return true
- }
- }
- return false
-}
diff --git a/example/cycle/main.go b/example/cycle/main.go
index dfe6973..9c9b9a5 100644
--- a/example/cycle/main.go
+++ b/example/cycle/main.go
@@ -12,9 +12,6 @@ func main() {
fmt.Printf("panic: %v\n", r)
}
}()
- defer func() {
- fmt.Println(dixglobal.Graph())
- }()
type (
A struct{}
diff --git a/example/go.mod b/example/go.mod
index f8099a0..e8e20ac 100644
--- a/example/go.mod
+++ b/example/go.mod
@@ -4,10 +4,6 @@ go 1.24.0
replace github.com/pubgo/dix/v2 => ../
-require github.com/pubgo/dix/v2 v2.0.0-alpha.3
+require github.com/pubgo/dix/v2 v2.0.0-00010101000000-000000000000
-require (
- github.com/lmittmann/tint v1.1.2 // indirect
- github.com/samber/lo v1.52.0 // indirect
- golang.org/x/text v0.31.0 // indirect
-)
+require github.com/lmittmann/tint v1.1.2 // indirect
diff --git a/example/go.sum b/example/go.sum
index 802974a..ca8ef76 100644
--- a/example/go.sum
+++ b/example/go.sum
@@ -1,6 +1,2 @@
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
-github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
-github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
-golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
-golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
diff --git a/example/handler/main.go b/example/handler/main.go
index 9a004ac..b1a3eab 100644
--- a/example/handler/main.go
+++ b/example/handler/main.go
@@ -24,10 +24,6 @@ func main() {
}
}()
- defer func() {
- fmt.Println(dixglobal.Graph())
- }()
-
dixglobal.Provide(func() *log.Logger {
return log.New(os.Stderr, "example: ", log.LstdFlags|log.Lshortfile)
})
@@ -47,8 +43,6 @@ func main() {
}
})
- fmt.Println(dixglobal.Graph())
-
dixglobal.Inject(func(r *Redis, l *log.Logger, rr map[string]*Redis) {
l.Println("invoke redis")
fmt.Println("invoke:", r.name)
diff --git a/example/struct-out/main.go b/example/struct-out/main.go
index ed7b3ed..c11015d 100644
--- a/example/struct-out/main.go
+++ b/example/struct-out/main.go
@@ -50,7 +50,6 @@ func main() {
err = fmt.Errorf("panic: %v", r)
}
fmt.Printf("panic: %v\n", err)
- fmt.Println(dixglobal.Graph()) // Original behavior from recovery.Exit's func
}
}()
@@ -97,6 +96,4 @@ func main() {
fmt.Println(dm)
fmt.Println(d5)
})
-
- fmt.Println(dixglobal.Graph())
}