Skip to content

Post Revisions: Upgrade diff from v4 to v8 #77976

@manzoorwanijk

Description

@manzoorwanijk

What problem does this address?

The diff library is declared at ^4.0.2 in packages/editor and ^8.0.3 in packages/sync. The Syncpack alignment work (#77950, #77954) needs to converge these onto a single version across the monorepo, which means lifting editor to v8 (a four-major jump).

Bumping diff to ^8.0.3 in editor causes 51 unit tests to fail across block-diff.js, revision-fields-diff/index.js, revision-diff-panel/index.js, and preserve-client-ids.js. The failures fall into two classes:

1. LCS tie-breaker change (v6+)

diff v6 added "prefer deletions before insertions" as a tie-breaker. For inputs where multiple equal-length LCSes exist, v8 picks a different one than v4. Concrete example with prev=[First, Second], curr=[Second-modified, First]:

  • v4 picked First as the matched element → output [add Smod, match F, remove S]pairSimilarBlocks sees one removed/one added of core/paragraph and pairs them cleanly into [Smod-modified, F-unchanged].
  • v8 picks the whitespace/null block between paragraphs as the matched element → output [remove F, add Smod, match null, remove S, add F]pairSimilarBlocks sees two removed and two added paragraphs and uses similarity matching, which incorrectly pairs F-removed with Smod-added and S-removed with F-added. The user-visible result is two confusing inline diffs (<del>First</del><ins>Second</ins> block content <ins>modified</ins> etc.) instead of a clean modified+unchanged pair.

This is a real UX regression in the revision-diff feature, not just a test snapshot drift.

2. diffWords semantics change (v6+)

diff v6 stopped treating whitespace as a token. Adjacent word changes now coalesce into a single removed/added pair instead of being reported per-word. Example:

  • v4: Visit <a><del>our</del><ins>the</ins> <del>site</del><ins>website</ins></a> today (two precise inline diffs).
  • v8: Visit <a><del>our site</del><ins>the website</ins></a> today (one coarser diff).

Less precise but arguably still acceptable. Affects the rich-text inline diff display in revision previews.

What is your proposed solution?

Fix the consumer code in block-diff.js so v8's output produces the same user-visible behaviour as v4. The current tests encode the correct UX (clean modified+unchanged pairs, per-word inline diffs) and should keep passing without modification.

Class 1: LCS tie-breaker

Replace the direct diffArrays(previousSigs, currentSigs) call with a matching pass that prefers content-bearing blocks (paragraphs, headings, etc.) over freeform/whitespace blocks. Two viable approaches:

  • Filter the input. Strip null/whitespace rawBlock entries from both arrays before passing to diffArrays, then re-interleave them in the output in current-revision order. The LCS is then computed only over content-bearing blocks, sidestepping v8's preference for the whitespace match.
  • Custom LCS. Build the matching chain ourselves with a scoring function that weights content matches above whitespace matches. More invasive but gives full control over tie-breakers going forward.

The first approach is the smaller change and likely sufficient.

Class 2: diffWords granularity

For the rich-text inline diffs, switch from diffWords to diffWordsWithSpace (which still treats whitespace as tokens, preserving v4-style per-word output), or post-process diffWords output to split coalesced runs at whitespace boundaries.

Approach for the PR

  1. Bump diff to ^8.0.3 in packages/editor/package.json.
  2. Implement the Class 1 and Class 2 fixes above.
  3. Verify all affected tests pass without modifying assertions.
  4. Manually verify the post revisions UI in the editor — open a post with several revisions and confirm the inline word-level diffs and block add/remove/modify markers render the same as before the bump.

Background

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions