Skip to content

Commit

Permalink
Compact Formatter und Stability Index
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven authored and Sven committed Mar 22, 2022
1 parent 5eac8d1 commit 967daf0
Show file tree
Hide file tree
Showing 19 changed files with 219 additions and 96 deletions.
6 changes: 6 additions & 0 deletions ModuleAnalyzer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PsModuleAnalyzer.Core", "So
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PsModuleAnalyzer.DgmlFormatter", "Source\ModuleAnalyzer.DgmlFormatter\PsModuleAnalyzer.DgmlFormatter.csproj", "{B4DFC143-D3FA-4F46-9274-FB09C94F1228}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PsModuleAnaylzer.CSVFormatter", "..\PsModuleAnaylzer.CSV\PsModuleAnaylzer.CSVFormatter.csproj", "{DDF936E4-61F3-4199-A6C6-39A79A09BBD7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -27,6 +29,10 @@ Global
{B4DFC143-D3FA-4F46-9274-FB09C94F1228}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4DFC143-D3FA-4F46-9274-FB09C94F1228}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4DFC143-D3FA-4F46-9274-FB09C94F1228}.Release|Any CPU.Build.0 = Release|Any CPU
{DDF936E4-61F3-4199-A6C6-39A79A09BBD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDF936E4-61F3-4199-A6C6-39A79A09BBD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDF936E4-61F3-4199-A6C6-39A79A09BBD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDF936E4-61F3-4199-A6C6-39A79A09BBD7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using PsModuleAnalyzer.App.Visitor;
using PsModuleAnalyzer.Core.Factory;
using PsModuleAnalyzer.Core.Model;
using PsModuleAnalyzer.Core.Repository;

namespace PsModuleAnalyzer.App.Factory
{
Expand Down
4 changes: 2 additions & 2 deletions Source/ModuleAnalyzer.App/Output/MermaidOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public MermaidOutput(string destinationPath)
_destinationPath = destinationPath;
}

public void CreateAnalyzerOutupt(List<ModuleCommandCall> moduleCommandCalls)
public void CreateAnalyzerOutupt(ModuleDefinition moduleDefinition)
{
var content = CreateMarkdownContent(moduleCommandCalls);
var content = CreateMarkdownContent(moduleDefinition.ModuleCommandCalls);
WriteMarkdownFile(content);
}

Expand Down
5 changes: 4 additions & 1 deletion Source/ModuleAnalyzer.App/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using PsModuleAnalyzer.App.Output;
using PsModuleAnalyzer.Core.Anaylzer;
using PsModuleAnalyzer.DgmlFormatter;
using PsModuleAnaylzer.CSV;

namespace PsModuleAnalyzer.App
{
Expand All @@ -12,7 +13,9 @@ private static void Main(string[] args)
ModuleAnalyzer? analyzer = ModuleAnalyzerBuilder.Create("D:\\Repositories\\Go\\Source\\Go.psd1")
.AddCommandVisitor<DefaultCommandVisitorFactory>()
.AddDgmlFormatter("d:\\module.dgml")
.AddOutputWriter(new MermaidOutput("d:\\module.md"))
.AddCSVFormatter("d:\\module.csv")
.AddCSVFormatter("d:\\module-compact.csv", true)
.AddOutputFormatter(new MermaidOutput("d:\\module.md"))
.Build();

analyzer.Analyze();
Expand Down
1 change: 1 addition & 0 deletions Source/ModuleAnalyzer.App/PsModuleAnalyzer.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\PsModuleAnaylzer.CSV\PsModuleAnaylzer.CSVFormatter.csproj" />
<ProjectReference Include="..\ModuleAnalyzer.Core\PsModuleAnalyzer.Core.csproj" />
<ProjectReference Include="..\ModuleAnalyzer.DgmlFormatter\PsModuleAnalyzer.DgmlFormatter.csproj" />
</ItemGroup>
Expand Down
49 changes: 40 additions & 9 deletions Source/ModuleAnalyzer.App/Visitor/DefaultCommandVisitor.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
using PsModuleAnalyzer.Core.Model;
using PsModuleAnalyzer.Core.Repository;
using PsModuleAnalyzer.Core.Visitor;
using System.Management.Automation.Language;

namespace PsModuleAnalyzer.App.Visitor
{
public class DefaultCommandVisitor : CommandVisitor
{
public DefaultCommandVisitor(ModuleCommand moduleCommand, ModuleDefinition moduleRepository) :
base(moduleCommand, moduleRepository)
public DefaultCommandVisitor(ModuleCommand moduleCommand, ModuleDefinition moduleDefinition) :
base(moduleCommand, moduleDefinition)
{

}

public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
public override AstVisitAction VisitCommand(CommandAst commandAst)
{
return AstVisitAction.SkipChildren;
string? targetCommandName = commandAst.GetCommandName();

IModuleCommand? targetCommand = _moduleRepository.GetModuleCommand(targetCommandName);

if (targetCommand == null)
{
targetCommand = _moduleRepository.AddExternalModuleCommand(targetCommandName);
}

ModuleCommandCall? moduleCommandCall = new ModuleCommandCall(_moduleCommand, targetCommand, _moduleRepository);

_moduleRepository.AddModuleCommandCall(moduleCommandCall);

return AstVisitAction.Continue;
}

public override AstVisitAction VisitCommand(CommandAst commandAst)
public override AstVisitAction VisitCommandParameter(CommandParameterAst parameterAst)
{
string? targetCommandName = commandAst.GetCommandName();
var currentCall = _moduleRepository.ModuleCommandCalls.Last();
var currentParam = _moduleRepository.GetModuleCommandParameter(currentCall.Target.Name, parameterAst.ParameterName);

if(currentParam != null)
currentCall.Parameters.Add(currentParam);

return AstVisitAction.Continue;
}

public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst commandAst)
{
string? targetCommandName = commandAst.Name;

IModuleCommand? targetCommand = _moduleRepository.GetModuleCommand(targetCommandName);

Expand All @@ -29,11 +52,19 @@ public override AstVisitAction VisitCommand(CommandAst commandAst)
targetCommand = _moduleRepository.AddExternalModuleCommand(targetCommandName);
}

ModuleCommandCall? moduleCommandCall = new ModuleCommandCall(_moduleCommand, targetCommand);
ModuleCommandCall? moduleCommandCall = new ModuleCommandCall(_moduleCommand, targetCommand, _moduleRepository);
if(commandAst.Parameters != null)
{
foreach(var cmd in commandAst.Parameters)
{
var cmdParam = new ModuleCommandParameter(_moduleCommand, cmd.Name.ToString(), cmd.StaticType.Name);
moduleCommandCall.Parameters.Add(cmdParam);
}
}

_moduleRepository.AddModuleCommandCall(moduleCommandCall);

return AstVisitAction.SkipChildren;
return AstVisitAction.Continue;
}
}
}
70 changes: 16 additions & 54 deletions Source/ModuleAnalyzer.Core/Anaylzer/ModuleAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using PsModuleAnalyzer.Core.Factory;
using PsModuleAnalyzer.Core.Interfaces;
using PsModuleAnalyzer.Core.Model;
using PsModuleAnalyzer.Core.Repository;
using PsModuleAnalyzer.Core.Visitor;
using System.Management.Automation;
using System.Management.Automation.Language;
Expand All @@ -16,19 +15,15 @@ public class ModuleAnalyzer

internal ModuleAnalyzer(string modulePath)
{
PSModuleInfo? moduleInfo = LoadModuleFromPath(modulePath);
_moduleDefinition = new ModuleDefinition(moduleInfo.Name, moduleInfo.ModuleBase);

var commands = CreateModuleCommandList(moduleInfo).ToHashSet();
_moduleDefinition.AddModuleCommands(commands);
_moduleDefinition = new ModuleDefinition(modulePath);
}

public void AddOutputFormat(IAnalyzerOutput output)
{
AnalyzerOutputFormatters.Add(output);
}

public void SetFactory(CommandVisitorFactory factory)
public void SetCommandVisitorFactory(CommandVisitorFactory factory)
{
Factory = factory;
}
Expand All @@ -37,64 +32,31 @@ public void Analyze()
{
foreach (ModuleCommand? command in _moduleDefinition.ModuleCommands)
{
ScriptBlockAst? ast = Parser.ParseInput(
ScriptBlockAst ast = Parser.ParseInput(
command.Definition,
out Token[] tokens,
out ParseError[] errors
);

List<ParameterAst> paramastList = new();
var newAst = (ScriptBlockAst) ast.Copy();
if(ast.ParamBlock != null)
{
foreach (var param in ast.ParamBlock.Parameters)
paramastList.Add((ParameterAst)param.Copy());
}

FunctionDefinitionAst fast = new FunctionDefinitionAst(newAst.Extent, false, false, command.Name, paramastList, newAst);
CommandVisitor? commandVisitor = Factory.Create(command, _moduleDefinition);
ast.Visit(commandVisitor);
fast.Visit(commandVisitor);
}

CreateOutput(_moduleDefinition.ModuleCommandCalls);
CreateOutput();
}

private void CreateOutput(List<ModuleCommandCall> commandCalls)
private void CreateOutput()
{
AnalyzerOutputFormatters.ForEach(output => output.CreateAnalyzerOutupt(commandCalls));
}

private static PSModuleInfo LoadModuleFromPath(string modulePath)
{
PowerShell? ps = PowerShell.Create();
ps.AddScript("Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted; Get-ExecutionPolicy");
ps.Commands.AddScript($"Import-Module {modulePath} -PassThru");
return ps.Invoke<PSModuleInfo>().First();
}

private string GetCommandNamespace(string name, string abosoluteCommandPath)
{
return abosoluteCommandPath
.Replace(_moduleDefinition.Path, "")
.Replace($"{name}.ps1", "")
.Trim('\\')
.Replace("\\", ".");
}

private List<ModuleCommand> CreateModuleCommandList(PSModuleInfo moduleInfo)
{
List<ModuleCommand>? moduleCommandList = new List<ModuleCommand>();
foreach (KeyValuePair<string, FunctionInfo> command in moduleInfo.ExportedFunctions)
{
ModuleCommand? moduleCommand = new ModuleCommand(command.Value.Name, command.Value.Definition, GetCommandNamespace(command.Value.Name, command.Value.ScriptBlock.File));
try
{
foreach (KeyValuePair<string, ParameterMetadata> param in command.Value.Parameters)
{
ModuleCommandParameter? moduleCommandParam = new ModuleCommandParameter(moduleCommand, param.Value.Name, param.Value.ParameterType.Name);
moduleCommand.Parameters.Add(moduleCommandParam);
}
}
catch
{
Console.WriteLine("Param Error");
}


moduleCommandList.Add(moduleCommand);
}
return moduleCommandList;
AnalyzerOutputFormatters.ForEach(output => output.CreateAnalyzerOutupt(_moduleDefinition));
}
}
}
4 changes: 2 additions & 2 deletions Source/ModuleAnalyzer.Core/Anaylzer/ModuleAnalyzerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static ModuleAnalyzerBuilder Create(string modulePath)
return new ModuleAnalyzerBuilder(modulePath);
}

public ModuleAnalyzerBuilder AddOutputWriter(IAnalyzerOutput output)
public ModuleAnalyzerBuilder AddOutputFormatter(IAnalyzerOutput output)
{
_analyzerOutputs.Add(output);
return this;
Expand All @@ -34,7 +34,7 @@ public ModuleAnalyzerBuilder AddOutputWriter(IAnalyzerOutput output)
public ModuleAnalyzer Build()
{
ModuleAnalyzer? analyzer = new ModuleAnalyzer(_modulePath);
analyzer.SetFactory(_factory);
analyzer.SetCommandVisitorFactory(_factory);

_analyzerOutputs.ForEach(output => analyzer.AddOutputFormat(output));
return analyzer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using PsModuleAnalyzer.Core.Model;
using PsModuleAnalyzer.Core.Repository;
using PsModuleAnalyzer.Core.Visitor;

namespace PsModuleAnalyzer.Core.Factory
Expand Down
2 changes: 1 addition & 1 deletion Source/ModuleAnalyzer.Core/Interfaces/IAnalyzerOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ namespace PsModuleAnalyzer.Core.Interfaces
{
public interface IAnalyzerOutput
{
public void CreateAnalyzerOutupt(List<ModuleCommandCall> commandCalls);
public void CreateAnalyzerOutupt(ModuleDefinition moduleDefinition);
}
}
3 changes: 2 additions & 1 deletion Source/ModuleAnalyzer.Core/Model/IModuleCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ public interface IModuleCommand
string Namespace { get; }
int NumberOfReferencedBy { get; set; }
List<ModuleCommandParameter> Parameters { get; }
List<ModuleCommand> ReferencedBy { get; }
List<IModuleCommand> References { get; }
List<IModuleCommand> ReferencedBy { get; }
bool IsExternal { get; }

Dictionary<string, string> GetParametersAsDictionary();
Expand Down
51 changes: 46 additions & 5 deletions Source/ModuleAnalyzer.Core/Model/ModuleCommand.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
namespace PsModuleAnalyzer.Core.Model
using System.Linq;

namespace PsModuleAnalyzer.Core.Model
{
public class ModuleCommand : IModuleCommand
{
private readonly string _commandFile;

public string Name { get; private set; }
public string Definition { get; private set; }
public List<ModuleCommand> References { get; private set; } = new();
public List<ModuleCommand> ReferencedBy { get; private set; } = new();
public ModuleDefinition Module { get; private set; }
public List<IModuleCommand> References { get => CalculateReferences(); }
public List<IModuleCommand> ReferencedBy { get => CalculateReferencedBy(); }
public List<ModuleCommandParameter> Parameters { get; private set; } = new();
public int NumberOfReferencedBy { get; set; } = 0;
public bool IsExternal { get; }
public string Namespace { get; private set; }

public ModuleCommand(string name, string definition, string @namespace)
public decimal StabilityIndex { get => CalculateStabilityIndex(); }


public ModuleCommand(string name, string definition, string commandFile, ModuleDefinition module)
{
Name = name;
Definition = definition;
IsExternal = false;
Namespace = @namespace;
Module = module;
_commandFile = commandFile;

ConfigureNamespace();
}

public Dictionary<string, string> GetParametersAsDictionary()
Expand All @@ -28,5 +39,35 @@ public Dictionary<string, string> GetParametersAsDictionary()
}
return parameters;
}

private List<IModuleCommand> CalculateReferencedBy()
{
return Module.ModuleCommandCalls
.Where(cmd => cmd.Target.Name == Name)
.Select(cmd => cmd.Source)
.ToList();
}

private List<IModuleCommand> CalculateReferences()
{
return Module.ModuleCommandCalls
.Where(cmd => cmd.Source.Name == Name)
.Select(cmd => cmd.Source)
.ToList();
}

private decimal CalculateStabilityIndex()
{
return Math.Round((decimal) CalculateReferences().Count / (CalculateReferences().Count + CalculateReferencedBy().Count), 3);
}

private void ConfigureNamespace()
{
Namespace = _commandFile
.Replace(Module.Path, "")
.Replace($"{Name}.ps1", "")
.Trim('\\')
.Replace("\\", ".");
}
}
}
15 changes: 12 additions & 3 deletions Source/ModuleAnalyzer.Core/Model/ModuleCommandCall.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
namespace PsModuleAnalyzer.Core.Model
using System.Reflection;

namespace PsModuleAnalyzer.Core.Model
{
public class ModuleCommandCall
{
public readonly IModuleCommand Target;
private readonly ModuleDefinition _module;
public readonly IModuleCommand Source;
public readonly IModuleCommand Target;
public readonly List<ModuleCommandParameter> Parameters = new();
public int References { get => CalculateReferences(); }

public ModuleCommandCall(IModuleCommand source, IModuleCommand target)
public ModuleCommandCall(IModuleCommand source, IModuleCommand target, ModuleDefinition module)
{
_module = module;
Source = source;
Target = target;
}

private int CalculateReferences()
=> _module.ModuleCommandCalls
.Count(calls => calls.Source.Name == Source.Name && calls.Target.Name == Target.Name);
}
}
Loading

0 comments on commit 967daf0

Please sign in to comment.