Skip to content

feat: user-defined equality, patch apply, generics, and extensibility - #2

Merged
christiangda merged 5 commits into
mainfrom
feat/extensibility-and-usability
Jul 23, 2026
Merged

feat: user-defined equality, patch apply, generics, and extensibility#2
christiangda merged 5 commits into
mainfrom
feat/extensibility-and-usability

Conversation

@christiangda

Copy link
Copy Markdown
Contributor

Summary

Implements the improvements identified in the API review, turning promised-but-missing behavior into real features and adding high-leverage capabilities. All additions are backward-compatible and remain stdlib-only (zero external dependencies).

What changed

🐞 Correctness / dead code

  • Equatable[T] / Comparable[T] now work. A type's Equals(T) bool or CompareTo(T) int method is honored automatically (custom comparators still take precedence). They were previously exported and documented but never consulted.
  • Unified diff now emits context lines. Replaced the placeholder with an LCS-based line diff producing proper context windows and consistent add/remove/context change types (the old code hard-coded _ = contextSize).
  • WithEquateEmpty(bool) — a real toggle for nil/empty-container equivalence (the old EquateEmpty() was enable-only).

🚀 New capabilities

  • ApplyJSONPatch — RFC 6902 applier (add/remove/replace/move/copy/test), closing the generate→apply loop.
  • Type-safe genericsEqualT[T], DeepEqualT[T], DiffT[T], CompareWithDiffT[T], GetJSONPatchT[T].
  • Context-aware comparisonEqualCtx/DiffCtx/CompareWithDiffCtx + ContextComparator, cancellable via context.Context.
  • WithFieldNaming(JSONTagNaming) — JSON-tag-aware paths and patch pointers so patches apply to real JSON documents.

🔧 Extensibility & ergonomics

  • WithReporter — stream each Difference as it's found.
  • Richer ignoresWithIgnorePaths, WithIgnorePathPatterns (regexp), WithIgnoreMapKeys, and the comparator:"-" struct tag.
  • RegisterFormatter — pluggable output formats (CSV, JUnit, SARIF, …). Unknown formats now return ErrUnknownFormat.
  • String() helpers for UnifiedDiff and VisualDiff.
  • Sentinel errorsErrUnknownFormat, ErrCanceled, ErrInvalidPatch.
  • Testing helpersAssertEqual/AssertNotEqual/RequireEqual (via a minimal TestingT interface, so testing isn't pulled into production builds).

📖 Docs & AI guidance

  • Updated README + docs/ and added Extensibility and Testing guides.
  • Merged the slashdevops/e5t and ds-utils conventions into .github/copilot-instructions.md, tailored to this stdlib-only library, and exposed it as AGENTS.md (symlink). Ticket-number and no-AI-coauthor rules from ds-utils were intentionally omitted as they don't fit this open-source repo.

⚠️ Behavior change

FormatDiff with an unknown format now returns ErrUnknownFormat instead of silently falling back to text. The existing test was updated to assert the new contract.

Verification

gofmt -l .        # clean
go vet ./...      # clean
go build ./...    # ok
go test -race -covermode=atomic ./...   # PASS, 82.7% coverage
go list -deps ... # no external deps

🤖 Generated with Claude Code

christiangda and others added 5 commits July 23, 2026 16:54
Honor the exported Equatable[T] and Comparable[T] interfaces (a type's
Equals/CompareTo method now decides equality, with custom comparators
still taking precedence). Replace the placeholder unified diff with an
LCS-based line diff that emits proper context windows and consistent
add/remove/context change types. Add field-path and regexp ignores, map
key ignores, the `comparator:"-"` struct tag, JSON-tag field naming,
a streaming reporter hook, and sentinel errors. FormatDiff now returns
ErrUnknownFormat for unknown formats instead of silently using text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a type-safe generic layer (EqualT, DeepEqualT, DiffT,
CompareWithDiffT, GetJSONPatchT). Add context-aware entry points
(EqualCtx, DiffCtx, CompareWithDiffCtx and the ContextComparator
interface) that stop early on cancellation. Add ApplyJSONPatch, an
RFC 6902 applier supporting add/remove/replace/move/copy/test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add RegisterFormatter/UnregisterFormatter so callers can teach FormatDiff
new output formats. Add String() helpers for UnifiedDiff and VisualDiff.
Add AssertEqual/AssertNotEqual/RequireEqual testing helpers that print a
readable diff on failure, using a minimal TestingT interface so the
testing package is not pulled into production builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add unit tests and executable examples for user-defined equality,
unified-diff context, the equate-empty toggle, context cancellation,
generics, JSON-tag naming, ApplyJSONPatch round-trips, the reporter hook,
richer ignore rules, the formatter registry, diff stringers, and the
assertion helpers. Update the format test for the new ErrUnknownFormat
contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the README and docs/ (configuration, diffing, json-patch,
custom-comparators, faq) and add extensibility and testing guides
covering generics, context, reporters, formatters, patch application,
and assertions. Rewrite the AI guidance (copilot-instructions.md) by
merging the slashdevops/e5t and ds-utils conventions, tailored to this
stdlib-only library, and expose it as AGENTS.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@christiangda christiangda self-assigned this Jul 23, 2026
@christiangda
christiangda merged commit b7dc470 into main Jul 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant