Skip to content

Add API "matches" to comparison results alongside differences #53

@jbrinkman

Description

@jbrinkman

Summary

Add the ability to collect and return "matches" (types and members that are equivalent across old and new assemblies, including mapped namespaces and types) in addition to the existing differences. This helps quantify how much of the API has been migrated vs. remaining work.

Motivation

  • Validates which classes and methods are the same (including mapped namespaces/types).
  • Enables migration progress metrics (e.g., percentage matched).
  • Improves report usefulness by showing both what changed and what stayed the same.

Scope

  • Do not remove or break existing differences output.
  • Add a new "matches" collection in the comparison result, with supporting summary counts.
  • Include mappings where equivalence is due to configured mappings or auto-mapped simple names.

Proposed Changes

  1. Models
  • Update src/DotNetApiDiff/Models/ComparisonResult.cs
    • Add:
      • List<TypeMatch> TypeMatches
      • List<MemberMatch> MemberMatches
      • MatchSummary MatchSummary (counts: matched types, matched members)
  • New types in src/DotNetApiDiff/Models/:
    • TypeMatch
      • OldTypeFullName, NewTypeFullName, MatchKind (Direct|Mapped|AutoMapped), optional MappingNote
    • MemberMatch
      • ContainingOldType, ContainingNewType, OldSignature, NewSignature, MatchKind (Direct|Mapped|SignatureEquivalent), optional MappingNote
    • MatchSummary
      • MatchedTypeCount, MatchedMemberCount
  • Keep existing fields (e.g., Differences, Summary) unchanged for backward compatibility.
  1. Comparer logic
  • src/DotNetApiDiff/ApiExtraction/ApiComparer.cs
    • While performing comparison:
      • Record type matches when:
        • Direct full name match
        • _nameMapper.MapFullTypeName produces a mapped match
        • Auto-mapped simple-name match when enabled
      • Record member matches when:
        • Direct same-name + same full-name
        • Signatures are equivalent via AreSignaturesEquivalent(...)
    • Populate comparisonResult.TypeMatches, comparisonResult.MemberMatches, and comparisonResult.MatchSummary.
    • Avoid changing IApiComparer interface by collecting matches internally during existing CompareTypes/CompareMembers traversal.
  1. Reporting/Serialization
  • src/DotNetApiDiff/Reporting/JsonFormatter.cs
    • Add new top-level sections (camelCase):
      • typeMatches: array of { oldTypeFullName, newTypeFullName, matchKind, mappingNote? }
      • memberMatches: array of { containingOldType, containingNewType, oldSignature, newSignature, matchKind, mappingNote? }
      • matchSummary: { matchedTypeCount, matchedMemberCount }
    • Keep existing properties intact for backward compatibility.
  • ConsoleFormatter, MarkdownFormatter, HtmlFormatterScriban
    • Show match summary counts.
    • Optionally list matched items (behind a configuration flag if needed to limit verbosity).
  1. Configuration
  • src/DotNetApiDiff/Models/Configuration/ComparisonConfiguration.cs
    • New options:
      • IncludeMatches (bool, default true)
      • MaxMatchItems (int?, optional cap for listing)
  • CLI in CompareCommand:
    • --include-matches/--no-include-matches
    • Optional: --max-match-items <N>

Backward Compatibility

  • Existing consumers of ComparisonResult and JSON output are unaffected (new properties are additive).
  • IApiComparer interface remains unchanged.

Acceptance Criteria

  • Running a comparison with default config includes matches in the result and JSON.
  • Type matches include direct, mapped, and auto-mapped cases.
  • Member matches include direct and signature-equivalent (via mappings) cases.
  • Summary counts are accurate and covered by tests.
  • Feature can be disabled via configuration/CLI.
  • Formatters do not crash when matches are disabled or empty.

Testing

  • Unit tests for:
    • ApiComparer match detection for types and members (direct, mapped, auto-mapped, signature-equivalent).
    • JsonFormatter shape and casing including new fields.
    • Config toggles (IncludeMatches, MaxMatchItems).
  • Update/extend existing reporting tests to assert presence/absence of matches.

Open Questions

  • Do we want per-namespace match summaries?
  • Should HTML/Markdown list matched items by default, or only show counts unless IncludeMatchesVerbose is set?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions