forked from ScottPlot/ScottPlot
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
352 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
/dev/www/metrics | ||
*.Metrics.xml | ||
/dev/www/cookbook | ||
src/ScottPlot4/ScottPlot.Cookbook/CookbookOutput | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.4.33213.308 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeAnalysis", "CodeAnalysis.csproj", "{720EC31A-1F74-47A1-96D2-36EAB1803CC3}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{720EC31A-1F74-47A1-96D2-36EAB1803CC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{720EC31A-1F74-47A1-96D2-36EAB1803CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{720EC31A-1F74-47A1-96D2-36EAB1803CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{720EC31A-1F74-47A1-96D2-36EAB1803CC3}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {25D3A5B0-EEC3-4388-AF70-061D5C24DD8E} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using CodeAnalysis.HtmlReports; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace CodeAnalysis; | ||
|
||
public static class CodeReport | ||
{ | ||
public static void Generate(string repoRootPath, string saveAs = "code-report.html") | ||
{ | ||
string[] csFilePaths = Directory.GetFiles(repoRootPath, "*.cs", SearchOption.AllDirectories) | ||
.Where(x => !x.EndsWith("Designer.cs")) | ||
.Where(x => !x.Contains(Path.DirectorySeparatorChar + "obj" + Path.DirectorySeparatorChar)) | ||
.Where(x => !x.EndsWith("AssemblyInfo.cs")) | ||
.OrderBy(x => x) | ||
.ToArray(); | ||
|
||
Dictionary<string, int> linesByFile = csFilePaths.ToDictionary(x => x, x => File.ReadAllLines(x).Length); | ||
|
||
StringBuilder sb = new(); | ||
|
||
sb.AppendLine("<h1 align='center' style='margin-bottom: 0px;'>ScottPlot Code Metrics</h1>"); | ||
sb.AppendLine($"<div align='center'>Together, all projects contain {Total(linesByFile):N0} total lines of code</div>"); | ||
sb.AppendLine($"<hr style='margin: 50px;' />"); | ||
|
||
var sp4 = linesByFile.Where(x => x.Key.Contains(Path.DirectorySeparatorChar + "ScottPlot4" + Path.DirectorySeparatorChar)); | ||
sb.AppendLine("<h2 style='margin-bottom: 0px;'>ScottPlot 4</h2>"); | ||
sb.AppendLine($"<ul>"); | ||
sb.AppendLine($"<li>Core Library: {Total(sp4, "ScottPlot4"):N0} lines</li>"); | ||
sb.AppendLine($"<li>Tests: {Total(sp4, "ScottPlot.Tests"):N0} lines</li>"); | ||
sb.AppendLine($"<li>Cookbook: {Total(sp4, "ScottPlot.Cookbook"):N0} lines</li>"); | ||
sb.AppendLine($"<li>Demos: {Total(sp4, "ScottPlot.Demo"):N0} lines</li>"); | ||
sb.AppendLine($"<li>All: {Total(sp4):N0}</li>"); | ||
sb.AppendLine($"</ul>"); | ||
|
||
var sp5 = linesByFile.Where(x => x.Key.Contains(Path.DirectorySeparatorChar + "ScottPlot5" + Path.DirectorySeparatorChar)); | ||
sb.AppendLine("<h2 style='margin-bottom: 0px;'>ScottPlot 5</h2>"); | ||
sb.AppendLine($"<ul>"); | ||
sb.AppendLine($"<li>Core Library: {Total(sp5, "ScottPlot5"):N0}</li>"); | ||
sb.AppendLine($"<li>Tests: {Total(sp5, "ScottPlot5 Tests"):N0} lines</li>"); | ||
sb.AppendLine($"<li>Cookbook: {Total(sp5, "ScottPlot5 Cookbook"):N0} lines</li>"); | ||
sb.AppendLine($"<li>Demos: {Total(sp5, "ScottPlot5 Demos"):N0} lines</li>"); | ||
sb.AppendLine($"<li>All: {Total(sp5):N0}</li>"); | ||
sb.AppendLine($"</ul>"); | ||
|
||
var shared = linesByFile.Where(x => x.Key.Contains(Path.DirectorySeparatorChar + "Shared" + Path.DirectorySeparatorChar)); | ||
sb.AppendLine("<h2 style='margin-bottom: 0px;'>Shared Code</h2>"); | ||
sb.AppendLine($"<ul>"); | ||
sb.AppendLine($"<li>All: {Total(shared):N0} lines</li>"); | ||
sb.AppendLine($"</ul>"); | ||
|
||
sb.AppendLine($"<div align='center' style='margin-top: 100px;'>Generated {DateTime.Now}</div>"); | ||
|
||
/* | ||
foreach ((string filePath, int lineCount) in linesByFile) | ||
sb.AppendLine($"<div>{filePath} {lineCount}</div>"); | ||
*/ | ||
|
||
saveAs = Path.GetFullPath(saveAs); | ||
string html = HtmlTemplate.WrapInPico(sb.ToString()); | ||
Directory.CreateDirectory(Path.GetDirectoryName(saveAs)!); | ||
File.WriteAllText(saveAs, html); | ||
Console.WriteLine($"Wrote: {saveAs}"); | ||
} | ||
|
||
private static int Total(IEnumerable<KeyValuePair<string, int>> linesByFile, string? midFolderName = null) | ||
{ | ||
if (string.IsNullOrEmpty(midFolderName)) | ||
return linesByFile.Select(x => x.Value).Sum(); | ||
|
||
return linesByFile | ||
.Where(x => x.Key.Contains(Path.DirectorySeparatorChar + midFolderName + Path.DirectorySeparatorChar)) | ||
.Select(x => x.Value) | ||
.Sum(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
namespace CodeAnalysis.HtmlReports; | ||
|
||
public static class HtmlTemplate | ||
{ | ||
public static string WrapInPico(string content, string? title = null) | ||
{ | ||
return @"<!doctype html> | ||
<html lang='en'> | ||
<head> | ||
<meta charset='utf-8'> | ||
<meta name='viewport' content='width=device-width, initial-scale=1'> | ||
<link rel='stylesheet' href='https://unpkg.com/@picocss/pico@1.*/css/pico.min.css'> | ||
<title>{{TITLE}}</title> | ||
</head> | ||
<body> | ||
<main class='container'> | ||
{{CONTENT}} | ||
</main> | ||
</body> | ||
</html>".Replace("{{TITLE}}", title).Replace("{{CONTENT}}", content); | ||
} | ||
|
||
public static string WrapInBootstrap(string content, string? title = null) | ||
{ | ||
return @"<!doctype html> | ||
<html lang='en'> | ||
<head> | ||
<meta charset='utf-8'> | ||
<meta name='viewport' content='width=device-width, initial-scale=1'> | ||
<title>{{TITLE}}</title> | ||
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css'> | ||
</head> | ||
<body> | ||
<div class='container'>{{CONTENT}}</div> | ||
<script src='https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js'></script> | ||
</body> | ||
</html>".Replace("{{TITLE}}", title).Replace("{{CONTENT}}", content); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using System.Text; | ||
|
||
namespace CodeAnalysis.HtmlReports; | ||
|
||
public class ProjectSummaries | ||
{ | ||
MultiProjectReport Report { get; } | ||
|
||
public ProjectSummaries(MultiProjectReport report) | ||
{ | ||
Report = report; | ||
} | ||
|
||
private string GetContent() | ||
{ | ||
StringBuilder sb = new(); | ||
|
||
sb.AppendLine("<h1>ScottPlot Code Metrics</h1>"); | ||
|
||
sb.AppendLine("<h3>All Projects</h3>"); | ||
|
||
TableBuilder tb = new(); | ||
|
||
tb.AddHeader(new string[] { | ||
"Project", | ||
"Lines of Code", | ||
"Types", | ||
"Cyclomatic Complexity" }); | ||
|
||
foreach (ProjectReport project in Report.Projects) | ||
{ | ||
tb.AddRow(new string[] { | ||
project.ProjectName, | ||
$"{project.LinesOfCode:N0}", | ||
$"{project.Types:N0}", | ||
$"{project.CyclomaticComplexity:N0}" }); | ||
} | ||
|
||
sb.AppendLine(tb.GetHtml()); | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
public void Save(string htmlFilePath) | ||
{ | ||
string html = HtmlTemplate.WrapInPico(GetContent(), "ScottPlot Code Metrics"); | ||
string saveAs = Path.GetFullPath(htmlFilePath); | ||
File.WriteAllText(saveAs, html); | ||
Console.WriteLine($"Saved: {saveAs}"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.Text; | ||
|
||
namespace CodeAnalysis.HtmlReports; | ||
|
||
internal class TableBuilder | ||
{ | ||
StringBuilder Body = new(); | ||
|
||
public void AddHeader(string[] items) | ||
{ | ||
Body.AppendLine("<tr>"); | ||
foreach (string item in items) | ||
{ | ||
Body.AppendLine($"<th><strong>{item}</strong></th>"); | ||
} | ||
Body.AppendLine("</tr>"); | ||
} | ||
|
||
public void AddRow(string[] items) | ||
{ | ||
Body.AppendLine("<tr>"); | ||
foreach (string item in items) | ||
{ | ||
Body.AppendLine($"<td>{item}</td>"); | ||
} | ||
Body.AppendLine("</tr>"); | ||
} | ||
|
||
public string GetHtml() | ||
{ | ||
return $"<table>{Body}</table>"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System.Xml.Linq; | ||
|
||
namespace CodeAnalysis; | ||
|
||
public class Metrics | ||
{ | ||
public string? NamespaceName { get; set; } = null; | ||
public string? TypeName { get; set; } = null; | ||
public string FullTypeName => $"{NamespaceName}.{TypeName}"; | ||
|
||
public int? CyclomaticComplexity { get; set; } = null; | ||
public int? LinesOfCode { get; set; } = null; | ||
public int? ExecutableLines { get; set; } = null; | ||
public int? Maintainability { get; set; } = null; | ||
|
||
public static Metrics FromElement(XElement metricsElement, string namespaceName, string typeName) | ||
{ | ||
Metrics ms = new(); | ||
|
||
foreach (XElement metric in metricsElement.Elements("Metric")) | ||
{ | ||
string name = metric.Attribute("Name")!.Value.ToString(); | ||
int value = int.Parse(metric.Attribute("Value")!.Value); | ||
if (name == "CyclomaticComplexity") | ||
ms.CyclomaticComplexity = value; | ||
else if (name == "MaintainabilityIndex") | ||
ms.Maintainability = value; | ||
else if (name == "SourceLines") | ||
ms.LinesOfCode = value; | ||
else if (name == "ExecutableLines") | ||
ms.ExecutableLines = value; | ||
} | ||
|
||
return ms; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace CodeAnalysis; | ||
|
||
public class MultiProjectReport | ||
{ | ||
public Metrics[] Metrics { get; } | ||
public ProjectReport[] Projects { get; } | ||
|
||
public MultiProjectReport(string[] metricsFilePaths) | ||
{ | ||
Projects = metricsFilePaths.Select(x => new ProjectReport(x)).ToArray(); | ||
Metrics = Projects.SelectMany(x => x.Metrics).ToArray(); | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return $"Report spanning {Projects.Length} projects and {Metrics.Length} analyzed types"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using CodeAnalysis; | ||
|
||
string repoRoot = Path.GetFullPath(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "../../../../../")); | ||
|
||
/* | ||
string sourceFolder = Path.Combine(repoRoot, "src"); | ||
if (!Directory.Exists(sourceFolder)) | ||
throw new DirectoryNotFoundException(sourceFolder); | ||
string[] metricsFiles = Directory.GetFiles(sourceFolder, "*.Metrics.xml", SearchOption.AllDirectories); | ||
MultiProjectReport report = new(metricsFiles); | ||
Console.WriteLine(report); | ||
CodeAnalysis.HtmlReports.ProjectSummaries s = new(report); | ||
s.Save("summaries.html"); | ||
*/ | ||
|
||
string saveAs = Path.Combine(repoRoot, "dev/www/metrics/index.html"); | ||
CodeReport.Generate(repoRoot, saveAs); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using System.Xml.Linq; | ||
|
||
namespace CodeAnalysis; | ||
|
||
public class ProjectReport | ||
{ | ||
public string ProjectName { get; } | ||
public List<Metrics> Metrics { get; } = new(); | ||
|
||
public int LinesOfCode => Metrics.Select(x => x.LinesOfCode).Where(x => x.HasValue).Select(x => x!.Value).Sum(); | ||
public int CyclomaticComplexity => Metrics.Select(x => x.CyclomaticComplexity).Where(x => x.HasValue).Select(x => x!.Value).Sum(); | ||
|
||
public int Types => Metrics.Count; | ||
|
||
public ProjectReport(string xmlFilePath) | ||
{ | ||
ProjectName = Path.GetFileName(xmlFilePath).Replace(".Metrics.xml", ""); | ||
|
||
string xmlText = File.ReadAllText(xmlFilePath); | ||
XDocument doc = XDocument.Parse(xmlText); | ||
XElement assembly = doc.Descendants("Assembly").First(); | ||
|
||
foreach (XElement namespaceElement in assembly.Element("Namespaces")!.Elements("Namespace")) | ||
{ | ||
string namespaceName = namespaceElement.Attribute("Name")!.Value; | ||
|
||
foreach (XElement namedType in namespaceElement.Elements("Types").Elements("NamedType")) | ||
{ | ||
string typeName = namedType.Attribute("Name")!.Value; | ||
|
||
var metricsElement = namedType.Element("Metrics"); | ||
if (metricsElement is not null) | ||
{ | ||
Metrics.Add(CodeAnalysis.Metrics.FromElement(metricsElement, namespaceName, typeName)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return $"{ProjectName} with {Metrics.Count} metrics"; | ||
} | ||
} |