< Summary

Information
Class: DotNetApiDiff.Reporting.MarkdownFormatter
Assembly: DotNetApiDiff
File(s): /home/runner/work/dotnet-api-diff/dotnet-api-diff/src/DotNetApiDiff/Reporting/MarkdownFormatter.cs
Line coverage
94%
Covered lines: 118
Uncovered lines: 7
Coverable lines: 125
Total lines: 180
Line coverage: 94.4%
Branch coverage
91%
Covered branches: 31
Total branches: 34
Branch coverage: 91.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Format(...)85%202091.95%
FormatChangeGroup(...)100%1414100%

File(s)

/home/runner/work/dotnet-api-diff/dotnet-api-diff/src/DotNetApiDiff/Reporting/MarkdownFormatter.cs

#LineLine coverage
 1// Copyright DotNet API Diff Project Contributors - SPDX Identifier: MIT
 2using DotNetApiDiff.Interfaces;
 3using DotNetApiDiff.Models;
 4using System.Text;
 5
 6namespace DotNetApiDiff.Reporting;
 7
 8/// <summary>
 9/// Formatter for Markdown output with human-readable documentation
 10/// </summary>
 11public class MarkdownFormatter : IReportFormatter
 12{
 13    /// <summary>
 14    /// Formats a comparison result as Markdown
 15    /// </summary>
 16    /// <param name="result">The comparison result to format</param>
 17    /// <returns>Formatted Markdown output as a string</returns>
 18    public string Format(ComparisonResult result)
 519    {
 520        var output = new StringBuilder();
 21
 22        // Create header with title and assembly information
 523        output.AppendLine("# API Comparison Report");
 524        output.AppendLine();
 25
 26        // Add metadata section
 527        output.AppendLine("## Metadata");
 528        output.AppendLine();
 529        output.AppendLine("| Property | Value |");
 530        output.AppendLine("|----------|-------|");
 531        output.AppendLine($"| Source Assembly | `{Path.GetFileName(result.OldAssemblyPath)}` |");
 532        output.AppendLine($"| Target Assembly | `{Path.GetFileName(result.NewAssemblyPath)}` |");
 533        output.AppendLine($"| Comparison Date | {result.ComparisonTimestamp:yyyy-MM-dd HH:mm:ss} |");
 534        output.AppendLine($"| Total Differences | {result.TotalDifferences} |");
 35
 536        if (result.HasBreakingChanges)
 237        {
 738            output.AppendLine($"| Breaking Changes | **{result.Differences.Count(d => d.IsBreakingChange)}** |");
 239        }
 40
 541        output.AppendLine();
 42
 43        // Add summary section
 544        output.AppendLine("## Summary");
 545        output.AppendLine();
 546        output.AppendLine("| Change Type | Count |");
 547        output.AppendLine("|-------------|-------|");
 548        output.AppendLine($"| Added | {result.Summary.AddedCount} |");
 549        output.AppendLine($"| Removed | {result.Summary.RemovedCount} |");
 550        output.AppendLine($"| Modified | {result.Summary.ModifiedCount} |");
 551        output.AppendLine($"| Breaking Changes | {result.Summary.BreakingChangesCount} |");
 552        output.AppendLine($"| **Total Changes** | **{result.Summary.TotalChanges}** |");
 553        output.AppendLine();
 54
 55        // Add breaking changes section if any exist
 556        if (result.HasBreakingChanges)
 257        {
 258            output.AppendLine("## Breaking Changes");
 259            output.AppendLine();
 260            output.AppendLine("The following changes may break compatibility with existing code:");
 261            output.AppendLine();
 62
 263            output.AppendLine("| Type | Element | Description | Severity |");
 264            output.AppendLine("|------|---------|-------------|----------|");
 65
 2666            foreach (var change in result.Differences.Where(d => d.IsBreakingChange).OrderBy(d => d.Severity).ThenBy(d =
 367            {
 368                string severityText = change.Severity switch
 369                {
 070                    SeverityLevel.Critical => $"**{change.Severity}**",
 271                    SeverityLevel.Error => change.Severity.ToString(),
 172                    SeverityLevel.Warning => change.Severity.ToString(),
 073                    _ => change.Severity.ToString()
 374                };
 75
 376                output.AppendLine($"| {change.ElementType} | `{change.ElementName}` | {change.Description} | {severityTe
 377            }
 78
 279            output.AppendLine();
 280        }
 81
 82        // Group differences by change type
 1383        var addedItems = result.Differences.Where(d => d.ChangeType == ChangeType.Added).ToList();
 1384        var removedItems = result.Differences.Where(d => d.ChangeType == ChangeType.Removed).ToList();
 1385        var modifiedItems = result.Differences.Where(d => d.ChangeType == ChangeType.Modified).ToList();
 1386        var excludedItems = result.Differences.Where(d => d.ChangeType == ChangeType.Excluded).ToList();
 1387        var movedItems = result.Differences.Where(d => d.ChangeType == ChangeType.Moved).ToList();
 88
 89        // Add detailed sections for each change type
 590        if (addedItems.Any())
 291        {
 292            output.AppendLine($"## Added Items ({addedItems.Count})");
 293            output.AppendLine();
 294            FormatChangeGroup(output, addedItems);
 295        }
 96
 597        if (removedItems.Any())
 298        {
 299            output.AppendLine($"## Removed Items ({removedItems.Count})");
 2100            output.AppendLine();
 2101            FormatChangeGroup(output, removedItems);
 2102        }
 103
 5104        if (modifiedItems.Any())
 1105        {
 1106            output.AppendLine($"## Modified Items ({modifiedItems.Count})");
 1107            output.AppendLine();
 1108            FormatChangeGroup(output, modifiedItems);
 1109        }
 110
 5111        if (movedItems.Any())
 0112        {
 0113            output.AppendLine($"## Moved Items ({movedItems.Count})");
 0114            output.AppendLine();
 0115            FormatChangeGroup(output, movedItems);
 0116        }
 117
 118        // Add excluded items section if any exist (requirement 7.2)
 5119        if (excludedItems.Any())
 2120        {
 2121            output.AppendLine($"## Excluded/Unsupported Items ({excludedItems.Count})");
 2122            output.AppendLine();
 2123            output.AppendLine("The following items were intentionally excluded from the comparison:");
 2124            output.AppendLine();
 2125            FormatChangeGroup(output, excludedItems);
 2126        }
 127
 5128        return output.ToString();
 5129    }
 130
 131    private void FormatChangeGroup(StringBuilder output, List<ApiDifference> changes)
 7132    {
 133        // Group changes by element type for better organization
 23134        var groupedChanges = changes.GroupBy(c => c.ElementType).OrderBy(g => g.Key);
 135
 37136        foreach (var group in groupedChanges)
 8137        {
 8138            output.AppendLine($"### {group.Key}");
 8139            output.AppendLine();
 140
 8141            output.AppendLine("| Element | Description | Breaking |");
 8142            output.AppendLine("|---------|-------------|----------|");
 143
 48144            foreach (var change in group.OrderBy(c => c.ElementName))
 8145            {
 8146                string breakingText = change.IsBreakingChange ? "Yes" : "No";
 8147                output.AppendLine($"| `{change.ElementName}` | {change.Description} | {breakingText} |");
 148
 149                // Add signature details if available
 8150                if (!string.IsNullOrEmpty(change.OldSignature) || !string.IsNullOrEmpty(change.NewSignature))
 5151                {
 5152                    output.AppendLine();
 5153                    output.AppendLine("<details>");
 5154                    output.AppendLine("<summary>Signature Details</summary>");
 5155                    output.AppendLine();
 156
 5157                    if (!string.IsNullOrEmpty(change.OldSignature))
 3158                    {
 3159                        output.AppendLine("**Old:**");
 3160                        output.AppendLine("```csharp");
 3161                        output.AppendLine(change.OldSignature);
 3162                        output.AppendLine("```");
 3163                    }
 164
 5165                    if (!string.IsNullOrEmpty(change.NewSignature))
 3166                    {
 3167                        output.AppendLine("**New:**");
 3168                        output.AppendLine("```csharp");
 3169                        output.AppendLine(change.NewSignature);
 3170                        output.AppendLine("```");
 3171                    }
 172
 5173                    output.AppendLine("</details>");
 5174                }
 8175            }
 176
 8177            output.AppendLine();
 8178        }
 7179    }
 180}