diff --git a/cmd/gf/internal/cmd/cmddep/cmddep_output.go b/cmd/gf/internal/cmd/cmddep/cmddep_output.go index 408d4d60e..d58b40bf2 100644 --- a/cmd/gf/internal/cmd/cmddep/cmddep_output.go +++ b/cmd/gf/internal/cmd/cmddep/cmddep_output.go @@ -34,11 +34,15 @@ func (a *analyzer) generate(in Input) string { // generateTree generates ASCII tree output. func (a *analyzer) generateTree(in Input) string { var sb strings.Builder - pkgs := a.getSortedPackages() - for _, pkgPath := range pkgs { + // Find root packages (packages that are not imported by any other package) + rootPkgs := a.findRootPackages() + + // Use a single visited map across all root packages to avoid duplicates + a.visited = make(map[string]bool) + + for _, pkgPath := range rootPkgs { pkg := a.packages[pkgPath] - a.visited = make(map[string]bool) shortName := a.shortName(pkg.ImportPath, in.Group) sb.WriteString(shortName + "\n") a.printTreeNode(&sb, pkg, "", in, 0) @@ -46,6 +50,33 @@ func (a *analyzer) generateTree(in Input) string { return sb.String() } +// findRootPackages finds packages that are not imported by any other internal package. +func (a *analyzer) findRootPackages() []string { + // Build a set of all imported packages + imported := make(map[string]bool) + for _, pkg := range a.packages { + for _, dep := range pkg.Imports { + imported[dep] = true + } + } + + // Find packages that are not imported by others + roots := make([]string, 0) + for pkgPath := range a.packages { + if !imported[pkgPath] { + roots = append(roots, pkgPath) + } + } + + // If no roots found (circular dependencies), use all packages + if len(roots) == 0 { + roots = a.getSortedPackages() + } + + sort.Strings(roots) + return roots +} + func (a *analyzer) printTreeNode(sb *strings.Builder, pkg *goPackage, prefix string, in Input, depth int) { if in.Depth > 0 && depth >= in.Depth { return diff --git a/cmd/gf/internal/cmd/cmddep/static/app.js b/cmd/gf/internal/cmd/cmddep/static/app.js index bcd854b31..4918b5d23 100644 --- a/cmd/gf/internal/cmd/cmddep/static/app.js +++ b/cmd/gf/internal/cmd/cmddep/static/app.js @@ -6,7 +6,7 @@ let selectedPackage = null; let allPackages = []; let isRemoteMode = false; let currentRemoteModule = ''; -let packageListMode = 'flat'; // 'flat' or 'tree' +let packageListMode = 'tree'; // 'flat' or 'tree' let expandedNodes = new Set(); // Track expanded tree nodes // Pan and Zoom state @@ -94,9 +94,11 @@ async function init() { theme.init(); initPanZoom(); initRemoteModuleInput(); - await loadModuleName(); - await loadPackages(); - await refresh(); + const hasLocalModule = await loadModuleName(); + if (hasLocalModule) { + await loadPackages(); + await refresh(); + } } // Initialize remote module input @@ -376,21 +378,28 @@ function showZoomIndicator() { } // Load module name from server +// Returns true if local module exists, false otherwise async function loadModuleName() { try { const response = await fetch('/api/module'); const data = await response.json(); document.getElementById('moduleName').textContent = data.name || ''; - // If no local module, set default value for remote module input + // If no local module, set default value and auto-analyze if (!data.name) { const input = document.getElementById('remoteModuleInput'); if (input && !input.value) { input.value = 'github.com/gogf/gf/v2'; + // Fetch versions first, then auto-analyze + await fetchVersions(); + analyzeRemoteModule(); } + return false; } + return true; } catch (e) { console.error('Failed to load module name:', e); + return false; } } @@ -566,14 +575,14 @@ function toggleTreeNode(path) { // Re-render with current filter const query = document.getElementById('searchInput').value.toLowerCase(); - const filtered = query ? allPackages.filter(pkg => pkg.toLowerCase().includes(query)) : allPackages; + const filtered = query ? allPackages.filter(pkg => getPkgName(pkg).toLowerCase().includes(query)) : allPackages; renderPackageList(filtered); } // Filter packages by search query function filterPackages() { const query = document.getElementById('searchInput').value.toLowerCase(); - const filtered = allPackages.filter(pkg => pkg.toLowerCase().includes(query)); + const filtered = allPackages.filter(pkg => getPkgName(pkg).toLowerCase().includes(query)); renderPackageList(filtered); } diff --git a/cmd/gf/internal/cmd/cmddep/static/index.html b/cmd/gf/internal/cmd/cmddep/static/index.html index 3026bbaa5..742aad7ac 100644 --- a/cmd/gf/internal/cmd/cmddep/static/index.html +++ b/cmd/gf/internal/cmd/cmddep/static/index.html @@ -87,8 +87,8 @@ 0