Files
renamer/internal/replace/summary.go

81 lines
2.0 KiB
Go

package replace
import "sort"
// ConflictDetail describes a rename that could not be applied.
type ConflictDetail struct {
OriginalPath string
ProposedPath string
Reason string
}
// Summary aggregates metrics for previews, applies, and ledger entries.
type Summary struct {
TotalCandidates int
ChangedCount int
PatternMatches map[string]int
Conflicts []ConflictDetail
Duplicates []string
EmptyReplacement bool
}
// NewSummary constructs an initialized summary.
func NewSummary() Summary {
return Summary{
PatternMatches: make(map[string]int),
}
}
// AddDuplicate records a duplicate pattern supplied by the user.
func (s *Summary) AddDuplicate(pattern string) {
if pattern == "" {
return
}
s.Duplicates = append(s.Duplicates, pattern)
}
// AddResult incorporates an individual candidate replacement result.
// RecordCandidate updates aggregate counts for a processed candidate and any matches.
func (s *Summary) RecordCandidate(res Result) {
s.TotalCandidates++
if !res.Changed {
return
}
s.ChangedCount++
for pattern, count := range res.Matches {
s.PatternMatches[pattern] += count
}
}
// AddConflict appends a conflict detail to the summary.
func (s *Summary) AddConflict(conflict ConflictDetail) {
s.Conflicts = append(s.Conflicts, conflict)
}
// SortedDuplicates returns de-duplicated duplicates list for reporting.
func (s *Summary) SortedDuplicates() []string {
if len(s.Duplicates) == 0 {
return nil
}
copyList := make([]string, 0, len(s.Duplicates))
seen := make(map[string]struct{}, len(s.Duplicates))
for _, dup := range s.Duplicates {
if _, ok := seen[dup]; ok {
continue
}
seen[dup] = struct{}{}
copyList = append(copyList, dup)
}
sort.Strings(copyList)
return copyList
}
// ReplacementWasEmpty records whether the replacement string is empty and returns true.
func (s *Summary) ReplacementWasEmpty(replacement string) bool {
if replacement == "" {
s.EmptyReplacement = true
return true
}
return false
}