149

How can I view the hierarchy of dependencies between NuGet packages (either textual or graphically)?

2

15 Answers 15

118

If you're using the new .csproj, you could get all dependencies with reference in here (after project built):

{ProjectDir}\obj\project.assets.json

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

simplest and to the point solution, cheers.
I think this works in any csproj that uses the <PackageReference> format instead of a packages.config file. I have a legacy app with an oldschool csproj, modified to use PackageReference and this file exists in my obj folder.
What application is this screenshot from?
34

Like @neil-barnwell solution, but works with NuGet.Core 2.7+

Install-Package NuGet.Core

Here is the code

using System;
using System.Linq;
using System.Runtime.Versioning;
using System.IO;
using NuGet;

public class Program
{
    public static void Main(string[] args)
    {
        var frameworkName = new FrameworkName(".NETFramework, Version=4.0");

        // var packageSource = "https://www.nuget.org/api/v2/";
        var packageSource = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "NuGet", "Cache");

        var repository = PackageRepositoryFactory.Default.CreateRepository(packageSource);
        const bool prerelease = false;

        var packages = repository.GetPackages()
            .Where(p => prerelease ? p.IsAbsoluteLatestVersion : p.IsLatestVersion)
            .Where(p => VersionUtility.IsCompatible(frameworkName, p.GetSupportedFrameworks()));

        foreach (IPackage package in packages)
        {
            GetValue(repository, frameworkName, package, prerelease, 0);
        }

        Console.WriteLine();
        Console.WriteLine("Press Enter...");
        Console.ReadLine();
    }

    private static void GetValue(IPackageRepository repository, FrameworkName frameworkName, IPackage package, bool prerelease, int level)
    {

        Console.WriteLine("{0}{1}", new string(' ', level * 3), package);
        foreach (PackageDependency dependency in package.GetCompatiblePackageDependencies(frameworkName))
        {
            IPackage subPackage = repository.ResolveDependency(dependency, prerelease, true);
            GetValue(repository, frameworkName, subPackage, prerelease, level + 1);
        }
    }
}

1 Comment

It is throwing Could not load type 'System.Windows.IWeakEventListener error
29

It is also possible to write code against the API in NuGet.Core. Install it via NuGet:

install-package nuget.core

Then you can get a repository object and walk the graph. Here's a sample app I just built:

using System;
using System.Collections.Generic;
using System.Linq;
using NuGet;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
        {    
            var repo = new LocalPackageRepository(@"C:\Code\Common\Group\Business-Logic\packages");
            IQueryable<IPackage> packages = repo.GetPackages();
            OutputGraph(repo, packages, 0);
        }

        static void OutputGraph(LocalPackageRepository repository, IEnumerable<IPackage> packages, int depth)
        {
            foreach (IPackage package in packages)
            {
                Console.WriteLine("{0}{1} v{2}", new string(' ', depth), package.Id, package.Version);

                IList<IPackage> dependentPackages = new List<IPackage>();
                foreach (var dependency in package.Dependencies)
                {
                    dependentPackages.Add(repository.FindPackage(dependency.Id, dependency.VersionSpec.ToString()));
                }

                OutputGraph(repository, dependentPackages, depth += 3);
            }
        }
    }
}

In my case, this app outputs something like this:

MyCompany.Castle v1.1.0.3
   Castle.Windsor v2.5.3
      Castle.Core v2.5.2
      MyCompany.Common v1.1.0.6
         CommonServiceLocator v1.0
            MyCompany.Enum v1.1.0.7
   MyCompany.Common v1.1.0.6
      CommonServiceLocator v1.0
         MyCompany.Enum v1.1.0.7
      MyCompany.Enum v1.1.0.7
         MyCompany.Versioning v1.3
            Castle.Core v2.5.2
               Castle.Windsor v2.5.3
                  Castle.Core v2.5.2
                  CommonServiceLocator v1.0
                     NUnit v2.5.10.11092
                        RhinoMocks v3.6

7 Comments

There's a ResolveDependency extension method in NuGet that you can use.
depth += 3 is probably a bug, change to depth + 3. You can then see all packages on the left and only dependencies of that packages are indented
I tried to update this to the latest version of NuGet, but my edit was rejected. Change foreach dependency to package.DependencySets and add another foreach loop get the dependency.
Make sure you run this in a .Net Framework console app and not a .Net Core app. The core version will not have access to all the framework dependencies and will blow up on the call to FindPackages
Also the Nuget.Core package should be 1.5.x or lower. With higher versions the code won't compile.
|
27

I've found a nice NPM package to print the dependency tree into console. Of course if you don't mind using/installing NPM/Node.JS.

Considering other solutions, this is the most simple one, you don't need to write your own code or register something, and you get just such dependency tree as you expect. But it works only with packages.config format.

I can't believe this functionality is absent in free Visual Studio editions or nuget.exe too.

2 Comments

This works great (for packages.config format) and should have more votes! Note that the version numbers shown for dependencies are not the minimum required version (or range) but the actual version installed. (It would be nice to know which packages depend on very old versions of dependencies, because there might be breaking changes in the currently installed version.)
The other answers provided did not work for my Xamarin Visual Studio solution but this one does because it only looks at packages.config. Thank you
14

I Can Has .NET Core (GitHub repository) produces nice graphs of NuGet dependencies along with a Graphviz representation. And as its name implies, you also get .NET Core compatibility information for free.

If you prefer to run it locally on your computer, I Can Has .NET Core also offers a console mode.

NuGet dependencies graph sample (web)

NuGet dependencies graph sample (Graphviz)

2 Comments

"We have decided to close down icanhasdot.net in May 2020."GitHub - OctopusDeploy/ICanHasDotnetCore
Site is now closed down, having served its purpose.
12

I add a compatible solution with the latest version of nuget-core

install-package nuget.core

This is the console App to get the dependencies graph

    class Program
    {
        static void Main()
        {
            Console.Write("Enter the local repo folder: ");
            var repoFolder = Console.ReadLine();
            
            var repo = new LocalPackageRepository(repoFolder);
            IQueryable<IPackage> packages = repo.GetPackages();
            OutputGraph(repo, packages, 0);
        }

        static void OutputGraph(LocalPackageRepository repository, IEnumerable<IPackage> packages, int depth)
        {
            foreach (IPackage package in packages)
            {
                Console.WriteLine("{0}{1} v{2}", new string(' ', depth), package.Id, package.Version);

                IList<IPackage> dependentPackages = new List<IPackage>();
                foreach (var dependencySet in package.DependencySets)
                {
                    foreach (var dependency in dependencySet.Dependencies)
                    {
                        var dependentPackage = repository.FindPackage(dependency.Id, dependency.VersionSpec, true, true);
                        if (dependentPackage != null)
                        {
                            dependentPackages.Add(dependentPackage);
                        }
                    }       
                }

                OutputGraph(repository, dependentPackages, depth + 3);
            }
        }
    }

Comments

10

Having gone through all existing answers, IMHO they are incomplete and/or obsolete. Fortunately, it seems that today there are several good options:

Or roll your own using the modern APIs (not Nuget.Core):

private static async Task GetRecursiveDependenciesCore(string id, string version, ConcurrentQueue<string> dependencies)
{
    var sourceRepository = new SourceRepository(new PackageSource(NugetOrgSource), Repository.Provider.GetCoreV3());
    var dependencyResource = await sourceRepository.GetResourceAsync<DependencyInfoResource>(CancellationToken.None);
    var package = await dependencyResource.ResolvePackage(new PackageIdentity(id, new NuGetVersion(version)), NuGetFramework.AnyFramework, new NugetLogger(), CancellationToken.None);
    if (package == null)
    {
        throw new InvalidOperationException("Could not locate dependency!");
    }

    foreach (var dependency in package.Dependencies)
    {
        dependencies.Enqueue(dependency.Id + " " + dependency.VersionRange.MinVersion);
    }

    await Task.WhenAll(package.Dependencies.Select(d => GetRecursiveDependenciesCore(d.Id, d.VersionRange.MinVersion.ToNormalizedString(), dependencies)));
}

Comments

8

This is a built-in feature in the new .csproj format. In Visual Studio 2017+, open the Solution Explorer and you can find you packages like:

{Your project}->Dependencies->Packages

You can open each NuGet dependency tree and run with it recursively, effectively seeing not only the dependency tree for specific packages, but also which NuGet packages your project actually installs.

7 Comments

Where exactly do you see "Dependencies"? I don't see it anywhere in the Solution Explorer.
If you're working on a .Net Standard or .Net Core project then you can see it by opening each project's tree. But if you're working on a .Net Framework project then you should use one of the other responses.
Anyone that knows if this is going to make it into the Solution Explorer for those of us who use .Net Frameweork?
This even works with Solution Explorer search (at least in VS 2019), super useful to quickly trace the dependency chain leading to a certain package.
There is a downside to this answer: In Solution Explorer the version number that is shown behind each dependency is not the version number needed by this special dependency, but the highest version that is required over all dependencies. If you need to find out exactly which Nuget packages pushes a required version number up, you will have to resort to the answer of @JohnJang (look into \obj\project.assets.json).
|
7

Package Visualizer from NuGet 1.4 should work. See http://docs.nuget.org/docs/release-notes/nuget-1.4

2 Comments

Ahh that is helpful, but unfortunately I only have VS Pro, and the tools used for that are only in Ultimate. :(
Its unfortunate that is not included in pro version. IMHO considering NuGet is available even in express versions, all its features should be available even in express versions. Package graph information is very helpful sometime.
5

Another option you have is to use the nuget-deps-tree npm package. It supports both the packages.config format and the newer assets format used by .NET projects.

1 Comment

Unfortunately, the output of nuget-deps-tree is almost useless for casual viewing of a dependency tree, but it is the only solution I've seen that actually works.
4

If you need more than 1 depth of dependencies and more detailed information about your packages, you can also check the below file in your project:

{project directory}\bin\Debug\net8.0\<project name>.deps.json

enter image description here

Comments

1

I built a powershell script net-pkg.psm1 to draw hierarchy of dependencies.

The script works by reading file .\obj\project.assets.json (the file when you run dotnet restore)

Assume you are in Windows OS with Powershell built-in. Just download the file net-pkg.psm1 and run these command to see it work.

> ipmo -Force "C:\dev-note\learning\dotnet\net-pkg.psm1"
> cd E:\path\to\folder\of\csproj
> initialize-asset
> build-map 'net8.0'
> show-tree

└─ net8.0
   ├─ Microsoft.AspNetCore.Mvc.NewtonsoftJson/8.0.3
   ├─ MyOrg.Proj.Jobs/2.3.0
   │  ├─ MyOrg.Proj.Persistence.CosmosDb/10.0.1
   │  │  ├─ Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0
   │  │  ├─ MyOrg.Proj.Persistence.Abstractions/10.0.1
   │  │  │  ├─ Newtonsoft.Json/13.0.2 - 13.0.3
   │  │  │  └─ MyOrg.Proj.Requests.Abstractions/6.0.0
   │  │  ├─ Azure.ResourceManager.CosmosDB/1.2.1
   │  │  ├─ MyOrg.Proj.ManagedIdentity.Cosmos/4.0.2
   │  │  │  ├─ MyOrg.Proj.ManagedIdentity/4.0.2
   │  │  │  │  └─ Microsoft.Extensions.Configuration.Abstractions/8.0.0
   │  │  │  └─ Microsoft.Azure.Cosmos/3.35.4
   │  │  └─ Microsoft.AspNetCore.Hosting.Abstractions/2.2.0
   │  └─ MyOrg.Proj.Persistence.InMemory/10.0.1
   │     ├─ MyOrg.Proj.Persistence.Abstractions/10.0.1
   │     └─ MyOrg.Proj.Requests.Abstractions/6.0.0
   └─ Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0

2 Comments

For this to work for others, would the contents of net-pkg.psml also need to be above, or is it a 'standard' pkg available to all? Maybe just a little more explanation to get out of low quality answer review queue.
I assume that anyone who develop .net in Windows OS have powershell built-in. Just download the file net-pkg.psm1 and run those above command to see it work.
1

nugraph is a .NET tool I wrote that generates visual dependency graph of NuGet packages.

Install it with

dotnet tool install --global nugraph

Then run it with

nugraph Microsoft.Extensions.Logging.Console

It can generate both Mermaid and Graphviz diagrams that look like this.

Dependency graph of Microsoft.Extensions.Logging.Console

It has many more options and can also generate graphs of .NET projects (csproj/fsproj/vbproj). Documentation is available on the nugraph homepage.

Disclaimer: I'm the author of this tool.

Comments

0

.NET has a built-in feature now:

dotnet list package --include-transitive

which can print an output as follows:

Project 'Maui.Controls.Sample.Sandbox' has the following package references
   [net8.0-windows10.0.19041]:
   Top-level Package                               Requested   Resolved
   > Microsoft.Extensions.DependencyInjection      8.0.0       8.0.0

   Transitive Package                                           Resolved
   > libsodium                                                  1.0.19
   > LZMA-SDK                                                   22.1.1
   > Microsoft.AspNetCore.Authorization                         8.0.0
   > Microsoft.AspNetCore.Components                            8.0.0
   > Microsoft.AspNetCore.Components.Analyzers                  8.0.0
   > Microsoft.AspNetCore.Components.Forms                      8.0.0
   [..]

so unfortunately, it's not really hierarchical but it gives the dependencies.

For a better dependency hierarchy which does rely on external tools, one can enable generating of JSON lock files (packages.lock.json files) in her C# project using

<PropertyGroup>
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

then run dotnet restore and check contents of your packages.lock.json file:

{
  "version": 1,
  "dependencies": {
    "net8.0-windows10.0.19041": {
      "Microsoft.Extensions.DependencyInjection": {
        "type": "Direct",
        "requested": "[8.0.0, )",
        "resolved": "8.0.0",
        "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
        "dependencies": {
          "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
        }
      },
      "libsodium": {
        "type": "Transitive",
        "resolved": "1.0.19",
        "contentHash": "tupm/HViwBN6Knd/gckR+cLaJGR39GLmiU4iDMM5hp/1BoczMr8fwJhSU+3/C2V4hi9nBK/4FICRKtTLU30TCA=="
      },
      "LZMA-SDK": {
        "type": "Transitive",
        "resolved": "22.1.1",
        "contentHash": "lxG8/H53OCqebnDFlTStwzbgtmUN/DqnXN8kffa/ctHcSEHhIPDyEa3jLzpZxVX5F8bmJgvb1mna6gnhetykIw=="
      },
      "Microsoft.AspNetCore.Authorization": {
        "type": "Transitive",
        "resolved": "8.0.0",
        "contentHash": "OGIGJMnlWvQgcweHcv1Mq/P24Zx/brUHeEdD05NzqkSXmQSnFomTvVyCuBtCXT4JPfv2m70y1RSocmd9bIbJRg==",
        "dependencies": {
          "Microsoft.AspNetCore.Metadata": "8.0.0",
          "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
          "Microsoft.Extensions.Options": "8.0.0"
        }
      },
      [..]

https://github.com/NuGet/Home/issues/6188 is unfortunately still open.

Comments

0

Until IDE's provide better graphing support for showing Nuget libs of your project(s), it would be practical to just have a solution that does not require any additional tooling in dotnet or similar and which works with both .NET Framework and .NET projects.

Using Powershell you can:

  • Analyze the Json contents in project.assets.json files in subdir(s)
  • List up the dependencies in a mermaid js graph (SVG)
  • Add pan/zoom capabilities using Vanilla JS
  • Write a temporary HTML file that is launched into browser
  • Add tables showing top level and transitive dependencies and add filtering

Screenshot of the output the Powershell script provides

  • No requirement of any special dotnet tool

  • Works with both .NET Framework and .NET Core projects

  • Can show multiple projects, however, there are limitations in mermaid restricting the number of nodes and edges allowed. Recommended usage is to use one project at a time

  • Compile the project and the project.assets.json file should then be in the obj subfolder of the project you want to inspect of your .NET (Framework) project source code

  • Usage:

  • Run the Powershell script from Powershell ISE or Powershell

  • Make sure you are in the right folder when you run the script, there should be subdir(s) with project.assets.json

  • The function Show-NugetDependencyGraph can be put into your $profile file in Powershell for easier usage later on.

Nuget dependency graph


function Show-NugetDependencyGraph {
    [CmdletBinding()]
    param ()

    $tempHtmlPath = [System.IO.Path]::GetTempFileName() + ".html"
    $assetFiles = Get-ChildItem -Recurse -Filter "project.assets.json"

    $script:mermaidGraph = @"
<!DOCTYPE html>
<html>
<head>
  <script type="module">
    import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
    mermaid.initialize({ startOnLoad: true });
  </script>
  <style>
    body {
      font-family: sans-serif;
      padding: 20px;
    }
    .mermaid {
     background: #f9f9f9;
     padding: 20px;
     border-radius: 8px;
     height: auto;
     max-height: 80vh;
     overflow: auto;
   }
    .mermaid svg {
      min-height: 800px;
      width: 100%;
      height: auto;
    }
  </style>
</head>
<body>
<h2>NuGet Dependency Graph (Max Depth: 3)</h2>
<div class="mermaid">

graph TD

"@

    $visited = @{}
    $nodes = @{}
    $edges = @{}
    $topLevelDeps = @{}
    $transitiveDeps = @{}

    function Escape-MermaidLabel {
        param ([string]$text)
        $text = $text -replace '\(', '&#40;'
        $text = $text -replace '\)', '&#41;'
        $text = $text -replace '\[', '&#91;'
        $text = $text -replace '\]', '&#93;'
        $text = $text -replace ',', '&#44;'
        return $text
    }

    function Normalize-NodeId {
        param ([string]$text)
        return ($text -replace '[^a-zA-Z0-9_]', '_')
    }

    function Add-Dependencies {
        param (
            [string]$pkgName,
            [object]$targets,
            [int]$depth,
            [string]$path = ""
        )
        if ($depth -gt 3 -or $visited.ContainsKey($pkgName)) { return }
        $visited[$pkgName] = $true

        $pkgVersion = $pkgName.Split('/')[1]
        $pkgId = $pkgName.Split('/')[0]
        $escapedVersion = Escape-MermaidLabel($pkgVersion)
        $nodeId = Normalize-NodeId ("{0}_{1}" -f $pkgId, $pkgVersion)
        $nodeLabel = "$nodeId[""$pkgId<br/>v$escapedVersion""]:::level$depth"

        if (-not $nodes.ContainsKey($nodeId)) {
            $script:mermaidGraph += "$nodeLabel`n"
            $nodes[$nodeId] = $true
        }

        $currentPath = if ($path) { "$path → $pkgId ($pkgVersion)" } else { "$pkgId ($pkgVersion)" }
        if ($depth -eq 1) {
            $topLevelDeps["$pkgId/$pkgVersion"] = $currentPath
        } else {
            $transitiveDeps["$pkgId/$pkgVersion"] = $currentPath
        }

        foreach ($target in $targets.PSObject.Properties) {
            $pkg = $target.Value.$pkgName
            if ($pkg -and $pkg.dependencies) {
                foreach ($dep in $pkg.dependencies.PSObject.Properties) {
                    $depName = $dep.Name
                    $depVersion = $dep.Value
                    $escapedDepVersion = Escape-MermaidLabel($depVersion)
                    $depNodeId = Normalize-NodeId ("{0}_{1}" -f $depName, $depVersion)
                    $depNodeLabel = "$depNodeId[""$depName<br/>v$escapedDepVersion""]:::level$($depth+1)"

                    if (-not $nodes.ContainsKey($depNodeId)) {
                        $script:mermaidGraph += "$depNodeLabel`n"
                        $nodes[$depNodeId] = $true
                    }

                    $edge = "$nodeId --> $depNodeId"
                    if (-not $edges.ContainsKey($edge)) {
                        $script:mermaidGraph += "$edge`n"
                        $edges[$edge] = $true
                    }

                    Add-Dependencies ("$depName/$depVersion") $targets ($depth + 1) $currentPath
                }
            }
        }
    }

    foreach ($file in $assetFiles) {
        $json = Get-Content $file.FullName | ConvertFrom-Json
        $targets = $json.targets
        foreach ($target in $targets.PSObject.Properties) {
            $targetPackages = $target.Value
            foreach ($package in $targetPackages.PSObject.Properties) {
                Add-Dependencies $package.Name $targets 1
            }
        }
    }

    $script:mermaidGraph += @"
classDef level1 fill:#cce5ff,stroke:#004085,stroke-width:2px;
classDef level2 fill:#d4edda,stroke:#155724,stroke-width:1.5px;
classDef level3 fill:#fff3cd,stroke:#856404,stroke-width:1px;
</div>

<script>
  function enablePanZoom(svg) {
    let isPanning = false;
    let startX, startY;
    let viewBox = svg.viewBox.baseVal;
    let zoomFactor = 1.1;
    // Initial zoom: scale to 200%
    const initialZoom = 2.0;
    const newWidth = viewBox.width / initialZoom;
    const newHeight = viewBox.height / initialZoom;
    viewBox.x += (viewBox.width - newWidth) / 2;
    viewBox.y += (viewBox.height - newHeight) / 2;
    viewBox.width = newWidth;
    viewBox.height = newHeight;
    svg.addEventListener("mousedown", (e) => {
      isPanning = true;
      startX = e.clientX;
      startY = e.clientY;
      svg.style.cursor = "grabbing";
    });
    svg.addEventListener("mousemove", (e) => {
      if (!isPanning) return;
      const dx = (e.clientX - startX) * (viewBox.width / svg.clientWidth);
      const dy = (e.clientY - startY) * (viewBox.height / svg.clientHeight);
      viewBox.x -= dx;
      viewBox.y -= dy;
      startX = e.clientX;
      startY = e.clientY;
    });
    svg.addEventListener("mouseup", () => {
      isPanning = false;
      svg.style.cursor = "grab";
    });
    svg.addEventListener("mouseleave", () => {
      isPanning = false;
      svg.style.cursor = "grab";
    });
    svg.addEventListener("wheel", (e) => {
      e.preventDefault();
      const { x, y, width, height } = viewBox;
      const mx = e.offsetX / svg.clientWidth;
      const my = e.offsetY / svg.clientHeight;
      const zoom = e.deltaY < 0 ? 1 / zoomFactor : zoomFactor;
      const newWidth = width * zoom;
      const newHeight = height * zoom;
      viewBox.x += (width - newWidth) * mx;
      viewBox.y += (height - newHeight) * my;
      viewBox.width = newWidth;
      viewBox.height = newHeight;
    });
    svg.style.cursor = "grab";
  }
  document.addEventListener("DOMContentLoaded", () => {
    setTimeout(() => {
      const svg = document.querySelector(".mermaid svg");
      if (svg) {
        enablePanZoom(svg);
      } else {
        console.warn("SVG not found after 1.5s.");
      }
    }, 1500);
  });
</script>


<h3>🔎 Filter Dependencies</h3>
<input type="text" id="searchInput" onkeyup="filterTables()" placeholder="Search for NuGet package..." style="width: 100%; padding: 8px; margin-bottom: 20px; font-size: 16px;">

<style>
  table {
    border-collapse: collapse;
    width: 100%;
    margin-bottom: 40px;
    font-size: 14px;
  }
  th, td {
    border: 1px solid #ccc;
    padding: 8px;
    text-align: left;
  }
  tr:nth-child(even) {
    background-color: #f9f9f9;
  }
  tr:hover {
    background-color: #e2f0fb;
  }
  th {
    background-color: #007bff;
    color: white;
  }
</style>

<h3>📦 Top-Level Dependencies</h3>
<table id="topTable">
  <thead><tr><th>Package</th><th>Dependency Path</th></tr></thead>
  <tbody>
"@

    $sortedTopLevel = $topLevelDeps.GetEnumerator() | Sort-Object Name
    foreach ($dep in $sortedTopLevel) {
        $script:mermaidGraph += "<tr><td>$($dep.Key)</td><td>$($dep.Value)</td></tr>`n"
    }

    $script:mermaidGraph += @"
  </tbody>
</table>

<h3>📚 Transitive Dependencies</h3>
<table id="transitiveTable">
  <thead><tr><th>Package</th><th>Dependency Path</th></tr></thead>
  <tbody>
"@

    $sortedTransitive = $transitiveDeps.GetEnumerator() | Sort-Object Name
    foreach ($dep in $sortedTransitive) {
        $script:mermaidGraph += "<tr><td>$($dep.Key)</td><td>$($dep.Value)</td></tr>`n"
    }

    $script:mermaidGraph += @"
  </tbody>
</table>

<script>
function filterTables() {
  const input = document.getElementById('searchInput').value.toLowerCase();
  ['topTable', 'transitiveTable'].forEach(id => {
    const rows = document.getElementById(id).getElementsByTagName('tr');
    for (let i = 1; i < rows.length; i++) {
      const cells = rows[i].getElementsByTagName('td');
      const match = Array.from(cells).some(cell => cell.textContent.toLowerCase().includes(input));
      rows[i].style.display = match ? '' : 'none';
    }
  });
}
</script>

</body>
</html>
"@

    [System.IO.File]::WriteAllText($tempHtmlPath, $script:mermaidGraph, [System.Text.Encoding]::UTF8)
    Start-Process $tempHtmlPath
}

# Run the function
Show-NugetDependencyGraph

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.