Releases: Open-Tech-Foundation/obj-diff
Releases · Open-Tech-Foundation/obj-diff
Release list
@opentf/obj-diff@0.17.0
Added
stringify(value)/parse(wire)— a general-purpose, type-safe JSON codec for any JavaScript value (the counterpart toserialize/deserialize, which are diff-specific). Built on the same wire codec, so it preserves every supported native type (Date,RegExp,Map,Set, allTypedArrays,ArrayBuffer,DataView,Error,URL, boxed primitives,BigInt,NaN/±Infinity/-0,undefined,Temporal) plus circular references and shared identity among plain objects and arrays, nested to any depth. Symbols, functions, and class instances throw.serialize/deserializenow support circular references and shared identity for plain objects and arrays. Any plain container reachable by more than one edge within an op is hoisted into the$refstable as anobj/arrentry and referenced by token, so cycles (obj.self = obj, mutually linked nodes, self-referential arrays) and objects shared in two places rebuild with the same identity on the far side. Single-use containers still serialize inline as readable JSON, so output for the common case is unchanged. Cycles that run through aMap/Set/Errorstill throw.serialize/deserializenow supportURLvalues.
@opentf/obj-diff@0.16.0
Added
serialize(diff)/deserialize(wire)— a self-describing JSON wire format for diffs.diff()returns live objects by reference, soJSON.stringifymangles them (Date→string,Map/Set→{},TypedArray→numeric-keyed object,BigInt→throws).serializekeepsvalue/pathreadable but replaces each special value with a lightweight reference token"@n"and collects the real types in a per-op$refstable ({ "n": { _t, _v } });deserializeresolves the tokens back into live typed values so apatch()on the far side reconstructs the correct objects. CoversDate,RegExp,Map,Set, allTypedArrays,ArrayBuffer,DataView,Error(+ standard subclasses), boxed primitives,BigInt,NaN/±Infinity/-0,undefined, andTemporalvalues, nested to any depth (incl.Map/Set/object keys inpath). Real strings shaped like"@n"are escaped. Symbols, functions, class instances, and circular references throw. Deserializing aTemporalvalue needs aTemporalimplementation onglobalThis.- Native diffing support for all Temporal types (
Temporal.Instant,PlainDate,PlainTime,PlainDateTime,PlainYearMonth,PlainMonthDay,ZonedDateTime,Duration). They are compared as immutable, atomic values — replaced wholesale via a singleCHANGEDop when they differ, and preserved by reference throughpatch(). Equality uses each type's own.equals();Duration(which has no.equals()) is compared structurally by its canonical string, so two equal-length but differently-expressed durations (e.g.PT2HvsPT120M) are treated as a change and the exact value is reconstructed on patch. Detection is brand-based (Symbol.toStringTag), so it works with the native global or the@js-temporal/polyfill.
@opentf/obj-diff@0.15.0
Fixed
- Fixed
patch()losingnullprototypes of nested objects; previously only the root object'snullprototype was preserved. - Fixed two invalid
Dates (NaNtimestamps) being reported as changed; they now compare as equal, consistent withNaN === NaNhandling for primitives. - Fixed
Errorobjects with equal messages but different custom properties (or different error classes with the same message) comparing as equal. Errors now compare by prototype,name,messageand own enumerable properties, and are replaced wholesale when they differ. - Fixed boxed primitives (
new Number(),new String(),new Boolean()) ignoring custom properties: equal-valued boxes now diff their own enumerable properties; different values report a replacement. - Fixed class instances always comparing as equal: non-plain objects fell through to a string comparison where both sides stringify to
[object Object]. Instances sharing the same prototype are now diffed by their own enumerable properties, and instances of different classes are reported as replaced. - Fixed
patch()corruptingMaps that use object keys: cloning the map broke key reference identity, so patches missed the entry and inserted a duplicate key instead. Non-primitive patch keys are now matched against existing map keys by structural equality. - Fixed
patch()mutating the target object it was diffed against: the sparse array cleanup walked the whole result, following values inserted by reference, and compacted sparse arrays belonging to the caller's objects. - Fixed
patch()compacting sparse arrays that no patch touched, shifting indices of unrelated data. Array cleanup is now limited to arrays that actually received deletions, and only trailing holes are truncated — so patching to a sparse target (e.g.[1, 2, 3]→[1, , 3]) now round-trips correctly. - Fixed
patch()producing a wrongSetwhen shrinking it by two or more elements.Setdeletions are now emitted in descending index order so sequential removal during patching no longer shifts pending indices. - Fixed asymmetrical circular reference diffing to avoid false positives and stack overflows.
- Improved comparison of unhandled object types (e.g.
RegExp) by falling back to string value comparison. - Fixed deep
patch()traversal failing when encounteringSetcollections. - Fixed sparse array cleanup after patching to also cover arrays nested within
Mapvalues andSetelements.
Changed
patch()now throws a descriptiveTypeErrornaming the failing path when a patch references a path that does not exist in the object, instead of an opaque error from deep inside the traversal.- Objects that are the same reference now short-circuit as equal without a deep walk.
- The
DiffResultpathtype widened fromArray<string | number>toArray<unknown>: object keys are strings and array/Set indexes are numbers as before, butMapentries use the map key itself, which can be a value of any type.
Added
- Compact array diffs: two new array-only op types —
INSERTED(type: 3, splice the value in at the index) andREMOVED(type: 4, splice the element out) — with application-time indexes.diff()now trims the common prefix and suffix of arrays and emits splice ops for insertion/removal runs, so inserting one element at the front of a 10k-element array produces 1 op instead of 10,001. Existing types0/1/2keep their exact semantics and previously serialized patches still apply. Sparse arrays and arrays with non-index properties keep the previous key-based diff. - Shortest edit scripts for arrays: after prefix/suffix trimming, the remaining middle window is resolved with a bounded Myers LCS diff, so interleaved edits (remove + insert elsewhere + change) produce one op per actual edit — a mixed edit on 10k elements dropped from 9,998 ops to 4. Adjacent delete+insert pairs are zipped into granular recursive replacements, and the algorithm falls back to positional alignment when the edit-distance/cost cap is exceeded, bounding worst-case time and memory.
- Exported the diff type constants (
DELETED,ADDED,CHANGED,INSERTED,REMOVED) and theDiffTypetype from the package root. - Native diffing support for
ArrayBufferandDataView: contents are compared byte-by-byte (includingbyteOffset/byteLengthfor views) instead of always comparing as equal via the string fallback. - Native diffing and patching support for all JavaScript TypedArrays (
Uint8Array,Float32Array,BigInt64Array, etc.) allowing precise element-level diffs and preserving array types during patching. - Added comprehensive accuracy evaluation script (
evaluate.js) covering ES6 collections and edge cases. - Added updated benchmark competitors (
deep-diff-ts,@adobe/optimized-diff). - Updated README.md with detailed Accuracy vs Performance matrices.
@opentf/obj-diff@0.14.0
Minor Changes
- e475557: - Added comprehensive JSDoc documentation to all public API symbols (diff, diffWith, patch, DiffResult) to improve JSR score and developer experience.
- Fixed an issue where the JSR publish was failing due to uncommitted build artifacts by adding the --allow-dirty flag.
- Updated GitHub Actions to opt-in to Node.js 24, future-proofing the CI/CD pipeline.
@opentf/obj-diff@0.13.1
Patch Changes
- 5f0b4e6: Update pkg readme with updated docs.
@opentf/obj-diff@0.13.0
Minor Changes
- 5d846d9: - Modernized the entire build and test pipeline using Bun and a custom ESBuild-based bundling script.
- Significantly improved core robustness by fixing infinite recursion on circular references in
patch(). - Enhanced array diffing to correctly handle sparse array holes and non-numeric properties.
- Added preservation for
nullprototypes during the patching process. - Refined
diffWith()to support "Explicit Equality" by allowing the custom comparator to returnfalseto bypass deep-diffing. - Consolidated GitHub Actions into streamlined CI and Release workflows with integrated JSR and NPM support.
- Significantly improved core robustness by fixing infinite recursion on circular references in
@opentf/obj-diff@0.12.0
Minor Changes
- e5b61db: Added value prop to the Set removed diff results.
@opentf/obj-diff@0.11.0
Minor Changes
- 01f7696: Added deep diffing support for Map & Set objects.
@opentf/obj-diff@0.10.0
Minor Changes
- b32e7c8: Fixed circular refs.
@opentf/obj-diff@0.9.0
Minor Changes
- 39521b0: Fixed other object null type checking.