Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions DependenSee/MermaidSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace DependenSee;
public static class MermaidSerializer
{
const string ProjectBackgroundColor = "#00cc22";
const string PackageBackgroundColor = "#22aaee";

public static string ToString(DiscoveryResult discoveryResult)
{
using var stringWriter = new StringWriter();
using var writer = new IndentedTextWriter(stringWriter);

writer.WriteLine("graph LR");

writer.Indent++;

foreach (var project in discoveryResult.Projects)
{
writer.WriteLine($"{project.Id}[\"{project.Name}\"]:::project");
}

if (discoveryResult.Packages.Count > 0)
{
writer.WriteLine($"subgraph Packages");
foreach (var package in discoveryResult.Packages)
{
writer.WriteLine($"{package.Id}[\"{package.Name}\"]:::package");
}
writer.WriteLine("end");
}

foreach (var reference in discoveryResult.References)
{
writer.WriteLine($"{reference.From} --> {reference.To}");
}

writer.WriteLine($"classDef project fill:{ProjectBackgroundColor};");
writer.WriteLine($"classDef package fill:{PackageBackgroundColor};");

writer.Indent--;

writer.Flush();

return stringWriter.ToString();
}
}
15 changes: 13 additions & 2 deletions DependenSee/PowerArgsProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ public enum OutputTypes
[ArgDescription("Creates a JSON file.")] Json,
[ArgDescription("Creates a XML file.")] Xml,
[ArgDescription("Creates a Graphviz/DOT file.")] Graphviz,
[ArgDescription("Creates a Mermaid/MMD file.")] Mermaid,
[ArgDescription("Writes JSON output to stdout")] ConsoleJson,
[ArgDescription("Writes XML output to stdout")] ConsoleXml,
[ArgDescription("Writes Graphviz output to stdout")] ConsoleGraphviz,
[ArgDescription("Writes Mermaid output to stdout")] ConsoleMermaid,
}

[ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)]
Expand Down Expand Up @@ -60,6 +62,10 @@ public class PowerArgsProgram
[ArgShortcut("EPrN")]
public string ExcludeProjectNamespaces { get; set; }

[ArgDescription("Comma separated list of project file prefixes to trim from display. Wildcards not allowed. Only the filename is considered, case insensitive. Ex:'MyApp' trims display name of projects starting with 'MyApp'. 'MyApp.Core' and 'MyApp.Extensions' display as 'Core' and 'Extensions'")]
[ArgShortcut("TPrN")]
public string TrimProjectNamespaces { get; set; }

[ArgDefaultValue("")]
[ArgDescription("Comma separated list of package name prefixes to include. Wildcards not allowed. Only the package name is considered, case insensitive. If specified, 'IncludePackages' is overridden to True. Ex: 'Xamarin, Microsoft' includes only packages starting with Xamarin and packages starting with Microsoft")]
[ArgShortcut("IPaN")]
Expand All @@ -68,6 +74,11 @@ public class PowerArgsProgram
[ArgDescription("Comma separated list of package name prefixes to exclude. Wildcards not allowed. Only the filename is considered, case insensitive. If specified, 'IncludePackages' is overridden to True. This must be a subset of includes to be useful. Ex: 'Microsoft.Logging, Azure' Excludes packages starting with Microsoft.Logging and packages starting with Azure")]
[ArgShortcut("EPaN")]
public string ExcludePackageNamespaces { get; set; }

[ArgDescription("Comma separated list of package name prefixes to trim from display. Wildcards not allowed. Only the package name is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`. Ex:'MyApp' trims display name of packages starting with 'MyApp'. 'MyApp.Core' and 'MyApp.Extensions' display as 'Core' and 'Extensions'")]
[ArgShortcut("TPaN")]
public string TrimPackageNamespaces { get; set; }

[ArgDefaultValue("")]
[ArgDescription("Comma Separated list of folders (either absolute paths or relative to SourceFolder) to skip during scan, even if there are references to them from your projects.")]
[ArgShortcut("EFol")]
Expand All @@ -78,7 +89,6 @@ public class PowerArgsProgram
[ArgShortcut("FReP")]
public bool FollowReparsePoints { get; set; }


public void Main()
{
var service = new ReferenceDiscoveryService
Expand All @@ -87,6 +97,8 @@ public void Main()
ExcludeProjectNamespaces = ExcludeProjectNamespaces,
IncludePackageNamespaces = IncludePackageNamespaces,
IncludeProjectNamespaces = IncludeProjectNamespaces,
TrimPackageNamespaces = TrimPackageNamespaces,
TrimProjectNamespaces = TrimProjectNamespaces,

IncludePackages = IncludePackages,

Expand All @@ -97,7 +109,6 @@ public void Main()
OutputType = OutputType,

SourceFolder = SourceFolder,

};
var result = service.Discover();
new ResultWriter().Write(result, OutputType, OutputPath, HtmlTitle);
Expand Down
26 changes: 23 additions & 3 deletions DependenSee/ReferenceDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ public class ReferenceDiscoveryService
public OutputTypes OutputType { get; set; }
public string IncludeProjectNamespaces { get; set; }
public string ExcludeProjectNamespaces { get; set; }
public string TrimProjectNamespaces { get; set; }
public string IncludePackageNamespaces { get; set; }
public string ExcludePackageNamespaces { get; set; }
public string TrimPackageNamespaces { get; set; }
public bool FollowReparsePoints { get; set; }
public string ExcludeFolders { get; set; }

private string[] _includeProjectNamespaces { get; set; }
private string[] _excludeProjectNamespaces { get; set; }
private string[] _trimProjectNamespaces { get; set; }
private string[] _includePackageNamespaces { get; set; }
private string[] _excludePackageNamespaces { get; set; }
private string[] _trimPackageNamespaces { get; set; }

private bool _shouldIncludePackages { get; set; }

Expand All @@ -31,15 +35,18 @@ public DiscoveryResult Discover()

_includeProjectNamespaces = ParseStringToLowercaseStringArray(IncludeProjectNamespaces);
_excludeProjectNamespaces = ParseStringToLowercaseStringArray(ExcludeProjectNamespaces);
_trimProjectNamespaces = ParseStringToLowercaseStringArray(TrimProjectNamespaces);

_includePackageNamespaces = ParseStringToLowercaseStringArray(IncludePackageNamespaces);
_excludePackageNamespaces = ParseStringToLowercaseStringArray(ExcludePackageNamespaces);
_trimPackageNamespaces = ParseStringToLowercaseStringArray(TrimPackageNamespaces);

if (!_includeProjectNamespaces.Any()) _includeProjectNamespaces = new[] { "" };
if (!_includePackageNamespaces.Any()) _includePackageNamespaces = new[] { "" };
_shouldIncludePackages = IncludePackages
|| !string.IsNullOrWhiteSpace(IncludePackageNamespaces)
|| !string.IsNullOrWhiteSpace(ExcludePackageNamespaces);
|| !string.IsNullOrWhiteSpace(ExcludePackageNamespaces)
|| !string.IsNullOrWhiteSpace(TrimPackageNamespaces);

Discover(SourceFolder, result);
return result;
Expand Down Expand Up @@ -88,7 +95,7 @@ private void Discover(string folder, DiscoveryResult result)
result.Projects.Add(new Project
{
Id = id,
Name = name
Name = toDisplayName(name, _trimProjectNamespaces),
});

var (projects, packages) = DiscoverFileReferences(file);
Expand All @@ -97,7 +104,11 @@ private void Discover(string folder, DiscoveryResult result)
.Where(p =>
_includeProjectNamespaces.Any(i => p.Name.ToLower().StartsWith(i))
&& !_excludeProjectNamespaces.Any(i => p.Name.ToLower().StartsWith(i)))
.ToList();
.Select(p =>
{
p.Name = toDisplayName(p.Name, _trimProjectNamespaces);
return p;
}).ToList();

foreach (var project in projects)
{
Expand All @@ -116,6 +127,11 @@ private void Discover(string folder, DiscoveryResult result)
{
return _includePackageNamespaces.Any(i => p.Name.ToLower().StartsWith(i))
&& !_excludePackageNamespaces.Any(i => p.Name.ToLower().StartsWith(i));
})
.Select(p =>
{
p.Name = toDisplayName(p.Name, _trimPackageNamespaces);
return p;
}).ToList();

foreach (var package in packages)
Expand All @@ -129,11 +145,15 @@ private void Discover(string folder, DiscoveryResult result)
});
}
}

var directories = Directory.EnumerateDirectories(folder);
foreach (var directory in directories)
{
Discover(directory, result);
}

static string toDisplayName(string name, string[] prefixes)
=> prefixes.FirstOrDefault(i => name.ToLower().StartsWith(i)) is string pn ? name[pn.Length..].TrimStart('.') : name;
}

private (List<Project> projects, List<Package> packages) DiscoverFileReferences(string path)
Expand Down
15 changes: 15 additions & 0 deletions DependenSee/ResultWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal void Write(DiscoveryResult result, OutputTypes type, string outputPath,
case OutputTypes.Xml:
case OutputTypes.Json:
case OutputTypes.Graphviz:
case OutputTypes.Mermaid:
if (string.IsNullOrWhiteSpace(outputPath))
{
Console.Error.WriteLine($"output type {type} require specifying {nameof(outputPath)}");
Expand All @@ -37,6 +38,9 @@ internal void Write(DiscoveryResult result, OutputTypes type, string outputPath,
case OutputTypes.Graphviz:
WriteAsGraphvizToFile(result, outputPath);
break;
case OutputTypes.Mermaid:
WriteAsMermaidToFile(result, outputPath);
break;
case OutputTypes.ConsoleJson:
WriteAsJsonToConsole(result);
break;
Expand All @@ -46,6 +50,9 @@ internal void Write(DiscoveryResult result, OutputTypes type, string outputPath,
case OutputTypes.ConsoleGraphviz:
WriteAsGraphvizToConsole(result);
break;
case OutputTypes.ConsoleMermaid:
WriteAsMermaidToConsole(result);
break;
default:
throw new Exception($"Unknown {nameof(type)} '{type}'");
}
Expand Down Expand Up @@ -95,4 +102,12 @@ private static void WriteAsGraphvizToFile(DiscoveryResult result, string outputP
Console.WriteLine($"GraphViz output written to {outputPath}");
}

private static void WriteAsMermaidToConsole(DiscoveryResult result)
=> Console.WriteLine(MermaidSerializer.ToString(result));

private static void WriteAsMermaidToFile(DiscoveryResult result, string outputPath)
{
File.WriteAllText(outputPath, MermaidSerializer.ToString(result));
Console.WriteLine($"Mermaid output written to {outputPath}");
}
}
34 changes: 32 additions & 2 deletions docs/CommandLine.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ Type of output to produce. Following types are available.
- `Json` - Creates a JSON file.
- `Xml` - Creates a XML file.
- `Graphviz` - Creates a Graphviz/DOT file.
- `Mermaid` - Creates a Mermaid/MMD file.
- `ConsoleJson` - Writes JSON output to stdout
- `ConsoleXml` - Writes XML output to stdout
- `GonsoleGraphviz` - Writes Graphviz output to stdout
- `ConsoleGraphviz` - Writes Graphviz output to stdout
- `ConsoleMermaid` - Writes Mermaid output to stdout

When a `Console...` type output is specified, the `-OutputPath` can be ommitted.
`Console...` output types may still write warings to `stderr` stream. If you're piping just the `stderr` into another program, consider checking the `stderr` for warnings as well.
Expand Down Expand Up @@ -150,6 +152,20 @@ If you want to include spaces between items, make sure you enclose the parameter
- `DependenSee \Source\SolutionFolder -O ConsoleJson -EPrN MyApp.Extensions, MyApp.Helpers`
- Excludes projects starting with MyApp.Extensions and projects starting with MyApp.Helpers

## TrimProjectNamespaces
Comma separated list of project file prefixes to trim. Wildcards not allowed. Only the filename is considered, case insensitive.

**Shorthand: `-TPrN`**

**Default: `<empty string>`**

### Examples

- `DependenSee \Source\SolutionFolder -O ConsoleJson -TrimProjectNamespaces MyApp`
- Displays project names starting with MyApp. 'MyApp.Core' and 'MyApp.Extensions' display as 'Core' and 'Extensions'
- `DependenSee \Source\SolutionFolder -O ConsoleJson -TPrN MyApp`
- Displays project names starting with MyApp. 'MyApp.Core' and 'MyApp.Extensions' display as 'Core' and 'Extensions'

## IncludePackageNamespaces
Comma separated list of package name prefixes to include. Wildcards not allowed. Only the package name is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`.

Expand All @@ -168,14 +184,28 @@ If you want to include spaces between items, make sure you enclose the parameter

## ExcludePackageNamespaces

Comma separated list of package name prefixes to exclude. Wildcards not allowed. Only the filename is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`. This must be a subset of includes to be useful.
Comma separated list of package name prefixes to exclude. Wildcards not allowed. Only the package name is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`. This must be a subset of includes to be useful.

If you want to include spaces between items, make sure you enclose the parameter value in double quotes.

**Shorthand: `-EPaN`**

**Default: `<unspecified>`**

## TrimPackageNamespaces
Comma separated list of package name prefixes to trim. Wildcards not allowed. Only the package name is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`.

**Shorthand: `-TPaN`**

**Default: `<empty string>`**

### Examples

- `DependenSee \Source\SolutionFolder -O ConsoleJson -TrimPackageNamespaces MyApp`
- Displays package names starting with MyApp. 'MyApp.Core' and 'MyApp.Extensions' display as 'Core' and 'Extensions'
- `DependenSee \Source\SolutionFolder -O ConsoleJson -TPaN MyApp`
- Displays package names starting with MyApp. 'MyApp.Core' and 'MyApp.Extensions' display as 'Core' and 'Extensions'

## FollowReparsePoints

Set if you want the scan to follow valid reparse points. This is helpful if your project references are relying on symlinks, NTFS junction points .etc.
Expand Down