static void Main(string[] args) { var fileContents = File.ReadAllText(@"D:\workshop\pitstop\pitstop.analyzed.json"); Types = JsonConvert.DeserializeObject <List <TypeDescription> >(fileContents, JsonDefaults.DeserializerSettings()).ToList(); var type = Types.FirstOrDefault("Pitstop.TimeService.Events.DayHasPassed"); Types.PopulateInheritedBaseTypes(); Types.PopulateInheritedMembers(); Console.WriteLine("Base types:"); foreach (var baseType in type.BaseTypes) { Console.WriteLine($"- {baseType}"); } Console.WriteLine(); Console.WriteLine("Fields:"); foreach (var field in type.Fields) { Console.WriteLine($"- {field.Name}"); } Console.WriteLine(); Console.WriteLine("Commands:"); var commands = Types.Where(t => t.ImplementsType("Pitstop.Infrastructure.Messaging.Command")); foreach (var command in commands) { Console.WriteLine($"- {command.FullName}"); } Console.WriteLine(); Console.WriteLine("Events:"); var @events = Types.Where(t => t.ImplementsType("Pitstop.Infrastructure.Messaging.Event")); foreach (var @event in @events) { Console.WriteLine($"- {@event.FullName}"); } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Command Handlers:"); var commandHandlers = Types .Where(t => t.IsClass() && t.Methods.Any(m => m.Parameters.Any(p => p.Attributes.Any(a => a.Type.Equals("Microsoft.AspNetCore.Mvc.FromBodyAttribute"))))) .ToDictionary(t => t.FullName, t => t.Methods.Where(m => m.Parameters.Any(p => p.Attributes.Any(a => a.Type.Equals("Microsoft.AspNetCore.Mvc.FromBodyAttribute")))).Select(m => Types.First(m.Parameters.Last().Type).Name).ToList()); foreach (var kv in commandHandlers) { Console.WriteLine(kv.Key); foreach (var @namespace in kv.Value) { Console.WriteLine($"- {@namespace}"); } Console.WriteLine(); } var eventHandlerClasses = Types .Where(t => t.IsClass() && t.ImplementsType("Pitstop.Infrastructure.Messaging.IMessageHandlerCallback")) .Where(t => t.Methods.Any(m => m.Name == "HandleAsync" && m.Parameters.Any(p => Types.First(p.Type).ImplementsType("Pitstop.Infrastructure.Messaging.Event")))) .Select(t => (EventHandlerClass: t, Events: t.Methods.Where(m => m.Name == "HandleAsync" && m.Parameters.Any(p => Types.First(p.Type).ImplementsType("Pitstop.Infrastructure.Messaging.Event"))).Select(m => Types.First(m.Parameters[0].Type).Name).ToList())); // Pivot events and handlers var query = from ehc in eventHandlerClasses from e in ehc.Events group ehc.EventHandlerClass.Namespace by e into g select g; Console.WriteLine(); Console.WriteLine("Event Receiving Services:"); foreach (var group in query) { Console.WriteLine(group.Key); foreach (var @namespace in group) { Console.WriteLine($"- {@namespace}"); } Console.WriteLine(); } Console.WriteLine(); Console.WriteLine("Trace Statements:"); var customerController = Types.First("Pitstop.Application.CustomerManagementAPI.Controllers.CustomersController"); var handlingMethod = customerController.Methods.First(m => m.Name == "RegisterAsync" && m.Parameters[0].Type == "Pitstop.CustomerManagementAPI.Commands.RegisterCustomer"); var messagePublishStatements = handlingMethod.Statements.SelectMany(s => FlattenStatements(s).OfType <InvocationDescription>().Where(s => s.Name == "PublishMessageAsync")); foreach (var statement in messagePublishStatements) { Console.WriteLine($"When a RegisterCustomer command is handled, a {Types.First(statement.Arguments[1].Type).Name} event will be published."); } }
static void Main(string[] args) { var fileContents = File.ReadAllText(@"D:\workshop\pitstop\pitstop.analyzed.json"); Types = JsonConvert.DeserializeObject <List <TypeDescription> >(fileContents, JsonDefaults.DeserializerSettings()).ToList(); Types.PopulateInheritedBaseTypes(); Types.PopulateInheritedMembers(); var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Pitstop Generated Documentation"); stringBuilder.AppendLine(); stringBuilder.AppendLine("## Service Architecture"); stringBuilder.AppendLine(); stringBuilder.AppendLine("![Pitstop solution architecture](https://github.com/EdwinVW/pitstop/wiki/img/solution-architecture.png)"); stringBuilder.AppendLine(); stringBuilder.AppendLine("## Commands"); stringBuilder.AppendLine(); foreach (var group in Types.Where(t => t.ImplementsType("Pitstop.Infrastructure.Messaging.Command")) .GroupBy(t => t.Name) .OrderBy(g => g.Key)) { stringBuilder.AppendLine($"### {group.Key.ToSentenceCase()}"); stringBuilder.AppendLine(); stringBuilder.AppendLine("#### Services"); stringBuilder.AppendLine(); foreach (var command in group.OrderBy(c => c.Namespace)) { stringBuilder.AppendLine($"- {command.Namespace.Split('.').Reverse().Skip(1).First().ToSentenceCase()}"); } stringBuilder.AppendLine(); if (group.SelectMany(t => t.Fields).Any()) { stringBuilder.AppendLine("#### Fields"); stringBuilder.AppendLine(); stringBuilder.AppendLine("|Property|Type|Description|"); stringBuilder.AppendLine("|-|-|-|"); foreach (var field in group.SelectMany(t => t.Fields) .GroupBy(f => (f.Type, f.Name)) .Select(g => g.First()) .OrderBy(f => f.Name)) { stringBuilder.AppendLine($"|{field.Name}|{field.Type.ForDiagram()}|{field.DocumentationComments?.Summary}|"); } stringBuilder.AppendLine(); var type = group.First(); if (Types.CommandHandlerFor(type) != null) { RenderCommandDiagram(stringBuilder, type); } else { stringBuilder.AppendLine("> ❗ No command handler found"); stringBuilder.AppendLine(); } } } stringBuilder.AppendLine("## Events"); stringBuilder.AppendLine(); foreach (var group in Types.Where(t => t.ImplementsType("Pitstop.Infrastructure.Messaging.Event")) .GroupBy(t => t.Name) .OrderBy(t => t.Key)) { stringBuilder.AppendLine($"### {group.Key.ToSentenceCase()}"); stringBuilder.AppendLine(); stringBuilder.AppendLine("#### Services"); stringBuilder.AppendLine(); foreach (var @event in group.OrderBy(e => e.Namespace)) { stringBuilder.AppendLine($"- {@event.Namespace.Split('.').Reverse().Skip(1).First().ToSentenceCase()}"); } stringBuilder.AppendLine(); if (group.SelectMany(t => t.Fields).Any()) { stringBuilder.AppendLine("#### Fields"); stringBuilder.AppendLine(); stringBuilder.AppendLine("|Property|Type|Description|"); stringBuilder.AppendLine("|-|-|-|"); foreach (var field in group.SelectMany(t => t.Fields) .GroupBy(f => (f.Type, f.Name)) .Select(g => g.First()) .OrderBy(f => f.Name)) { stringBuilder.AppendLine($"|{field.Name}|{field.Type.ForDiagram()}|{field.DocumentationComments?.Summary}|"); } stringBuilder.AppendLine(); } } stringBuilder.AppendLine("## Aggregates"); stringBuilder.AppendLine(); foreach (var aggregateRoot in Types.Where(t => t.ImplementsTypeStartsWith("Pitstop.WorkshopManagementAPI.Domain.Core.AggregateRoot<"))) { stringBuilder.AppendLine($"### {aggregateRoot.Name.ToSentenceCase()}"); stringBuilder.AppendLine(); var aggregateIDType = Types.First(aggregateRoot.BaseTypes.First(bt => bt.StartsWith("Pitstop.WorkshopManagementAPI.Domain.Core.AggregateRoot<")).GenericTypes().First()); stringBuilder.AppendLine("```plantuml"); stringBuilder.UmlDiagramStart(); RenderClass(stringBuilder, aggregateIDType); stringBuilder.AppendLine($"{aggregateIDType.Name} -- {aggregateRoot.Name}"); RenderClass(stringBuilder, aggregateRoot); stringBuilder.UmlDiagramEnd(); stringBuilder.AppendLine("```"); stringBuilder.AppendLine(); } File.WriteAllText("pitstop.generated.md", stringBuilder.ToString()); }
static void Main(string[] args) { var fileContents = File.ReadAllText(@"D:\workshop\pitstop\pitstop.analyzed.json"); Types = JsonConvert.DeserializeObject <List <TypeDescription> >(fileContents, JsonDefaults.DeserializerSettings()).ToList(); Types.PopulateInheritedBaseTypes(); Types.PopulateInheritedMembers(); var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Pitstop Generated Documentation"); stringBuilder.AppendLine(); stringBuilder.AppendLine("## Service Architecture"); stringBuilder.AppendLine(); stringBuilder.AppendLine("![Pitstop solution architecture](https://github.com/EdwinVW/pitstop/wiki/img/solution-architecture.png)"); stringBuilder.AppendLine(); stringBuilder.AppendLine("## Commands"); stringBuilder.AppendLine(); foreach (var group in Types.Where(t => t.ImplementsType("Pitstop.Infrastructure.Messaging.Command")) .GroupBy(t => t.Name) .OrderBy(g => g.Key)) { stringBuilder.AppendLine($"### {group.Key.ToSentenceCase()}"); stringBuilder.AppendLine(); stringBuilder.AppendLine("#### Services"); stringBuilder.AppendLine(); foreach (var command in group.OrderBy(c => c.Namespace)) { stringBuilder.AppendLine($"- {command.Namespace.Split('.').Reverse().Skip(1).First().ToSentenceCase()}"); } stringBuilder.AppendLine(); if (group.SelectMany(t => t.Fields).Any()) { stringBuilder.AppendLine("#### Fields"); stringBuilder.AppendLine(); stringBuilder.AppendLine("|Property|Type|Description|"); stringBuilder.AppendLine("|-|-|-|"); foreach (var field in group.SelectMany(t => t.Fields) .GroupBy(f => (f.Type, f.Name)) .Select(g => g.First()) .OrderBy(f => f.Name)) { stringBuilder.AppendLine($"|{field.Name}|{field.Type.ForDiagram()}|{field.DocumentationComments?.Summary}|"); } stringBuilder.AppendLine(); } } stringBuilder.AppendLine("## Events"); stringBuilder.AppendLine(); foreach (var group in Types.Where(t => t.ImplementsType("Pitstop.Infrastructure.Messaging.Event")) .GroupBy(t => t.Name) .OrderBy(t => t.Key)) { stringBuilder.AppendLine($"### {group.Key.ToSentenceCase()}"); stringBuilder.AppendLine(); stringBuilder.AppendLine("#### Services"); stringBuilder.AppendLine(); foreach (var @event in group.OrderBy(e => e.Namespace)) { stringBuilder.AppendLine($"- {@event.Namespace.Split('.').Reverse().Skip(1).First().ToSentenceCase()}"); } stringBuilder.AppendLine(); if (group.SelectMany(t => t.Fields).Any()) { stringBuilder.AppendLine("#### Fields"); stringBuilder.AppendLine(); stringBuilder.AppendLine("|Property|Type|Description|"); stringBuilder.AppendLine("|-|-|-|"); foreach (var field in group.SelectMany(t => t.Fields) .GroupBy(f => (f.Type, f.Name)) .Select(g => g.First()) .OrderBy(f => f.Name)) { stringBuilder.AppendLine($"|{field.Name}|{field.Type.ForDiagram()}|{field.DocumentationComments?.Summary}|"); } stringBuilder.AppendLine(); } } File.WriteAllText("pitstop.generated.md", stringBuilder.ToString()); }