6.0.0 (2025-06-13)
⚠ BREAKING CHANGES
- API Rename and Visibility:**
- The
diffItemfunction is no longer exported. Its functionality is now primarily internal. - A new function
diffValue(source: unknown, target: unknown, basePath?: Path): SanityPatchOperations[]is introduced and exported. This function generates an array ofSanityPatchOperations(which are plain objects like{set: {...}},{unset: [...]}) based on the differences betweensourceandtargetvalues. It does not wrap these operations in theSanityPatchMutationstructure. - The
diffPatchfunction (which diffs documents and returnsSanityPatchMutation[]) now internally callsdiffItemand then uses the refactoredserializePatchesto construct the final mutations. The logic for addingidandifRevisionIDto the patch mutations now resides withindiffPatch.
- The
- Patch Type Refinements:**
- Removed older, more generic patch types like
SetPatch,InsertAfterPatch,SanitySetPatch,SanityUnsetPatch,SanityInsertPatch, andSanityDiffMatchPatchfrom the public API (some were previously exported frompatches.ts). - Introduced new, more specific types for patch operations:
SanitySetPatchOperation({ set: Record<string, unknown> })SanityUnsetPatchOperation({ unset: string[] })SanityInsertPatchOperation({ insert: { before/after/replace: string, items: unknown[] } })SanityDiffMatchPatchOperation({ diffMatchPatch: Record<string, string> })
- The
SanityPatchOperationstype is now aPartialunion of these new operation types, reflecting that a single patch object fromdiffValuewill contain one or more of these operations. - The
SanityPatchtype (used withinSanityPatchMutation) nowextends SanityPatchOperationsand includesidand optionalifRevisionID. - The internal
Patchtype (used bydiffItem) remains but is now an internal detail.
- Removed older, more generic patch types like
- Refactored
serializePatchesFunction:- The
serializePatchesfunction now takes an array of internalPatchobjects and returns an array ofSanityPatchOperation[](the raw operation objects like{set: {...}}). - It no longer handles adding
idorifRevisionID; this responsibility is moved to thediffPatchfunction. - The logic for grouping
set,unset,insert, anddiffMatchPatchoperations into distinct objects in the output array has been improved for clarity.
- The
- Refactored
diffPatchFunction:- Now calls the internal
diffItemto get the raw patch list. - Calls the refactored
serializePatchesto getSanityPatchOperations[]. - Maps over these operations to create
SanityPatchMutation[], adding theidto each andifRevisionIDonly to the first patch mutation in the array.
- Now calls the internal
- JSDoc Updates:
- Updated JSDoc for
diffValueto clearly explain its purpose, parameters, and return type. - Updated JSDoc for
diffPatchand internal types to reflect the changes.
- Updated JSDoc for
Rationale:
- Clearer Public API:
diffValueprovides a more intuitive name for diffing arbitrary JavaScript values and returning the raw operations, distinct fromdiffPatchwhich is document-centric. - Improved Type Safety & Granularity: The new
Sanity...Operationtypes are more precise and make it easier to work with the different kinds of patch operations programmatically. - Correct
ifRevisionIDHandling: EnsuringifRevisionIDis only on the first patch of a transaction is crucial for correct optimistic locking in Sanity. - Better Separation of Concerns:
diffItemfocuses on generating a flat list of diffs,serializePatches(as used bydiffValue) groups them into operations, anddiffPatchhandles the document-specific concerns like_idandifRevisionID.
This refactor provides a cleaner and more robust API for generating patches, both for full documents and for arbitrary values.
- remove undefined-to-null conversion warnings and simplify internal APIs (#38)
* Removed the `diffMatchPatch` options (`enabled`, `lengthThresholdAbsolute`, `lengthThresholdRelative`) from `PatchOptions`.
* Removed the `DiffMatchPatchOptions` and `DiffOptions` (which included `diffMatchPatch`) interfaces from the public API.
* Removed the internal `mergeOptions` function and the DMP-specific parts of `defaultOptions`.
- New Performance-Based Heuristics for DMP:
- Introduced a new exported utility function
shouldUseDiffMatchPatch(source: string, target: string): boolean. This function encapsulates the new logic for deciding whether to use DMP. - The decision is now based on:
- Document Size Limit: Documents larger than 1MB (
DMP_MAX_DOCUMENT_SIZE) will usesetoperations. - Change Ratio Threshold: If more than 40% (
DMP_MAX_CHANGE_RATIO) of the text changes,setis used (indicates replacement vs. editing). - Small Document Optimization: Documents smaller than 10KB (
DMP_MIN_SIZE_FOR_RATIO_CHECK) always use DMP, as performance is consistently high for these. - System Key Protection: Properties starting with
_(system keys) continue to usesetoperations.
- Document Size Limit: Documents larger than 1MB (
- Added extensive JSDoc to
shouldUseDiffMatchPatchdetailing the heuristic rationale, performance characteristics (based on testing@sanity/diff-match-patchon an M2 MacBook Pro), algorithm details, and test methodology.
- Introduced a new exported utility function
- Internal Simplification:
- The internal
getDiffMatchPatchfunction now usesshouldUseDiffMatchPatchto make its decision and no longer accepts DMP-related options. - Simplified the call to the underlying
@sanity/diff-match-patchlibrary withingetDiffMatchPatchto usemakePatches(source, target)directly. This is more concise and leverages the internal optimizations of that library, with performance validated to be equivalent to the previous multi-step approach.
- The internal
- Constants: Introduced
SYSTEM_KEYS,DMP_MAX_DOCUMENT_SIZE,DMP_MAX_CHANGE_RATIO, andDMP_MIN_SIZE_FOR_RATIO_CHECKto define these thresholds. - Test Updates: Snapshots have been updated to reflect the new DMP behavior based on these heuristics.
Rationale for Change:
The previous configurable thresholds for DMP were somewhat arbitrary and could lead to suboptimal performance or overly verbose patches in certain scenarios. This change is based on empirical performance testing of the @sanity/diff-match-patch library itself. The new heuristics are designed to:
- Optimize for common editing patterns: Ensure fast performance for keystrokes and small pastes, which are the most frequent operations.
- Prevent performance degradation: Avoid triggering complex and potentially slow DMP algorithm paths when users perform large text replacements (e.g., pasting entirely new content).
- Simplify the API: Remove the burden of configuration from the user, providing sensible defaults.
- Maintain conflict-resistance: Continue to leverage DMP's strengths for collaborative editing where appropriate.
By hardcoding these well-tested heuristics, we aim for a more robust and performant string diffing strategy by default.
Features
- add key-based reordering support for keyed object arrays (#41) (27dcdc2)
- remove undefined-to-null conversion warnings and simplify internal APIs (#38) (86cff6e)
- replace
diffItemwithdiffValue(#39) (b8ad36a) - replace configurable DMP with perf-based heuristics (#36) (9577019)
Bug Fixes
- add repository field (d85b998)
This release is also available on: