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
- 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.
- 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.
- 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).
- 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?
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
Scope
Proposed Changes
src/DotNetApiDiff/Models/ComparisonResult.csList<TypeMatch> TypeMatchesList<MemberMatch> MemberMatchesMatchSummary MatchSummary(counts: matched types, matched members)src/DotNetApiDiff/Models/:TypeMatchOldTypeFullName,NewTypeFullName,MatchKind(Direct|Mapped|AutoMapped), optionalMappingNoteMemberMatchContainingOldType,ContainingNewType,OldSignature,NewSignature,MatchKind(Direct|Mapped|SignatureEquivalent), optionalMappingNoteMatchSummaryMatchedTypeCount,MatchedMemberCountDifferences,Summary) unchanged for backward compatibility.src/DotNetApiDiff/ApiExtraction/ApiComparer.cs_nameMapper.MapFullTypeNameproduces a mapped matchAreSignaturesEquivalent(...)comparisonResult.TypeMatches,comparisonResult.MemberMatches, andcomparisonResult.MatchSummary.IApiComparerinterface by collecting matches internally during existingCompareTypes/CompareMemberstraversal.src/DotNetApiDiff/Reporting/JsonFormatter.cstypeMatches: array of{ oldTypeFullName, newTypeFullName, matchKind, mappingNote? }memberMatches: array of{ containingOldType, containingNewType, oldSignature, newSignature, matchKind, mappingNote? }matchSummary:{ matchedTypeCount, matchedMemberCount }ConsoleFormatter,MarkdownFormatter,HtmlFormatterScribansrc/DotNetApiDiff/Models/Configuration/ComparisonConfiguration.csIncludeMatches(bool, default true)MaxMatchItems(int?, optional cap for listing)CompareCommand:--include-matches/--no-include-matches--max-match-items <N>Backward Compatibility
ComparisonResultand JSON output are unaffected (new properties are additive).IApiComparerinterface remains unchanged.Acceptance Criteria
Testing
ApiComparermatch detection for types and members (direct, mapped, auto-mapped, signature-equivalent).JsonFormattershape and casing including new fields.IncludeMatches,MaxMatchItems).Open Questions
IncludeMatchesVerboseis set?