feat: report valueChanged per preserved key in onReconciliation - #3274
christianhg wants to merge 1 commit into
Conversation
The reconciliation report said what happened to keys but not whether the content under a preserved key changed, and the first adopter immediately needed exactly that: detecting whether an edit touched `json:object` payloads it should have left alone. Every consumer would hand-roll the same deep-compare, and the library can answer more cheaply and exactly, since it holds each preserved node's stored counterpart at the moment of adoption. Each `preservedKeys` entry gains `valueChanged: boolean`: whether the node wearing that key in the returned value deep-equals its stored counterpart, identical fields and values with field order aside. Unlike the advisory `basis`, this is a stable fact of the invocation, safe to branch on, and the markDef-collision pin now demonstrates the difference the field exists to expose: an entry can carry `basis: 'content-unchanged'` with `valueChanged: true`, because a key fallback rewrote the span's `marks` reference after the match. The recorder gains a `storedCounterpart` WeakMap populated at the four sites that record a preservation basis. Verbatim and empty-run subtrees record pristine lockstep clones rather than self-references, so a mutation after adoption (the sibling-uniqueness pass renaming a duplicate stored key inside a preserved subtree) cannot fake a `false`; that hole was found in review and pinned red-first with a duplicate-keyed empty-run fixture. The compare is a local `deepEqualNodes` (order-insensitive fields, order-sensitive arrays, unexported), the report builder throws on a missing counterpart rather than defaulting, and nothing is recorded or compared when the callback is unset. Contracts moved with the field: fourteen existing full-report pins gained the literal, each derived from its fixture's semantics, the fuzz report-consistency oracle asserts the field against an independent local deep-equal and key map on every case, its corrupted-report meta-test rejects a flipped `valueChanged`, and a hardcoded-`false` mutation sends twenty tests red.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: d3ac697 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Bundle Stats✅ No significant changes. All scenario measurements (7)🗺️
Significant means at least 1.0 KB and 1% gzip, or at least 5 ms and 10% import time. |
feat: report
valueChangedper preserved key inonReconciliationEach
preservedKeysentry now carries avalueChangedboolean alongsidebasis,key, andpath: whether the node wearing that key in the returned value deep-equals its stored counterpart, identical fields and values with field order aside.falseis a guarantee, since a node the edit did not touch always comes back as the verbatim stored value, so filteringpreservedKeysforvalueChangedfinds exactly what an edit touched:The mechanism: the recorder gains a
storedCounterpartmap populated at the four adoption sites, and verbatim subtrees record pristine lockstep clones rather than self-references, so a mutation after adoption (the uniqueness pass renaming a duplicate stored key inside a preserved subtree) cannot fake afalse. That hole was found in review and is pinned red-first. The compare runs only when the callback is set, and the report builder throws on a missing counterpart rather than defaulting.One existing pin now demonstrates why the field earns its place next to
basis: a markDef key fallback produces an entry withbasis: 'content-unchanged'andvalueChanged: true, the advisory tier and the actual fact disagreeing exactly where a consumer would have been misled. Fourteen existing full-report pins gained the literal, the fuzz oracle asserts the field against an independent deep-equal on every case, and a hardcoded-falsemutation sends twenty tests red.Note
Low Risk
Additive @beta report field and comparison logic gated on onReconciliation; no change to reconciled output when the callback is omitted.
Overview
Adds
valueChangedto eachpreservedKeysentry in theonReconciliationreport (@portabletext/markdown), so callers can tell whether the returned node deep-equals its stored counterpart (field order ignored on objects; array order still matters). Unlike advisorybasis,valueChanged: falseis documented as safe to branch on—filtering preserved keys byvalueChangedsurfaces nodes the edit actually mutated.Implementation records a stored snapshot per adopted node via
ReconciliationRecorder.storedCounterpart, filled at adoption and mark-def sites; verbatim/reinserted subtrees pair against pristine clones so a later sibling-uniqueness key rename cannot incorrectly reportfalse. Report building runsdeepEqualNodesonly whenonReconciliationis set and throws if a preserved key lacks a counterpart.README and changeset document the API; reconciliation and fuzz tests assert the new field (including cases where
basissayscontent-unchangedbut the value did change).Reviewed by Cursor Bugbot for commit d3ac697. Bugbot is set up for automated code reviews on this repo. Configure here.