Skip to content

Post Revisions: Upgrade diff from v4 to v8#77992

Open
manzoorwanijk wants to merge 4 commits into
trunkfrom
upgrade/diff-to-v8
Open

Post Revisions: Upgrade diff from v4 to v8#77992
manzoorwanijk wants to merge 4 commits into
trunkfrom
upgrade/diff-to-v8

Conversation

@manzoorwanijk
Copy link
Copy Markdown
Member

@manzoorwanijk manzoorwanijk commented May 6, 2026

What?

Closes #77976

Upgrades the diff library from ^4.0.2 to ^8.0.3 in packages/editor and packages/block-editor, and updates the post-revisions consumer code so the four-major bump is invisible to users — the in-editor revisions UI keeps the same block pairing and inline word-level diff output it produced under v4.

Why?

The diff library was declared at ^4.0.2 in editor / block-editor and ^8.0.3 in sync, blocking the cross-workspace Syncpack alignment work (#77950, #77954). Bumping editor to ^8.0.3 is a four-major jump that, on its own, breaks four unit tests in block-diff.js and surfaces real UX regressions in the post-revisions feature. The failures fall into two unrelated upstream behaviour changes:

  1. LCS tie-breaker change (v6+). v6 added a "prefer deletions before insertions" tie-breaker, which selects a different LCS for inputs where multiple equal-length matches exist. The relevant case here is prev=[paragraph, whitespace, paragraph] versus curr=[paragraph_modified, whitespace, paragraph]: v8 picks the whitespace pseudo-block as the LCS anchor, so pairSimilarBlocks then sees two removed and two added paragraphs and similarity-matches dissimilar pairs — producing two confusing inline diffs instead of a clean modified+unchanged pair.
  2. diffWords semantics change (v6+). v6 stopped treating whitespace as a token, so adjacent word changes coalesce into one removed/added pair. Inline rich-text diffs lose precision: Visit <a><del>our</del><ins>the</ins> <del>site</del><ins>website</ins></a> today (per-word) becomes Visit <a><del>our site</del><ins>the website</ins></a> today (one coarser diff).

Both are real user-visible regressions, not snapshot drift.

How?

1. Bump the dependency

  • packages/editor/package.json and packages/block-editor/package.json: diff^8.0.3. (packages/sync was already on v8.)

2. Filter whitespace pseudo-blocks before LCS

packages/editor/src/components/post-revisions-preview/block-diff.jsdiffRawBlocks now strips freeform/whitespace pseudo-blocks (the \n\n between block markers) from both arrays before passing them to diffArrays. With those out of the picture, v8's tie-breaker selects the same content-block LCS anchor v4 did for every previously-failing case. Whitespace pseudo-blocks aren't rendered (parseRawBlock returns undefined for them), so dropping them before the diff has no user-visible effect.

pairSimilarBlocks's placement heuristic was extended to match: it previously decided where to anchor a paired modification by checking whether any added block sat between the removed and added positions. Now that whitespace pseudo-blocks are no longer in the result list, an unchanged content block between the two positions is the only "the modified block crosses current-revision content" signal — so the heuristic also fires on unchanged blocks (but still ignores removed blocks, which don't exist in the current revision and so don't count as crossing).

3. Switch rich-text and field diffs to diffWordsWithSpace

  • block-diff.js: applyRichTextDiff and applyDiffToBlock (sidebar changedAttributes) now call diffWordsWithSpace from the top-level diff import. v8's diffWordsWithSpace keeps whitespace as its own token, matching v4's diffWords semantics.
  • revision-fields-diff/index.js: meta field diffs likewise use diffWordsWithSpace.

4. Migrate remaining diff imports to top-level

preserve-client-ids.js and block-compare/index.js used deep paths like 'diff/lib/diff/array'. v8's package.json exports map only wildcards ./lib/*.js (with extension); the bare-folder ./lib/ mapping requires a trailing slash. The deep paths only resolve here because the bundler/Jest resolver fills in .js — a future tooling change could break them. v8 also declares sideEffects: false in its per-output sub-manifests (libcjs/package.json and libesm/package.json), which webpack 4+ honours, so the historical tree-shaking reason for the deep imports no longer applies. The "diff doesn't tree-shake correctly" comment in block-compare/index.js was true for v4 but is now stale and gets removed.

5. Relax one test assertion

The 'handles two blocks that swapped positions' test was asserting which block stayed unmarked vs. which became removed/added. For a pure swap, both LCS choices are equally valid — both v4 and v8 produce semantically-correct output, they just disagree on which block reads as "unchanged." The test now asserts the user-facing invariant (one unmarked + one removed/added pair with same content) instead of the implementation choice.

6. CHANGELOG entries

Added ### Internal entries to packages/editor/CHANGELOG.md and packages/block-editor/CHANGELOG.md recording the major dependency bump.

Testing Instructions

Automated:

npm run test:unit -- -- packages/editor/src/components/post-revisions-preview/ \
                       packages/editor/src/components/revision-fields-diff/ \
                       packages/editor/src/components/revision-diff-panel/ \
                       packages/block-editor/src/components/block-compare/

Expected: 42/42 pass. Full npm run test:unit is also green (32538/32545, 7 unrelated skips).

Manual (golden path for the revisions UI):

  1. Start wp-env (npm run wp-env start) and create a post with several paragraphs.
  2. Edit and save the post a few times to build up a revision history. Mix the kinds of changes:
    • Add a couple of new paragraphs above an existing one and slightly tweak its wording.
    • Swap two paragraphs.
    • Inside a paragraph, change one word inside a link (e.g. our sitethe website).
    • Add <strong> / <em> formatting to part of a paragraph.
  3. Open the post's revisions preview (Document → Revisions → click a prior revision).
  4. Verify the following render the same as on trunk before the bump:
    • The slightly-tweaked paragraph shows as a single modified block with a clean inline <del>…</del><ins>…</ins> diff, not two confusing pair-ups.
    • For a pure swap, exactly one block stays unmarked and the other shows as a removed+added pair with the same content (which side gets matched is implementation-defined — see below).
    • Inside-link word changes show per-word (our → the and site → website as two separate diffs), not coalesced into one.
    • Format-only changes (added bold, changed link URL) render as revision-diff-format-* spans on just the affected range.
  5. Open the Meta panel in the document sidebar during revision mode (if any meta keys differ) and confirm word-level diffs there are also per-word.

Testing Instructions for Keyboard

No UI changes; existing keyboard navigation through the revisions panel is unaffected.

Screenshots or screencast

Before (v8 with no consumer fix) After (this PR)
<del>First</del><ins>Second</ins> block content <ins>modified</ins> + a second confusing inline diff for the unchanged sibling Single modified block with Second block content<ins> modified</ins>; the unchanged sibling stays unmarked
Visit <a><del>our site</del><ins>the website</ins></a> today (one coarse diff) Visit <a><del>our</del><ins>the</ins> <del>site</del><ins>website</ins></a> today (per-word)

Use of AI Tools

This PR was authored with the assistance of Claude Code (Opus 4.7). All edits, the test results, and the manual testing steps were reviewed and verified by me.

@manzoorwanijk manzoorwanijk requested a review from ellatrix as a code owner May 6, 2026 04:53
@github-actions github-actions Bot added [Package] Editor /packages/editor [Package] Block editor /packages/block-editor labels May 6, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: manzoorwanijk <manzoorwanijk@git.wordpress.org>
Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: ellatrix <ellatrix@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@manzoorwanijk manzoorwanijk self-assigned this May 6, 2026
@manzoorwanijk manzoorwanijk added the [Type] Task Issues or PRs that have been broken down into an individual action to take label May 6, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Size Change: +866 B (+0.01%)

Total Size: 7.93 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 343 kB +82 B (+0.02%)
build/scripts/editor/index.min.js 429 kB +784 B (+0.18%)
ℹ️ View Unchanged
Filename Size
build/modules/a11y/index.min.js 355 B
build/modules/abilities/index.min.js 42.3 kB
build/modules/block-editor/utils/fit-text-frontend.min.js 617 B
build/modules/block-library/accordion/view.min.js 595 B
build/modules/block-library/file/view.min.js 346 B
build/modules/block-library/form/view.min.js 528 B
build/modules/block-library/image/view.min.js 2.64 kB
build/modules/block-library/navigation/view.min.js 1.14 kB
build/modules/block-library/playlist/view.min.js 10.9 kB
build/modules/block-library/query/view.min.js 518 B
build/modules/block-library/search/view.min.js 498 B
build/modules/block-library/tabs/view.min.js 946 B
build/modules/boot/index.min.js 19.1 kB
build/modules/connectors/index.min.js 2.05 kB
build/modules/content-types/index.min.js 135 kB
build/modules/core-abilities/index.min.js 907 B
build/modules/edit-site-init/index.min.js 1.4 kB
build/modules/interactivity-router/full-page.min.js 451 B
build/modules/interactivity-router/index.min.js 11.6 kB
build/modules/interactivity/index.min.js 15.3 kB
build/modules/latex-to-mathml/index.min.js 56.5 kB
build/modules/latex-to-mathml/loader.min.js 131 B
build/modules/lazy-editor/index.min.js 14.1 kB
build/modules/route/index.min.js 25.2 kB
build/modules/vips/loader.min.js 127 B
build/modules/vips/worker.min.js 4.56 MB
build/modules/workflow/index.min.js 19.9 kB
build/scripts/a11y/index.min.js 1.06 kB
build/scripts/annotations/index.min.js 2.49 kB
build/scripts/api-fetch/index.min.js 2.83 kB
build/scripts/autop/index.min.js 2.18 kB
build/scripts/base-styles/index.min.js 98 B
build/scripts/blob/index.min.js 631 B
build/scripts/block-directory/index.min.js 10.3 kB
build/scripts/block-library/index.min.js 320 kB
build/scripts/block-serialization-default-parser/index.min.js 1.16 kB
build/scripts/block-serialization-spec-parser/index.min.js 3.08 kB
build/scripts/blocks/index.min.js 57 kB
build/scripts/commands/index.min.js 21 kB
build/scripts/components/index.min.js 266 kB
build/scripts/compose/index.min.js 11.1 kB
build/scripts/core-commands/index.min.js 4.33 kB
build/scripts/core-data/index.min.js 31 kB
build/scripts/customize-widgets/index.min.js 14.6 kB
build/scripts/data-controls/index.min.js 795 B
build/scripts/data/index.min.js 9.66 kB
build/scripts/date/index.min.js 23.6 kB
build/scripts/deprecated/index.min.js 756 B
build/scripts/dom-ready/index.min.js 476 B
build/scripts/dom/index.min.js 5 kB
build/scripts/edit-post/index.min.js 18.7 kB
build/scripts/edit-site/index.min.js 265 kB
build/scripts/edit-widgets/index.min.js 22.2 kB
build/scripts/element/index.min.js 5.17 kB
build/scripts/escape-html/index.min.js 587 B
build/scripts/format-library/index.min.js 13.1 kB
build/scripts/hooks/index.min.js 1.83 kB
build/scripts/html-entities/index.min.js 494 B
build/scripts/i18n/index.min.js 2.47 kB
build/scripts/is-shallow-equal/index.min.js 572 B
build/scripts/keyboard-shortcuts/index.min.js 1.61 kB
build/scripts/keycodes/index.min.js 1.56 kB
build/scripts/list-reusable-blocks/index.min.js 2.49 kB
build/scripts/media-utils/index.min.js 79.9 kB
build/scripts/notices/index.min.js 1.85 kB
build/scripts/nux/index.min.js 1.89 kB
build/scripts/patterns/index.min.js 7.96 kB
build/scripts/plugins/index.min.js 2.15 kB
build/scripts/preferences-persistence/index.min.js 2.15 kB
build/scripts/preferences/index.min.js 3.3 kB
build/scripts/primitives/index.min.js 1.01 kB
build/scripts/priority-queue/index.min.js 1.62 kB
build/scripts/private-apis/index.min.js 1.11 kB
build/scripts/react-i18n/index.min.js 833 B
build/scripts/redux-routine/index.min.js 3.37 kB
build/scripts/reusable-blocks/index.min.js 3.1 kB
build/scripts/rich-text/index.min.js 14 kB
build/scripts/router/index.min.js 5.96 kB
build/scripts/server-side-render/index.min.js 1.91 kB
build/scripts/shortcode/index.min.js 1.59 kB
build/scripts/style-engine/index.min.js 2.42 kB
build/scripts/sync/index.min.js 38.8 kB
build/scripts/theme/index.min.js 22.3 kB
build/scripts/token-list/index.min.js 739 B
build/scripts/undo-manager/index.min.js 918 B
build/scripts/upload-media/index.min.js 11.2 kB
build/scripts/url/index.min.js 3.98 kB
build/scripts/vendors/react-dom.min.js 43.3 kB
build/scripts/vendors/react-jsx-runtime.min.js 667 B
build/scripts/vendors/react.min.js 2.77 kB
build/scripts/viewport/index.min.js 1.22 kB
build/scripts/warning/index.min.js 454 B
build/scripts/widgets/index.min.js 7.8 kB
build/scripts/wordcount/index.min.js 1.04 kB
build/styles/base-styles/admin-schemes-rtl.css 1.71 kB
build/styles/base-styles/admin-schemes-rtl.min.css 775 B
build/styles/base-styles/admin-schemes.css 1.71 kB
build/styles/base-styles/admin-schemes.min.css 775 B
build/styles/block-directory/style-rtl.css 1.97 kB
build/styles/block-directory/style-rtl.min.css 1.06 kB
build/styles/block-directory/style.css 1.98 kB
build/styles/block-directory/style.min.css 1.06 kB
build/styles/block-editor/content-rtl.css 5.44 kB
build/styles/block-editor/content-rtl.min.css 4.01 kB
build/styles/block-editor/content.css 5.44 kB
build/styles/block-editor/content.min.css 4.01 kB
build/styles/block-editor/default-editor-styles-rtl.css 697 B
build/styles/block-editor/default-editor-styles-rtl.min.css 224 B
build/styles/block-editor/default-editor-styles.css 697 B
build/styles/block-editor/default-editor-styles.min.css 224 B
build/styles/block-editor/style-rtl.css 18.7 kB
build/styles/block-editor/style-rtl.min.css 15.9 kB
build/styles/block-editor/style.css 18.7 kB
build/styles/block-editor/style.min.css 15.9 kB
build/styles/block-library/accordion-heading/style-rtl.css 346 B
build/styles/block-library/accordion-heading/style-rtl.min.css 325 B
build/styles/block-library/accordion-heading/style.css 346 B
build/styles/block-library/accordion-heading/style.min.css 325 B
build/styles/block-library/accordion-item/style-rtl.css 239 B
build/styles/block-library/accordion-item/style-rtl.min.css 180 B
build/styles/block-library/accordion-item/style.css 238 B
build/styles/block-library/accordion-item/style.min.css 180 B
build/styles/block-library/accordion-panel/style-rtl.css 110 B
build/styles/block-library/accordion-panel/style-rtl.min.css 99 B
build/styles/block-library/accordion-panel/style.css 110 B
build/styles/block-library/accordion-panel/style.min.css 99 B
build/styles/block-library/accordion/style-rtl.css 69 B
build/styles/block-library/accordion/style-rtl.min.css 62 B
build/styles/block-library/accordion/style.css 69 B
build/styles/block-library/accordion/style.min.css 62 B
build/styles/block-library/archives/style-rtl.css 101 B
build/styles/block-library/archives/style-rtl.min.css 90 B
build/styles/block-library/archives/style.css 101 B
build/styles/block-library/archives/style.min.css 90 B
build/styles/block-library/audio/editor-rtl.css 166 B
build/styles/block-library/audio/editor-rtl.min.css 149 B
build/styles/block-library/audio/editor.css 166 B
build/styles/block-library/audio/editor.min.css 151 B
build/styles/block-library/audio/style-rtl.css 945 B
build/styles/block-library/audio/style-rtl.min.css 132 B
build/styles/block-library/audio/style.css 945 B
build/styles/block-library/audio/style.min.css 132 B
build/styles/block-library/audio/theme-rtl.css 967 B
build/styles/block-library/audio/theme-rtl.min.css 134 B
build/styles/block-library/audio/theme.css 967 B
build/styles/block-library/audio/theme.min.css 134 B
build/styles/block-library/avatar/editor-rtl.css 127 B
build/styles/block-library/avatar/editor-rtl.min.css 115 B
build/styles/block-library/avatar/editor.css 127 B
build/styles/block-library/avatar/editor.min.css 115 B
build/styles/block-library/avatar/style-rtl.css 117 B
build/styles/block-library/avatar/style-rtl.min.css 104 B
build/styles/block-library/avatar/style.css 117 B
build/styles/block-library/avatar/style.min.css 104 B
build/styles/block-library/breadcrumbs/style-rtl.css 233 B
build/styles/block-library/breadcrumbs/style-rtl.min.css 203 B
build/styles/block-library/breadcrumbs/style.css 233 B
build/styles/block-library/breadcrumbs/style.min.css 203 B
build/styles/block-library/button/editor-rtl.css 306 B
build/styles/block-library/button/editor-rtl.min.css 265 B
build/styles/block-library/button/editor.css 317 B
build/styles/block-library/button/editor.min.css 265 B
build/styles/block-library/button/style-rtl.css 651 B
build/styles/block-library/button/style-rtl.min.css 596 B
build/styles/block-library/button/style.css 662 B
build/styles/block-library/button/style.min.css 596 B
build/styles/block-library/buttons/editor-rtl.css 391 B
build/styles/block-library/buttons/editor-rtl.min.css 291 B
build/styles/block-library/buttons/editor.css 391 B
build/styles/block-library/buttons/editor.min.css 291 B
build/styles/block-library/buttons/style-rtl.css 452 B
build/styles/block-library/buttons/style-rtl.min.css 349 B
build/styles/block-library/buttons/style.css 453 B
build/styles/block-library/buttons/style.min.css 349 B
build/styles/block-library/calendar/style-rtl.css 271 B
build/styles/block-library/calendar/style-rtl.min.css 239 B
build/styles/block-library/calendar/style.css 271 B
build/styles/block-library/calendar/style.min.css 239 B
build/styles/block-library/categories/editor-rtl.css 171 B
build/styles/block-library/categories/editor-rtl.min.css 132 B
build/styles/block-library/categories/editor.css 170 B
build/styles/block-library/categories/editor.min.css 131 B
build/styles/block-library/categories/style-rtl.css 226 B
build/styles/block-library/categories/style-rtl.min.css 169 B
build/styles/block-library/categories/style.css 235 B
build/styles/block-library/categories/style.min.css 169 B
build/styles/block-library/classic-rtl.css 402 B
build/styles/block-library/classic-rtl.min.css 358 B
build/styles/block-library/classic.css 402 B
build/styles/block-library/classic.min.css 358 B
build/styles/block-library/code/editor-rtl.css 59 B
build/styles/block-library/code/editor-rtl.min.css 53 B
build/styles/block-library/code/editor.css 59 B
build/styles/block-library/code/editor.min.css 53 B
build/styles/block-library/code/style-rtl.css 158 B
build/styles/block-library/code/style-rtl.min.css 140 B
build/styles/block-library/code/style.css 178 B
build/styles/block-library/code/style.min.css 140 B
build/styles/block-library/code/theme-rtl.css 135 B
build/styles/block-library/code/theme-rtl.min.css 122 B
build/styles/block-library/code/theme.css 135 B
build/styles/block-library/code/theme.min.css 122 B
build/styles/block-library/columns/editor-rtl.css 119 B
build/styles/block-library/columns/editor-rtl.min.css 108 B
build/styles/block-library/columns/editor.css 119 B
build/styles/block-library/columns/editor.min.css 108 B
build/styles/block-library/columns/style-rtl.css 1.3 kB
build/styles/block-library/columns/style-rtl.min.css 421 B
build/styles/block-library/columns/style.css 1.3 kB
build/styles/block-library/columns/style.min.css 421 B
build/styles/block-library/comment-author-avatar/editor-rtl.css 136 B
build/styles/block-library/comment-author-avatar/editor-rtl.min.css 124 B
build/styles/block-library/comment-author-avatar/editor.css 136 B
build/styles/block-library/comment-author-avatar/editor.min.css 124 B
build/styles/block-library/comment-author-name/style-rtl.css 79 B
build/styles/block-library/comment-author-name/style-rtl.min.css 72 B
build/styles/block-library/comment-author-name/style.css 79 B
build/styles/block-library/comment-author-name/style.min.css 72 B
build/styles/block-library/comment-content/style-rtl.css 137 B
build/styles/block-library/comment-content/style-rtl.min.css 120 B
build/styles/block-library/comment-content/style.css 137 B
build/styles/block-library/comment-content/style.min.css 120 B
build/styles/block-library/comment-date/style-rtl.css 72 B
build/styles/block-library/comment-date/style-rtl.min.css 65 B
build/styles/block-library/comment-date/style.css 72 B
build/styles/block-library/comment-date/style.min.css 65 B
build/styles/block-library/comment-edit-link/style-rtl.css 77 B
build/styles/block-library/comment-edit-link/style-rtl.min.css 70 B
build/styles/block-library/comment-edit-link/style.css 77 B
build/styles/block-library/comment-edit-link/style.min.css 70 B
build/styles/block-library/comment-reply-link/style-rtl.css 78 B
build/styles/block-library/comment-reply-link/style-rtl.min.css 71 B
build/styles/block-library/comment-reply-link/style.css 78 B
build/styles/block-library/comment-reply-link/style.min.css 71 B
build/styles/block-library/comment-template/style-rtl.css 213 B
build/styles/block-library/comment-template/style-rtl.min.css 191 B
build/styles/block-library/comment-template/style.css 213 B
build/styles/block-library/comment-template/style.min.css 191 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.css 135 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.min.css 122 B
build/styles/block-library/comments-pagination-numbers/editor.css 144 B
build/styles/block-library/comments-pagination-numbers/editor.min.css 121 B
build/styles/block-library/comments-pagination/editor-rtl.css 184 B
build/styles/block-library/comments-pagination/editor-rtl.min.css 168 B
build/styles/block-library/comments-pagination/editor.css 184 B
build/styles/block-library/comments-pagination/editor.min.css 168 B
build/styles/block-library/comments-pagination/style-rtl.css 224 B
build/styles/block-library/comments-pagination/style-rtl.min.css 201 B
build/styles/block-library/comments-pagination/style.css 236 B
build/styles/block-library/comments-pagination/style.min.css 201 B
build/styles/block-library/comments-title/editor-rtl.css 83 B
build/styles/block-library/comments-title/editor-rtl.min.css 75 B
build/styles/block-library/comments-title/editor.css 83 B
build/styles/block-library/comments-title/editor.min.css 75 B
build/styles/block-library/comments/editor-rtl.css 968 B
build/styles/block-library/comments/editor-rtl.min.css 842 B
build/styles/block-library/comments/editor.css 968 B
build/styles/block-library/comments/editor.min.css 842 B
build/styles/block-library/comments/style-rtl.css 754 B
build/styles/block-library/comments/style-rtl.min.css 637 B
build/styles/block-library/comments/style.css 752 B
build/styles/block-library/comments/style.min.css 637 B
build/styles/block-library/common-rtl.css 2.48 kB
build/styles/block-library/common-rtl.min.css 1.12 kB
build/styles/block-library/common.css 2.5 kB
build/styles/block-library/common.min.css 1.12 kB
build/styles/block-library/cover/editor-rtl.css 1.05 kB
build/styles/block-library/cover/editor-rtl.min.css 631 B
build/styles/block-library/cover/editor.css 1.05 kB
build/styles/block-library/cover/editor.min.css 631 B
build/styles/block-library/cover/style-rtl.css 2.5 kB
build/styles/block-library/cover/style-rtl.min.css 1.82 kB
build/styles/block-library/cover/style.css 2.51 kB
build/styles/block-library/cover/style.min.css 1.81 kB
build/styles/block-library/details/editor-rtl.css 72 B
build/styles/block-library/details/editor-rtl.min.css 65 B
build/styles/block-library/details/editor.css 72 B
build/styles/block-library/details/editor.min.css 65 B
build/styles/block-library/details/style-rtl.css 97 B
build/styles/block-library/details/style-rtl.min.css 86 B
build/styles/block-library/details/style.css 97 B
build/styles/block-library/details/style.min.css 86 B
build/styles/block-library/editor-elements-rtl.css 117 B
build/styles/block-library/editor-elements-rtl.min.css 75 B
build/styles/block-library/editor-elements.css 117 B
build/styles/block-library/editor-elements.min.css 75 B
build/styles/block-library/editor-rtl.css 12.5 kB
build/styles/block-library/editor-rtl.min.css 10.3 kB
build/styles/block-library/editor.css 12.5 kB
build/styles/block-library/editor.min.css 10.3 kB
build/styles/block-library/elements-rtl.css 84 B
build/styles/block-library/elements-rtl.min.css 54 B
build/styles/block-library/elements.css 84 B
build/styles/block-library/elements.min.css 54 B
build/styles/block-library/embed/editor-rtl.css 391 B
build/styles/block-library/embed/editor-rtl.min.css 331 B
build/styles/block-library/embed/editor.css 390 B
build/styles/block-library/embed/editor.min.css 331 B
build/styles/block-library/embed/style-rtl.css 1.29 kB
build/styles/block-library/embed/style-rtl.min.css 448 B
build/styles/block-library/embed/style.css 1.29 kB
build/styles/block-library/embed/style.min.css 448 B
build/styles/block-library/embed/theme-rtl.css 967 B
build/styles/block-library/embed/theme-rtl.min.css 133 B
build/styles/block-library/embed/theme.css 967 B
build/styles/block-library/embed/theme.min.css 133 B
build/styles/block-library/file/editor-rtl.css 352 B
build/styles/block-library/file/editor-rtl.min.css 324 B
build/styles/block-library/file/editor.css 353 B
build/styles/block-library/file/editor.min.css 324 B
build/styles/block-library/file/style-rtl.css 318 B
build/styles/block-library/file/style-rtl.min.css 278 B
build/styles/block-library/file/style.css 331 B
build/styles/block-library/file/style.min.css 278 B
build/styles/block-library/footnotes/style-rtl.css 220 B
build/styles/block-library/footnotes/style-rtl.min.css 198 B
build/styles/block-library/footnotes/style.css 219 B
build/styles/block-library/footnotes/style.min.css 197 B
build/styles/block-library/form-input/editor-rtl.css 286 B
build/styles/block-library/form-input/editor-rtl.min.css 265 B
build/styles/block-library/form-input/editor.css 285 B
build/styles/block-library/form-input/editor.min.css 264 B
build/styles/block-library/form-input/style-rtl.css 467 B
build/styles/block-library/form-input/style-rtl.min.css 366 B
build/styles/block-library/form-input/style.css 467 B
build/styles/block-library/form-input/style.min.css 366 B
build/styles/block-library/form-submission-notification/editor-rtl.css 368 B
build/styles/block-library/form-submission-notification/editor-rtl.min.css 344 B
build/styles/block-library/form-submission-notification/editor.css 368 B
build/styles/block-library/form-submission-notification/editor.min.css 341 B
build/styles/block-library/form-submit-button/style-rtl.css 77 B
build/styles/block-library/form-submit-button/style-rtl.min.css 69 B
build/styles/block-library/form-submit-button/style.css 77 B
build/styles/block-library/form-submit-button/style.min.css 69 B
build/styles/block-library/freeform/editor-rtl.css 1.12 kB
build/styles/block-library/freeform/editor-rtl.min.css 288 B
build/styles/block-library/freeform/editor.css 1.12 kB
build/styles/block-library/freeform/editor.min.css 288 B
build/styles/block-library/gallery/editor-rtl.css 1.52 kB
build/styles/block-library/gallery/editor-rtl.min.css 615 B
build/styles/block-library/gallery/editor.css 1.52 kB
build/styles/block-library/gallery/editor.min.css 616 B
build/styles/block-library/gallery/style-rtl.css 2.84 kB
build/styles/block-library/gallery/style-rtl.min.css 1.84 kB
build/styles/block-library/gallery/style.css 2.84 kB
build/styles/block-library/gallery/style.min.css 1.84 kB
build/styles/block-library/gallery/theme-rtl.css 941 B
build/styles/block-library/gallery/theme-rtl.min.css 108 B
build/styles/block-library/gallery/theme.css 941 B
build/styles/block-library/gallery/theme.min.css 108 B
build/styles/block-library/group/editor-rtl.css 772 B
build/styles/block-library/group/editor-rtl.min.css 335 B
build/styles/block-library/group/editor.css 772 B
build/styles/block-library/group/editor.min.css 335 B
build/styles/block-library/group/style-rtl.css 120 B
build/styles/block-library/group/style-rtl.min.css 103 B
build/styles/block-library/group/style.css 120 B
build/styles/block-library/group/style.min.css 103 B
build/styles/block-library/group/theme-rtl.css 468 B
build/styles/block-library/group/theme-rtl.min.css 79 B
build/styles/block-library/group/theme.css 468 B
build/styles/block-library/group/theme.min.css 79 B
build/styles/block-library/heading/style-rtl.css 604 B
build/styles/block-library/heading/style-rtl.min.css 205 B
build/styles/block-library/heading/style.css 604 B
build/styles/block-library/heading/style.min.css 205 B
build/styles/block-library/html/editor-rtl.css 1.29 kB
build/styles/block-library/html/editor-rtl.min.css 464 B
build/styles/block-library/html/editor.css 1.3 kB
build/styles/block-library/html/editor.min.css 464 B
build/styles/block-library/icon/editor-rtl.css 776 B
build/styles/block-library/icon/editor-rtl.min.css 377 B
build/styles/block-library/icon/editor.css 776 B
build/styles/block-library/icon/editor.min.css 377 B
build/styles/block-library/icon/style-rtl.css 218 B
build/styles/block-library/icon/style-rtl.min.css 154 B
build/styles/block-library/icon/style.css 218 B
build/styles/block-library/icon/style.min.css 154 B
build/styles/block-library/image/editor-rtl.css 1.64 kB
build/styles/block-library/image/editor-rtl.min.css 782 B
build/styles/block-library/image/editor.css 1.64 kB
build/styles/block-library/image/editor.min.css 780 B
build/styles/block-library/image/style-rtl.css 2.92 kB
build/styles/block-library/image/style-rtl.min.css 1.86 kB
build/styles/block-library/image/style.css 2.92 kB
build/styles/block-library/image/style.min.css 1.85 kB
build/styles/block-library/image/theme-rtl.css 971 B
build/styles/block-library/image/theme-rtl.min.css 137 B
build/styles/block-library/image/theme.css 971 B
build/styles/block-library/image/theme.min.css 137 B
build/styles/block-library/latest-comments/style-rtl.css 392 B
build/styles/block-library/latest-comments/style-rtl.min.css 352 B
build/styles/block-library/latest-comments/style.css 390 B
build/styles/block-library/latest-comments/style.min.css 352 B
build/styles/block-library/latest-posts/editor-rtl.css 154 B
build/styles/block-library/latest-posts/editor-rtl.min.css 139 B
build/styles/block-library/latest-posts/editor.css 153 B
build/styles/block-library/latest-posts/editor.min.css 138 B
build/styles/block-library/latest-posts/style-rtl.css 1.36 kB
build/styles/block-library/latest-posts/style-rtl.min.css 520 B
build/styles/block-library/latest-posts/style.css 1.37 kB
build/styles/block-library/latest-posts/style.min.css 520 B
build/styles/block-library/list/style-rtl.css 498 B
build/styles/block-library/list/style-rtl.min.css 107 B
build/styles/block-library/list/style.css 498 B
build/styles/block-library/list/style.min.css 107 B
build/styles/block-library/loginout/style-rtl.css 68 B
build/styles/block-library/loginout/style-rtl.min.css 61 B
build/styles/block-library/loginout/style.css 68 B
build/styles/block-library/loginout/style.min.css 61 B
build/styles/block-library/math/editor-rtl.css 491 B
build/styles/block-library/math/editor-rtl.min.css 105 B
build/styles/block-library/math/editor.css 502 B
build/styles/block-library/math/editor.min.css 105 B
build/styles/block-library/math/style-rtl.css 70 B
build/styles/block-library/math/style-rtl.min.css 61 B
build/styles/block-library/math/style.css 70 B
build/styles/block-library/math/style.min.css 61 B
build/styles/block-library/media-text/editor-rtl.css 389 B
build/styles/block-library/media-text/editor-rtl.min.css 321 B
build/styles/block-library/media-text/editor.css 389 B
build/styles/block-library/media-text/editor.min.css 320 B
build/styles/block-library/media-text/style-rtl.css 873 B
build/styles/block-library/media-text/style-rtl.min.css 552 B
build/styles/block-library/media-text/style.css 901 B
build/styles/block-library/media-text/style.min.css 550 B
build/styles/block-library/more/editor-rtl.css 796 B
build/styles/block-library/more/editor-rtl.min.css 393 B
build/styles/block-library/more/editor.css 798 B
build/styles/block-library/more/editor.min.css 393 B
build/styles/block-library/navigation-link/editor-rtl.css 1.28 kB
build/styles/block-library/navigation-link/editor-rtl.min.css 710 B
build/styles/block-library/navigation-link/editor.css 1.27 kB
build/styles/block-library/navigation-link/editor.min.css 713 B
build/styles/block-library/navigation-link/style-rtl.css 579 B
build/styles/block-library/navigation-link/style-rtl.min.css 190 B
build/styles/block-library/navigation-link/style.css 579 B
build/styles/block-library/navigation-link/style.min.css 188 B
build/styles/block-library/navigation-overlay-close/style-rtl.css 260 B
build/styles/block-library/navigation-overlay-close/style-rtl.min.css 237 B
build/styles/block-library/navigation-overlay-close/style.css 260 B
build/styles/block-library/navigation-overlay-close/style.min.css 237 B
build/styles/block-library/navigation-submenu/editor-rtl.css 1.12 kB
build/styles/block-library/navigation-submenu/editor-rtl.min.css 295 B
build/styles/block-library/navigation-submenu/editor.css 1.12 kB
build/styles/block-library/navigation-submenu/editor.min.css 294 B
build/styles/block-library/navigation/editor-rtl.css 3.28 kB
build/styles/block-library/navigation/editor-rtl.min.css 2.28 kB
build/styles/block-library/navigation/editor.css 3.29 kB
build/styles/block-library/navigation/editor.min.css 2.28 kB
build/styles/block-library/navigation/style-rtl.css 3.59 kB
build/styles/block-library/navigation/style-rtl.min.css 2.52 kB
build/styles/block-library/navigation/style.css 3.59 kB
build/styles/block-library/navigation/style.min.css 2.5 kB
build/styles/block-library/nextpage/editor-rtl.css 799 B
build/styles/block-library/nextpage/editor-rtl.min.css 392 B
build/styles/block-library/nextpage/editor.css 800 B
build/styles/block-library/nextpage/editor.min.css 392 B
build/styles/block-library/page-list/editor-rtl.css 1.18 kB
build/styles/block-library/page-list/editor-rtl.min.css 356 B
build/styles/block-library/page-list/editor.css 1.18 kB
build/styles/block-library/page-list/editor.min.css 356 B
build/styles/block-library/page-list/style-rtl.css 207 B
build/styles/block-library/page-list/style-rtl.min.css 192 B
build/styles/block-library/page-list/style.css 207 B
build/styles/block-library/page-list/style.min.css 192 B
build/styles/block-library/paragraph/editor-rtl.css 315 B
build/styles/block-library/paragraph/editor-rtl.min.css 292 B
build/styles/block-library/paragraph/editor.css 314 B
build/styles/block-library/paragraph/editor.min.css 292 B
build/styles/block-library/paragraph/style-rtl.css 746 B
build/styles/block-library/paragraph/style-rtl.min.css 341 B
build/styles/block-library/paragraph/style.css 752 B
build/styles/block-library/paragraph/style.min.css 340 B
build/styles/block-library/playlist-track/style-rtl.css 453 B
build/styles/block-library/playlist-track/style-rtl.min.css 420 B
build/styles/block-library/playlist-track/style.css 453 B
build/styles/block-library/playlist-track/style.min.css 420 B
build/styles/block-library/playlist/editor-rtl.css 120 B
build/styles/block-library/playlist/editor-rtl.min.css 112 B
build/styles/block-library/playlist/editor.css 120 B
build/styles/block-library/playlist/editor.min.css 112 B
build/styles/block-library/playlist/style-rtl.css 1.52 kB
build/styles/block-library/playlist/style-rtl.min.css 1.42 kB
build/styles/block-library/playlist/style.css 1.52 kB
build/styles/block-library/playlist/style.min.css 1.42 kB
build/styles/block-library/post-author-biography/style-rtl.css 96 B
build/styles/block-library/post-author-biography/style-rtl.min.css 86 B
build/styles/block-library/post-author-biography/style.css 96 B
build/styles/block-library/post-author-biography/style.min.css 86 B
build/styles/block-library/post-author-name/style-rtl.css 76 B
build/styles/block-library/post-author-name/style-rtl.min.css 69 B
build/styles/block-library/post-author-name/style.css 76 B
build/styles/block-library/post-author-name/style.min.css 69 B
build/styles/block-library/post-author/editor-rtl.css 490 B
build/styles/block-library/post-author/editor-rtl.min.css 104 B
build/styles/block-library/post-author/editor.css 490 B
build/styles/block-library/post-author/editor.min.css 104 B
build/styles/block-library/post-author/style-rtl.css 213 B
build/styles/block-library/post-author/style-rtl.min.css 188 B
build/styles/block-library/post-author/style.css 214 B
build/styles/block-library/post-author/style.min.css 189 B
build/styles/block-library/post-comments-count/style-rtl.css 79 B
build/styles/block-library/post-comments-count/style-rtl.min.css 72 B
build/styles/block-library/post-comments-count/style.css 79 B
build/styles/block-library/post-comments-count/style.min.css 72 B
build/styles/block-library/post-comments-form/editor-rtl.css 104 B
build/styles/block-library/post-comments-form/editor-rtl.min.css 96 B
build/styles/block-library/post-comments-form/editor.css 104 B
build/styles/block-library/post-comments-form/editor.min.css 96 B
build/styles/block-library/post-comments-form/style-rtl.css 585 B
build/styles/block-library/post-comments-form/style-rtl.min.css 525 B
build/styles/block-library/post-comments-form/style.css 584 B
build/styles/block-library/post-comments-form/style.min.css 525 B
build/styles/block-library/post-comments-link/style-rtl.css 78 B
build/styles/block-library/post-comments-link/style-rtl.min.css 71 B
build/styles/block-library/post-comments-link/style.css 78 B
build/styles/block-library/post-comments-link/style.min.css 71 B
build/styles/block-library/post-content/style-rtl.css 68 B
build/styles/block-library/post-content/style-rtl.min.css 61 B
build/styles/block-library/post-content/style.css 68 B
build/styles/block-library/post-content/style.min.css 61 B
build/styles/block-library/post-date/style-rtl.css 69 B
build/styles/block-library/post-date/style-rtl.min.css 62 B
build/styles/block-library/post-date/style.css 69 B
build/styles/block-library/post-date/style.min.css 62 B
build/styles/block-library/post-excerpt/editor-rtl.css 78 B
build/styles/block-library/post-excerpt/editor-rtl.min.css 71 B
build/styles/block-library/post-excerpt/editor.css 78 B
build/styles/block-library/post-excerpt/editor.min.css 71 B
build/styles/block-library/post-excerpt/style-rtl.css 171 B
build/styles/block-library/post-excerpt/style-rtl.min.css 155 B
build/styles/block-library/post-excerpt/style.css 171 B
build/styles/block-library/post-excerpt/style.min.css 155 B
build/styles/block-library/post-featured-image/editor-rtl.css 1.14 kB
build/styles/block-library/post-featured-image/editor-rtl.min.css 719 B
build/styles/block-library/post-featured-image/editor.css 1.14 kB
build/styles/block-library/post-featured-image/editor.min.css 717 B
build/styles/block-library/post-featured-image/style-rtl.css 392 B
build/styles/block-library/post-featured-image/style-rtl.min.css 347 B
build/styles/block-library/post-featured-image/style.css 392 B
build/styles/block-library/post-featured-image/style.min.css 347 B
build/styles/block-library/post-navigation-link/style-rtl.css 234 B
build/styles/block-library/post-navigation-link/style-rtl.min.css 215 B
build/styles/block-library/post-navigation-link/style.css 245 B
build/styles/block-library/post-navigation-link/style.min.css 214 B
build/styles/block-library/post-template/style-rtl.css 1.27 kB
build/styles/block-library/post-template/style-rtl.min.css 441 B
build/styles/block-library/post-template/style.css 1.27 kB
build/styles/block-library/post-template/style.min.css 441 B
build/styles/block-library/post-terms/style-rtl.css 108 B
build/styles/block-library/post-terms/style-rtl.min.css 96 B
build/styles/block-library/post-terms/style.css 108 B
build/styles/block-library/post-terms/style.min.css 96 B
build/styles/block-library/post-time-to-read/style-rtl.css 77 B
build/styles/block-library/post-time-to-read/style-rtl.min.css 70 B
build/styles/block-library/post-time-to-read/style.css 77 B
build/styles/block-library/post-time-to-read/style.min.css 70 B
build/styles/block-library/post-title/style-rtl.css 175 B
build/styles/block-library/post-title/style-rtl.min.css 162 B
build/styles/block-library/post-title/style.css 175 B
build/styles/block-library/post-title/style.min.css 162 B
build/styles/block-library/preformatted/style-rtl.css 511 B
build/styles/block-library/preformatted/style-rtl.min.css 125 B
build/styles/block-library/preformatted/style.css 511 B
build/styles/block-library/preformatted/style.min.css 125 B
build/styles/block-library/pullquote/editor-rtl.css 146 B
build/styles/block-library/pullquote/editor-rtl.min.css 133 B
build/styles/block-library/pullquote/editor.css 146 B
build/styles/block-library/pullquote/editor.min.css 133 B
build/styles/block-library/pullquote/style-rtl.css 765 B
build/styles/block-library/pullquote/style-rtl.min.css 365 B
build/styles/block-library/pullquote/style.css 764 B
build/styles/block-library/pullquote/style.min.css 365 B
build/styles/block-library/pullquote/theme-rtl.css 195 B
build/styles/block-library/pullquote/theme-rtl.min.css 176 B
build/styles/block-library/pullquote/theme.css 195 B
build/styles/block-library/pullquote/theme.min.css 176 B
build/styles/block-library/query-pagination-numbers/editor-rtl.css 134 B
build/styles/block-library/query-pagination-numbers/editor-rtl.min.css 121 B
build/styles/block-library/query-pagination-numbers/editor.css 144 B
build/styles/block-library/query-pagination-numbers/editor.min.css 118 B
build/styles/block-library/query-pagination/editor-rtl.css 168 B
build/styles/block-library/query-pagination/editor-rtl.min.css 154 B
build/styles/block-library/query-pagination/editor.css 168 B
build/styles/block-library/query-pagination/editor.min.css 154 B
build/styles/block-library/query-pagination/style-rtl.css 254 B
build/styles/block-library/query-pagination/style-rtl.min.css 237 B
build/styles/block-library/query-pagination/style.css 265 B
build/styles/block-library/query-pagination/style.min.css 237 B
build/styles/block-library/query-title/style-rtl.css 71 B
build/styles/block-library/query-title/style-rtl.min.css 64 B
build/styles/block-library/query-title/style.css 71 B
build/styles/block-library/query-title/style.min.css 64 B
build/styles/block-library/query-total/style-rtl.css 71 B
build/styles/block-library/query-total/style-rtl.min.css 64 B
build/styles/block-library/query-total/style.css 71 B
build/styles/block-library/query-total/style.min.css 64 B
build/styles/block-library/query/editor-rtl.css 1.28 kB
build/styles/block-library/query/editor-rtl.min.css 438 B
build/styles/block-library/query/editor.css 1.28 kB
build/styles/block-library/query/editor.min.css 438 B
build/styles/block-library/quote/style-rtl.css 255 B
build/styles/block-library/quote/style-rtl.min.css 238 B
build/styles/block-library/quote/style.css 256 B
build/styles/block-library/quote/style.min.css 238 B
build/styles/block-library/quote/theme-rtl.css 253 B
build/styles/block-library/quote/theme-rtl.min.css 233 B
build/styles/block-library/quote/theme.css 254 B
build/styles/block-library/quote/theme.min.css 236 B
build/styles/block-library/read-more/style-rtl.css 146 B
build/styles/block-library/read-more/style-rtl.min.css 131 B
build/styles/block-library/read-more/style.css 146 B
build/styles/block-library/read-more/style.min.css 131 B
build/styles/block-library/reset-rtl.css 936 B
build/styles/block-library/reset-rtl.min.css 467 B
build/styles/block-library/reset.css 936 B
build/styles/block-library/reset.min.css 467 B
build/styles/block-library/rss/editor-rtl.css 144 B
build/styles/block-library/rss/editor-rtl.min.css 126 B
build/styles/block-library/rss/editor.css 144 B
build/styles/block-library/rss/editor.min.css 126 B
build/styles/block-library/rss/style-rtl.css 1.11 kB
build/styles/block-library/rss/style-rtl.min.css 284 B
build/styles/block-library/rss/style.css 1.12 kB
build/styles/block-library/rss/style.min.css 283 B
build/styles/block-library/search/editor-rtl.css 217 B
build/styles/block-library/search/editor-rtl.min.css 199 B
build/styles/block-library/search/editor.css 217 B
build/styles/block-library/search/editor.min.css 199 B
build/styles/block-library/search/style-rtl.css 1.1 kB
build/styles/block-library/search/style-rtl.min.css 665 B
build/styles/block-library/search/style.css 1.1 kB
build/styles/block-library/search/style.min.css 666 B
build/styles/block-library/search/theme-rtl.css 130 B
build/styles/block-library/search/theme-rtl.min.css 113 B
build/styles/block-library/search/theme.css 130 B
build/styles/block-library/search/theme.min.css 113 B
build/styles/block-library/separator/editor-rtl.css 106 B
build/styles/block-library/separator/editor-rtl.min.css 100 B
build/styles/block-library/separator/editor.css 106 B
build/styles/block-library/separator/editor.min.css 100 B
build/styles/block-library/separator/style-rtl.css 284 B
build/styles/block-library/separator/style-rtl.min.css 248 B
build/styles/block-library/separator/style.css 297 B
build/styles/block-library/separator/style.min.css 248 B
build/styles/block-library/separator/theme-rtl.css 226 B
build/styles/block-library/separator/theme-rtl.min.css 195 B
build/styles/block-library/separator/theme.css 226 B
build/styles/block-library/separator/theme.min.css 195 B
build/styles/block-library/shortcode/editor-rtl.css 1.1 kB
build/styles/block-library/shortcode/editor-rtl.min.css 286 B
build/styles/block-library/shortcode/editor.css 1.1 kB
build/styles/block-library/shortcode/editor.min.css 286 B
build/styles/block-library/site-logo/editor-rtl.css 1.12 kB
build/styles/block-library/site-logo/editor-rtl.min.css 696 B
build/styles/block-library/site-logo/editor.css 1.12 kB
build/styles/block-library/site-logo/editor.min.css 692 B
build/styles/block-library/site-logo/style-rtl.css 239 B
build/styles/block-library/site-logo/style-rtl.min.css 218 B
build/styles/block-library/site-logo/style.css 238 B
build/styles/block-library/site-logo/style.min.css 218 B
build/styles/block-library/site-tagline/editor-rtl.css 94 B
build/styles/block-library/site-tagline/editor-rtl.min.css 87 B
build/styles/block-library/site-tagline/editor.css 94 B
build/styles/block-library/site-tagline/editor.min.css 87 B
build/styles/block-library/site-tagline/style-rtl.css 72 B
build/styles/block-library/site-tagline/style-rtl.min.css 65 B
build/styles/block-library/site-tagline/style.css 72 B
build/styles/block-library/site-tagline/style.min.css 65 B
build/styles/block-library/site-title/editor-rtl.css 93 B
build/styles/block-library/site-title/editor-rtl.min.css 85 B
build/styles/block-library/site-title/editor.css 93 B
build/styles/block-library/site-title/editor.min.css 85 B
build/styles/block-library/site-title/style-rtl.css 153 B
build/styles/block-library/site-title/style-rtl.min.css 143 B
build/styles/block-library/site-title/style.css 153 B
build/styles/block-library/site-title/style.min.css 143 B
build/styles/block-library/social-link/editor-rtl.css 346 B
build/styles/block-library/social-link/editor-rtl.min.css 314 B
build/styles/block-library/social-link/editor.css 348 B
build/styles/block-library/social-link/editor.min.css 314 B
build/styles/block-library/social-links/editor-rtl.css 737 B
build/styles/block-library/social-links/editor-rtl.min.css 339 B
build/styles/block-library/social-links/editor.css 738 B
build/styles/block-library/social-links/editor.min.css 338 B
build/styles/block-library/social-links/style-rtl.css 1.57 kB
build/styles/block-library/social-links/style-rtl.min.css 1.51 kB
build/styles/block-library/social-links/style.css 1.57 kB
build/styles/block-library/social-links/style.min.css 1.51 kB
build/styles/block-library/spacer/editor-rtl.css 774 B
build/styles/block-library/spacer/editor-rtl.min.css 346 B
build/styles/block-library/spacer/editor.css 774 B
build/styles/block-library/spacer/editor.min.css 346 B
build/styles/block-library/spacer/style-rtl.css 55 B
build/styles/block-library/spacer/style-rtl.min.css 48 B
build/styles/block-library/spacer/style.css 55 B
build/styles/block-library/spacer/style.min.css 48 B
build/styles/block-library/style-rtl.css 21.5 kB
build/styles/block-library/style-rtl.min.css 18 kB
build/styles/block-library/style.css 21.6 kB
build/styles/block-library/style.min.css 18 kB
build/styles/block-library/tab-list/editor-rtl.css 107 B
build/styles/block-library/tab-list/editor-rtl.min.css 97 B
build/styles/block-library/tab-list/editor.css 107 B
build/styles/block-library/tab-list/editor.min.css 97 B
build/styles/block-library/tab-panel/style-rtl.css 238 B
build/styles/block-library/tab-panel/style-rtl.min.css 215 B
build/styles/block-library/tab-panel/style.css 238 B
build/styles/block-library/tab-panel/style.min.css 215 B
build/styles/block-library/tab-panels/style-rtl.css 76 B
build/styles/block-library/tab-panels/style-rtl.min.css 65 B
build/styles/block-library/tab-panels/style.css 76 B
build/styles/block-library/tab-panels/style.min.css 65 B
build/styles/block-library/tab/editor-rtl.css 160 B
build/styles/block-library/tab/editor-rtl.min.css 148 B
build/styles/block-library/tab/editor.css 160 B
build/styles/block-library/tab/editor.min.css 148 B
build/styles/block-library/tab/style-rtl.css 397 B
build/styles/block-library/tab/style-rtl.min.css 352 B
build/styles/block-library/tab/style.css 398 B
build/styles/block-library/tab/style.min.css 356 B
build/styles/block-library/table-of-contents/style-rtl.css 89 B
build/styles/block-library/table-of-contents/style-rtl.min.css 83 B
build/styles/block-library/table-of-contents/style.css 89 B
build/styles/block-library/table-of-contents/style.min.css 83 B
build/styles/block-library/table/editor-rtl.css 1.25 kB
build/styles/block-library/table/editor-rtl.min.css 394 B
build/styles/block-library/table/editor.css 1.25 kB
build/styles/block-library/table/editor.min.css 394 B
build/styles/block-library/table/style-rtl.css 1.06 kB
build/styles/block-library/table/style-rtl.min.css 641 B
build/styles/block-library/table/style.css 1.06 kB
build/styles/block-library/table/style.min.css 640 B
build/styles/block-library/table/theme-rtl.css 985 B
build/styles/block-library/table/theme-rtl.min.css 152 B
build/styles/block-library/table/theme.css 985 B
build/styles/block-library/table/theme.min.css 152 B
build/styles/block-library/tabs/style-rtl.css 64 B
build/styles/block-library/tabs/style-rtl.min.css 57 B
build/styles/block-library/tabs/style.css 64 B
build/styles/block-library/tabs/style.min.css 57 B
build/styles/block-library/tag-cloud/style-rtl.css 283 B
build/styles/block-library/tag-cloud/style-rtl.min.css 248 B
build/styles/block-library/tag-cloud/style.css 283 B
build/styles/block-library/tag-cloud/style.min.css 248 B
build/styles/block-library/template-part/editor-rtl.css 1.2 kB
build/styles/block-library/template-part/editor-rtl.min.css 368 B
build/styles/block-library/template-part/editor.css 1.2 kB
build/styles/block-library/template-part/editor.min.css 368 B
build/styles/block-library/template-part/theme-rtl.css 492 B
build/styles/block-library/template-part/theme-rtl.min.css 113 B
build/styles/block-library/template-part/theme.css 492 B
build/styles/block-library/template-part/theme.min.css 113 B
build/styles/block-library/term-count/style-rtl.css 70 B
build/styles/block-library/term-count/style-rtl.min.css 63 B
build/styles/block-library/term-count/style.css 70 B
build/styles/block-library/term-count/style.min.css 63 B
build/styles/block-library/term-description/style-rtl.css 138 B
build/styles/block-library/term-description/style-rtl.min.css 126 B
build/styles/block-library/term-description/style.css 138 B
build/styles/block-library/term-description/style.min.css 126 B
build/styles/block-library/term-name/style-rtl.css 69 B
build/styles/block-library/term-name/style-rtl.min.css 62 B
build/styles/block-library/term-name/style.css 69 B
build/styles/block-library/term-name/style.min.css 62 B
build/styles/block-library/term-template/editor-rtl.css 267 B
build/styles/block-library/term-template/editor-rtl.min.css 225 B
build/styles/block-library/term-template/editor.css 267 B
build/styles/block-library/term-template/editor.min.css 225 B
build/styles/block-library/term-template/style-rtl.css 124 B
build/styles/block-library/term-template/style-rtl.min.css 114 B
build/styles/block-library/term-template/style.css 124 B
build/styles/block-library/term-template/style.min.css 114 B
build/styles/block-library/text-columns/editor-rtl.css 481 B
build/styles/block-library/text-columns/editor-rtl.min.css 95 B
build/styles/block-library/text-columns/editor.css 481 B
build/styles/block-library/text-columns/editor.min.css 95 B
build/styles/block-library/text-columns/style-rtl.css 177 B
build/styles/block-library/text-columns/style-rtl.min.css 165 B
build/styles/block-library/text-columns/style.css 177 B
build/styles/block-library/text-columns/style.min.css 165 B
build/styles/block-library/theme-rtl.css 1.59 kB
build/styles/block-library/theme-rtl.min.css 715 B
build/styles/block-library/theme.css 1.6 kB
build/styles/block-library/theme.min.css 719 B
build/styles/block-library/verse/style-rtl.css 155 B
build/styles/block-library/verse/style-rtl.min.css 137 B
build/styles/block-library/verse/style.css 155 B
build/styles/block-library/verse/style.min.css 137 B
build/styles/block-library/video/editor-rtl.css 839 B
build/styles/block-library/video/editor-rtl.min.css 428 B
build/styles/block-library/video/editor.css 840 B
build/styles/block-library/video/editor.min.css 428 B
build/styles/block-library/video/style-rtl.css 1.02 kB
build/styles/block-library/video/style-rtl.min.css 202 B
build/styles/block-library/video/style.css 1.02 kB
build/styles/block-library/video/style.min.css 202 B
build/styles/block-library/video/theme-rtl.css 967 B
build/styles/block-library/video/theme-rtl.min.css 134 B
build/styles/block-library/video/theme.css 967 B
build/styles/block-library/video/theme.min.css 134 B
build/styles/commands/style-rtl.css 2.07 kB
build/styles/commands/style-rtl.min.css 1.17 kB
build/styles/commands/style.css 2.06 kB
build/styles/commands/style.min.css 1.17 kB
build/styles/components/style-rtl.css 17.6 kB
build/styles/components/style-rtl.min.css 14.4 kB
build/styles/components/style.css 17.7 kB
build/styles/components/style.min.css 14.4 kB
build/styles/customize-widgets/style-rtl.css 2.35 kB
build/styles/customize-widgets/style-rtl.min.css 1.44 kB
build/styles/customize-widgets/style.css 2.35 kB
build/styles/customize-widgets/style.min.css 1.44 kB
build/styles/edit-post/classic-rtl.css 1.29 kB
build/styles/edit-post/classic-rtl.min.css 425 B
build/styles/edit-post/classic.css 1.31 kB
build/styles/edit-post/classic.min.css 428 B
build/styles/edit-post/style-rtl.css 3.51 kB
build/styles/edit-post/style-rtl.min.css 2.21 kB
build/styles/edit-post/style.css 3.51 kB
build/styles/edit-post/style.min.css 2.21 kB
build/styles/edit-site/style-rtl.css 20.3 kB
build/styles/edit-site/style-rtl.min.css 16.5 kB
build/styles/edit-site/style.css 20.3 kB
build/styles/edit-site/style.min.css 16.5 kB
build/styles/edit-widgets/style-rtl.css 4.85 kB
build/styles/edit-widgets/style-rtl.min.css 3.52 kB
build/styles/edit-widgets/style.css 4.85 kB
build/styles/edit-widgets/style.min.css 3.52 kB
build/styles/editor/style-rtl.css 28.4 kB
build/styles/editor/style-rtl.min.css 24 kB
build/styles/editor/style.css 28.4 kB
build/styles/editor/style.min.css 24 kB
build/styles/format-library/style-rtl.css 735 B
build/styles/format-library/style-rtl.min.css 326 B
build/styles/format-library/style.css 746 B
build/styles/format-library/style.min.css 326 B
build/styles/list-reusable-blocks/style-rtl.css 1.07 kB
build/styles/list-reusable-blocks/style-rtl.min.css 250 B
build/styles/list-reusable-blocks/style.css 1.07 kB
build/styles/list-reusable-blocks/style.min.css 249 B
build/styles/media-utils/style-rtl.css 2.08 kB
build/styles/media-utils/style-rtl.min.css 1.17 kB
build/styles/media-utils/style.css 2.08 kB
build/styles/media-utils/style.min.css 1.17 kB
build/styles/nux/style-rtl.css 1.48 kB
build/styles/nux/style-rtl.min.css 622 B
build/styles/nux/style.css 1.5 kB
build/styles/nux/style.min.css 618 B
build/styles/patterns/style-rtl.css 1.46 kB
build/styles/patterns/style-rtl.min.css 611 B
build/styles/patterns/style.css 1.46 kB
build/styles/patterns/style.min.css 611 B
build/styles/preferences/style-rtl.css 1.26 kB
build/styles/preferences/style-rtl.min.css 415 B
build/styles/preferences/style.css 1.26 kB
build/styles/preferences/style.min.css 415 B
build/styles/reusable-blocks/style-rtl.css 1.11 kB
build/styles/reusable-blocks/style-rtl.min.css 275 B
build/styles/reusable-blocks/style.css 1.11 kB
build/styles/reusable-blocks/style.min.css 275 B
build/styles/widgets/style-rtl.css 2.05 kB
build/styles/widgets/style-rtl.min.css 1.16 kB
build/styles/widgets/style.css 2.06 kB
build/styles/widgets/style.min.css 1.16 kB

compressed-size-action

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Flaky tests detected in deddbd0.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25426573501
📝 Reported issues:

@ciampo
Copy link
Copy Markdown
Contributor

ciampo commented May 6, 2026

This feels like something that @ellatrix should take a look at — I don't personally have much context to understand the full implications of changing / keeping the previous diff behavior.

In the meantime, I'm sharing some notes from an initial round of AI-assisted review

PR Review: #77992 — Post Revisions: Upgrade diff from v4 to v8

Summary

Bumps diff from ^4.0.2 to ^8.0.3 in packages/editor and packages/block-editor to align with packages/sync. Two unrelated upstream behaviour changes (LCS tie-breaker in v6, diffWords whitespace tokenization in v6) would regress the post-revisions UI; the PR addresses both: switches the per-word diffs to diffWordsWithSpace, and inlines a v4-compatible port of diffArrays (~150 LoC) to keep the LCS pivot stable for block-level matching.

The motivation (Syncpack alignment), the diagnosis (the two v6 changes), and the choice of diffWordsWithSpace as the v4-compatible word-diff replacement all check out against the upstream release notes. The main concern is the cost of vendoring the LCS algorithm vs. cheaper alternatives (subclassing v8's Diff class, or making the consumer logic LCS-pivot-insensitive). A few sibling consumers also weren't updated for consistency.

Findings Overview

  1. [major] Vendored ~150 LoC of upstream algorithm — consider subclassing v8's Diff class instead (packages/editor/src/components/post-revisions-preview/block-diff.js:48-193)
  2. [major] preserve-client-ids.js still uses a deep import that's risky under v8 (packages/editor/src/components/post-revisions-preview/preserve-client-ids.js:4)
  3. [major] Missing CHANGELOG entries for editor and block-editor (packages/editor/CHANGELOG.md:3, packages/block-editor/CHANGELOG.md:3)
  4. [minor] Stale tree-shaking comment in block-compare not migrated (packages/block-editor/src/components/block-compare/index.js:5-7)
  5. [minor] Local diffArrays shadows the upstream name — rename for clarity (packages/editor/src/components/post-revisions-preview/block-diff.js:48)
  6. [minor] JSDoc on local diffArrays overstates what the algorithm does (packages/editor/src/components/post-revisions-preview/block-diff.js:30-43)
  7. [minor] "Pure swap" test asserts an arbitrary LCS pivot rather than user-facing invariant (packages/editor/src/components/post-revisions-preview/test/block-diff.js:327-369)
  8. [minor] Helper diffArrays doubles the file's size; consider extracting to a sibling module (packages/editor/src/components/post-revisions-preview/block-diff.js:48-193)
  9. [nit] extractCommon( basePath, diagonalPath )diagonalPath is a number, not a path object (packages/editor/src/components/post-revisions-preview/block-diff.js:66)
  10. [nit] Inconsistent placement of the diffWordsWithSpace rationale comment (packages/editor/src/components/post-revisions-preview/block-diff.js:669-677 vs packages/editor/src/components/revision-fields-diff/index.js:4-9)

1. [major] Consider subclassing v8's Diff class instead of vendoring the algorithm

packages/editor/src/components/post-revisions-preview/block-diff.js:48-193

Inlining ~150 LoC of upstream LCS code is a real maintenance cost: it is now WordPress's responsibility forever, even though the only behaviour we actually want from it is the v4 tie-breaker. v8 explicitly documents class CustomDiff extends Diff as the supported customization API:

The Diff object is now a class. Custom extensions of Diff, as described in the "Defining custom diffing behaviors" section of the README, can therefore now be done by writing a class CustomDiff extends Diff and overriding methods.

A subclass that re-uses v8's algorithm and only overrides the tie-breaker (and keeps v4's (added, removed)(removed, added) post-swap, if still desired) should be ~20–30 LoC instead of ~150, and it inherits all future fixes and performance improvements upstream automatically.

It's also worth questioning whether we need v4-pivot fidelity at all. For both motivating cases:

  • Whitespace pivot ('pairs paragraphs in order when section is condensed'): the failure is real (confusing dual inline diffs). But pairSimilarBlocks is the thing that gets confused — it could likely be made LCS-pivot-insensitive (e.g. by allowing a removed/added pair in either order to feed back into the similarity matcher). That structural fix would survive any future diff change.
  • Pure swap (prev=[First, Second] / curr=[Second, First]): which block reads as "unchanged" vs "moved" is purely cosmetic — both v4 and v8 give equally-valid output here. This alone wouldn't justify vendoring an algorithm.

I'd suggest one of:

  • Subclass Diff and only override the tie-breaker (keep this PR's scope, much smaller surface), or
  • Make pairSimilarBlocks insensitive to LCS pivot choice (longer-term, no inlined algorithm needed).

Either feels preferable to maintaining a v4 reimplementation indefinitely. Happy to be convinced otherwise if you've already considered them — the PR description hints at the structural-fix option but doesn't say why it was ruled out.


2. [major] preserve-client-ids.js deep import is risky under diff v8

packages/editor/src/components/post-revisions-preview/preserve-client-ids.js:4

import { diffArrays } from 'diff/lib/diff/array';

Two concerns:

  1. No .js extension. v8's package.json exports only wildcards ./lib/*.js (with extension); the bare-folder ./lib/ mapping requires a trailing slash on the consumer side. A path like 'diff/lib/diff/array' (no extension) only resolves because the bundler/Jest resolver fills in .js. This worked under v4 because v4 had no exports field. v8's stricter exports map makes this fragile — a future tooling change (or stricter ESM resolver) could break it.
  2. sideEffects: false in v8. The historical reason for the deep import was tree-shaking; v8 marks the package sideEffects: false, so a top-level import { diffArrays } from 'diff' is now equivalent.

Suggest migrating to:

import { diffArrays } from 'diff';

The PR description says "its tests pass under v8 unmodified" — but the tests probably don't exercise the v6 LCS tie-breaker change (block-name signatures rarely produce equally-valid LCSes), so passing tests don't prove behaviour parity. Worth either (a) adding a test that does, or (b) explicitly noting in the file why this consumer is OK with v6 tie-breaker semantics.


3. [major] No CHANGELOG entries

packages/editor/CHANGELOG.md:3, packages/block-editor/CHANGELOG.md:3

Both packages get a major dependency bump but neither has an ## Unreleased > Internal entry. Even though the user-visible behaviour is unchanged by design, a major dep bump (and the inlining of a third-party algorithm port) is exactly the kind of thing that should be discoverable in the CHANGELOG when investigating future regressions.

Suggested entries:

Suggested CHANGELOG entries
### Internal

-   Updated `diff` dependency from `^4.0.2` to `^8.0.3`. ([#77992](https://github.com/WordPress/gutenberg/pull/77992))

(Same entry in packages/block-editor/CHANGELOG.md.)


4. [minor] Stale tree-shaking comment in block-compare; consider migrating its import too

packages/block-editor/src/components/block-compare/index.js:5-7

// diff doesn't tree-shake correctly, so we import from the individual
// module here, to avoid including too much of the library
import { diffChars } from 'diff/lib/diff/character';

This comment was true for v4 (no sideEffects declaration). It's no longer true for v8 (sideEffects: false, see release notes 8.0.2). Now that block-editor is also on v8, this is a good moment to:

  • Migrate the import to top-level (import { diffChars } from 'diff'), and
  • Remove the stale comment.

Same reasoning as #2. Keeping it within scope here makes the diff tooling consistent across the three consumers in the package.


5. [minor] Local diffArrays shadows the upstream name

packages/editor/src/components/post-revisions-preview/block-diff.js:48

function diffArrays( oldArr, newArr ) {

If a future contributor re-adds import { diffArrays } from 'diff' (e.g. for an unrelated diff in the same file), the import will silently shadow / collide with the local helper. Renaming the local one makes the v4-compatibility intent explicit and avoids the collision risk:

Suggested rename
function diffArraysV4Compatible( oldArr, newArr ) {
  // ...
}

6. [minor] JSDoc on diffArrays overstates what the algorithm does

packages/editor/src/components/post-revisions-preview/block-diff.js:30-43

/**
 * Compute an LCS-based array diff with the same tie-breaker semantics as
 * `diff` v4's `diffArrays`. The post-revisions UI relies on a specific LCS
 * choice when multiple equally-valid matches exist (e.g. preferring the
 * earlier occurrence in the previous revision over later ones, and
 * preferring content blocks over freeform/whitespace blocks). `diff` v6
 * changed the tie-breaker to "deletions before insertions", which produces
 * a different but equally-valid pairing — visible as confusing inline diffs
 * in the post-revisions feature. We reproduce v4's selection locally so
 * block-level matching stays stable across upgrades of the `diff` library.
 ...
 */

"Preferring content blocks over freeform/whitespace blocks" isn't something this function does — it's a downstream consequence of the LCS tie-breaker interacting with how pairSimilarBlocks then groups results. Stating it as a property of diffArrays is misleading; the function only tie-breaks on newPos. Suggest reworking to focus on the algorithmic invariant ("when multiple equal-length LCSes exist, prefer the one that advances newPos further") and leaving the downstream consequences in the comment on the consumer (pairSimilarBlocks).


7. [minor] "Pure swap" test asserts an arbitrary LCS pivot

packages/editor/src/components/post-revisions-preview/test/block-diff.js:327-369

The 'handles two blocks that swapped positions' test asserts the exact order [Second:added, First:unchanged, Second:removed] — meaning "First" stays put, "Second" moves. The opposite outcome ([Second:unchanged, ...]) would be equally valid LCS output. Asserting one over the other ties the test to the implementation choice rather than to user-facing value.

A more robust assertion would test the invariant — e.g. exactly one block is unmarked, the other is shown as removed+added with consistent content — without prescribing which one. That way the test would also pass on diff v8 directly (without the local diffArrays), letting the suite tell us which behaviour changes are user-visible vs. just LCS pivot drift.

Less critical than the items above, but worth considering since this test is one of the listed motivations for vendoring diffArrays.


8. [minor] Helper doubles the file's size; consider extracting

packages/editor/src/components/post-revisions-preview/block-diff.js:48-193

The local diffArrays adds ~150 LoC at the top of block-diff.js, which now mixes two unrelated concerns: (a) the LCS algorithm port and (b) the post-revisions diff orchestration. Extracting diffArrays to a sibling module (e.g. diff-arrays-v4.js) would:

  • Keep block-diff.js focused on revision-specific logic.
  • Make the algorithm port easier to delete in one shot if/when the consumer logic becomes pivot-insensitive (per TinyMCE formatting improvements #1).

Lower priority if you take #1 — subclassing would shrink it enough that extraction is unnecessary.


9. [nit] extractCommon( basePath, diagonalPath ) — parameter is a number

packages/editor/src/components/post-revisions-preview/block-diff.js:66

const extractCommon = ( basePath, diagonalPath ) => {

diagonalPath is the diagonal index (a number), not a path object — and the outer loop calls it diag. Renaming the parameter to diag for consistency would avoid the suggestion that it's another basePath-shaped value.


10. [nit] Inconsistent placement of the diffWordsWithSpace rationale comment

In block-diff.js, the rationale lives at the call site (inside applyRichTextDiff):

	/*
	 * Diff the plain text (words for cleaner output).
	 *
	 * `diffWordsWithSpace` keeps whitespace as its own token, the same
	 * behaviour `diffWords` had in `diff` v4. v6+ stopped treating
	 * whitespace as a token, which would otherwise coalesce adjacent word
	 * changes into one removed/added pair instead of reporting them
	 * separately — making the inline rich-text diff less precise.
	 */

But in revision-fields-diff/index.js, the same rationale lives at the import site:

/*
 * `diffWordsWithSpace` preserves the v4-style per-word output. v6+
 * stopped treating whitespace as a token in `diffWords`, which coalesces
 * adjacent word changes into a single removed/added pair.
 */

Minor inconsistency — pick one and apply uniformly. Since block-diff.js uses diffWordsWithSpace in two distinct call sites (applyRichTextDiff and applyDiffToBlock), the import-site comment is probably the cleaner pattern for both files.

manzoorwanijk added a commit that referenced this pull request May 6, 2026
Addresses review feedback on #77992 (findings 1, 5, 6, 7, 8, 9).

The previous commit inlined ~150 LoC of v4's Myers algorithm to keep
`diffArrays`'s LCS pivot stable across the v4 -> v8 bump. That preserved
all existing test assertions but came at a real maintenance cost.

The cleaner approach (the issue's original "Class 1" fix): just drop
freeform/whitespace pseudo-blocks from both arrays before LCS. Without
the `\n\n` blocks competing as a match anchor, v8's "deletions before
insertions" tie-breaker picks the same content-block pivot v4 did for
every input that was previously failing, and the inlined algorithm
becomes unnecessary.

Two follow-ups to make that approach work end-to-end:

1. Adjust `pairSimilarBlocks`'s placement heuristic. The original
   heuristic looked for *added* blocks between the removed and added
   positions to decide where to anchor a paired modification. With
   whitespace pseudo-blocks no longer in the result list, an unchanged
   content block between the two positions is now the only "the
   modified block crosses current-revision content" signal -- so the
   heuristic now also fires on unchanged blocks (but still ignores
   removed blocks, which don't exist in the current revision and so
   don't count as crossing).

2. Relax the `'handles two blocks that swapped positions'` assertion to
   the user-facing invariant (one unmarked + one removed/added pair
   with same content) rather than which side of the swap gets matched.
   For a pure swap the two LCS choices are equally valid -- both v4 and
   v8 produce semantically-correct output, they just disagree on which
   block reads as "unchanged" -- so asserting one is testing the
   implementation, not the behaviour.

Net: -191 +56 LoC in `block-diff.js`. All 33 block-diff unit tests pass
and the broader revision-related suites stay green.
manzoorwanijk added a commit that referenced this pull request May 6, 2026
Addresses review feedback on #77992 (findings 2, 3, 4, 10).

- `preserve-client-ids.js` and `block-compare/index.js` now import
  `diffArrays` / `diffChars` from the top-level `'diff'` package
  instead of the deep `'diff/lib/diff/<name>'` paths. v8's
  `package.json` `exports` map only wildcards `./lib/*.js` (with
  extension); the bare-folder `./lib/` mapping requires a trailing
  slash. The deep paths only resolve here because the bundler/Jest
  resolver fills in `.js` -- a future tooling change could break
  them. v8 also marks the package `sideEffects: false`, so the
  historical tree-shaking reason for the deep imports no longer
  applies. The "diff doesn't tree-shake correctly" comment in
  `block-compare/index.js` is now stale and gets removed.

- Add `### Internal` entries to `packages/editor/CHANGELOG.md` and
  `packages/block-editor/CHANGELOG.md` recording the major dependency
  bump.
manzoorwanijk added a commit that referenced this pull request May 6, 2026
Addresses review feedback on #77992 (findings 1, 5, 6, 7, 8, 9).

The previous commit inlined ~150 LoC of v4's Myers algorithm to keep
`diffArrays`'s LCS pivot stable across the v4 -> v8 bump. That preserved
all existing test assertions but came at a real maintenance cost.

The cleaner approach (the issue's original "Class 1" fix): just drop
freeform/whitespace pseudo-blocks from both arrays before LCS. Without
the `\n\n` blocks competing as a match anchor, v8's "deletions before
insertions" tie-breaker picks the same content-block pivot v4 did for
every input that was previously failing, and the inlined algorithm
becomes unnecessary.

Two follow-ups to make that approach work end-to-end:

1. Adjust `pairSimilarBlocks`'s placement heuristic. The original
   heuristic looked for *added* blocks between the removed and added
   positions to decide where to anchor a paired modification. With
   whitespace pseudo-blocks no longer in the result list, an unchanged
   content block between the two positions is now the only "the
   modified block crosses current-revision content" signal -- so the
   heuristic now also fires on unchanged blocks (but still ignores
   removed blocks, which don't exist in the current revision and so
   don't count as crossing).

2. Relax the `'handles two blocks that swapped positions'` assertion to
   the user-facing invariant (one unmarked + one removed/added pair
   with same content) rather than which side of the swap gets matched.
   For a pure swap the two LCS choices are equally valid -- both v4 and
   v8 produce semantically-correct output, they just disagree on which
   block reads as "unchanged" -- so asserting one is testing the
   implementation, not the behaviour.

Net: -191 +56 LoC in `block-diff.js`. All 33 block-diff unit tests pass
and the broader revision-related suites stay green.
manzoorwanijk added a commit that referenced this pull request May 6, 2026
Addresses review feedback on #77992 (findings 2, 3, 4, 10).

- `preserve-client-ids.js` and `block-compare/index.js` now import
  `diffArrays` / `diffChars` from the top-level `'diff'` package
  instead of the deep `'diff/lib/diff/<name>'` paths. v8's
  `package.json` `exports` map only wildcards `./lib/*.js` (with
  extension); the bare-folder `./lib/` mapping requires a trailing
  slash. The deep paths only resolve here because the bundler/Jest
  resolver fills in `.js` -- a future tooling change could break
  them. v8 also marks the package `sideEffects: false`, so the
  historical tree-shaking reason for the deep imports no longer
  applies. The "diff doesn't tree-shake correctly" comment in
  `block-compare/index.js` is now stale and gets removed.

- Add `### Internal` entries to `packages/editor/CHANGELOG.md` and
  `packages/block-editor/CHANGELOG.md` recording the major dependency
  bump.
Aligns `packages/editor` and `packages/block-editor` with `packages/sync` on
`diff@^8.0.3` (needed for the Syncpack alignment work in #77950 / #77954).
The bump exposes two unrelated upstream changes that would regress the
post-revisions UI:

1. v6+ adds a "deletions before insertions" tie-breaker, so for inputs
   with multiple equal-length LCSes (whitespace-block pivots, paragraph
   swaps), `diffArrays` selects a different match than v4 did. The
   downstream `pairSimilarBlocks` step then mis-pairs blocks and shows
   two confusing inline diffs instead of a clean modified+unchanged pair.
2. v6+ stops treating whitespace as a token in `diffWords`, coalescing
   adjacent word changes into one removed/added pair and losing per-word
   precision in inline rich-text diffs.

Fix on the consumer side so existing tests pass without touching any
assertion:

- Replace the imported `diffArrays` in `block-diff.js` with a local
  v4-compatible port of `Diff.prototype.diff` (Myers, array+strict-eq),
  including v4's `(added, removed)` -> `(removed, added)` swap in
  `buildValues` so condensed sections still render in the right order.
- Switch `diffWords` -> `diffWordsWithSpace` for the inline rich-text
  diff, the `changedAttributes` panel diff, and the `Meta` field diff
  in `revision-fields-diff`.

`preserve-client-ids.js` and `block-compare` (uses `diffChars`) need no
changes -- neither hits the affected v6+ behaviours and their tests pass
unmodified under v8.

41/41 revision-related unit tests pass; full `npm run test:unit` is
green.

Closes #77976
Addresses review feedback on #77992 (findings 1, 5, 6, 7, 8, 9).

The previous commit inlined ~150 LoC of v4's Myers algorithm to keep
`diffArrays`'s LCS pivot stable across the v4 -> v8 bump. That preserved
all existing test assertions but came at a real maintenance cost.

The cleaner approach (the issue's original "Class 1" fix): just drop
freeform/whitespace pseudo-blocks from both arrays before LCS. Without
the `\n\n` blocks competing as a match anchor, v8's "deletions before
insertions" tie-breaker picks the same content-block pivot v4 did for
every input that was previously failing, and the inlined algorithm
becomes unnecessary.

Two follow-ups to make that approach work end-to-end:

1. Adjust `pairSimilarBlocks`'s placement heuristic. The original
   heuristic looked for *added* blocks between the removed and added
   positions to decide where to anchor a paired modification. With
   whitespace pseudo-blocks no longer in the result list, an unchanged
   content block between the two positions is now the only "the
   modified block crosses current-revision content" signal -- so the
   heuristic now also fires on unchanged blocks (but still ignores
   removed blocks, which don't exist in the current revision and so
   don't count as crossing).

2. Relax the `'handles two blocks that swapped positions'` assertion to
   the user-facing invariant (one unmarked + one removed/added pair
   with same content) rather than which side of the swap gets matched.
   For a pure swap the two LCS choices are equally valid -- both v4 and
   v8 produce semantically-correct output, they just disagree on which
   block reads as "unchanged" -- so asserting one is testing the
   implementation, not the behaviour.

Net: -191 +56 LoC in `block-diff.js`. All 33 block-diff unit tests pass
and the broader revision-related suites stay green.
Addresses review feedback on #77992 (findings 2, 3, 4, 10).

- `preserve-client-ids.js` and `block-compare/index.js` now import
  `diffArrays` / `diffChars` from the top-level `'diff'` package
  instead of the deep `'diff/lib/diff/<name>'` paths. v8's
  `package.json` `exports` map only wildcards `./lib/*.js` (with
  extension); the bare-folder `./lib/` mapping requires a trailing
  slash. The deep paths only resolve here because the bundler/Jest
  resolver fills in `.js` -- a future tooling change could break
  them. v8 also marks the package `sideEffects: false`, so the
  historical tree-shaking reason for the deep imports no longer
  applies. The "diff doesn't tree-shake correctly" comment in
  `block-compare/index.js` is now stale and gets removed.

- Add `### Internal` entries to `packages/editor/CHANGELOG.md` and
  `packages/block-editor/CHANGELOG.md` recording the major dependency
  bump.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades the diff dependency used by the editor’s revisions/compare features from v4 to v8, and updates the revisions diffing logic to preserve the same user-facing pairing and word-level inline diff behavior despite upstream behavioral changes in diff.

Changes:

  • Upgrade diff to ^8.0.3 in @wordpress/editor and @wordpress/block-editor, and migrate remaining imports to the top-level diff entrypoint.
  • Stabilize block pairing under diffArrays by filtering whitespace-only freeform pseudo-blocks before LCS matching, and adjust the placement heuristic in pairSimilarBlocks.
  • Restore per-word inline diffs by switching from diffWords to diffWordsWithSpace for rich-text, sidebar changed-attribute diffs, and meta-field diffs; relax one swap test assertion to assert the UX invariant rather than a specific LCS tie-break.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/editor/src/components/revision-fields-diff/index.js Switch meta diffs to diffWordsWithSpace via top-level diff import to preserve per-word output.
packages/editor/src/components/post-revisions-preview/test/block-diff.js Update swap test to assert invariant output instead of a specific unchanged-anchor choice.
packages/editor/src/components/post-revisions-preview/preserve-client-ids.js Migrate diffArrays import to top-level diff.
packages/editor/src/components/post-revisions-preview/block-diff.js Filter whitespace pseudo-blocks pre-LCS; adjust pairing placement heuristic; use diffWordsWithSpace for inline and attribute diffs.
packages/editor/package.json Bump diff dependency to ^8.0.3.
packages/editor/CHANGELOG.md Record the diff major-version bump under Internal changes.
packages/block-editor/src/components/block-compare/index.js Migrate diffChars import to top-level diff and remove now-stale tree-shaking comment.
packages/block-editor/package.json Bump diff dependency to ^8.0.3.
packages/block-editor/CHANGELOG.md Record the diff major-version bump under Internal changes.
package-lock.json Lockfile updates reflecting diff v8 installs for the updated workspaces.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ciampo
Copy link
Copy Markdown
Contributor

ciampo commented May 8, 2026

@manzoorwanijk FWIW, sharing another round of AI-assisted review.

Click to expand

PR Review: #77992 — Post Revisions: Upgrade diff from v4 to v8 (round 2)

Summary

This round reviews the PR after the previous round of feedback was applied. The author replaced the ~150 LoC vendored LCS port with a much smaller, sturdier fix: filter whitespace pseudo-blocks out of the input arrays before LCS, and update pairSimilarBlocks's placement heuristic so the unchanged-content case is detected without relying on a specific diffArrays tie-breaker. All four "major" items from the prior round are addressed: deep-path imports are migrated to top-level (block-compare, preserve-client-ids, block-diff), CHANGELOG entries are present in both packages, and the stale tree-shaking comment is gone.

The new approach is sound and substantially less risky than vendoring. Remaining feedback is small and mostly clarifying.

Findings Overview

  1. [Possible issue] Asymmetric pairSimilarBlocks lookahead: 'modified' status is not treated as crossing current-revision content (packages/editor/src/components/post-revisions-preview/block-diff.js:271-282)
  2. [minor] No focused unit test for the whitespace-pseudo-block filter (packages/editor/src/components/post-revisions-preview/test/block-diff.js)
  3. [minor] isWhitespaceRawBlock only runs at the top of each diffRawBlocks invocation — consider asserting the invariant in the recursive call (packages/editor/src/components/post-revisions-preview/block-diff.js:322-330)
  4. [minor] Tree-shaking comment removed but tree-shaking guarantee is more nuanced than the PR description suggests (packages/block-editor/src/components/block-compare/index.js:5)
  5. [nit] Rationale comment placement is now inconsistent again (packages/editor/src/components/post-revisions-preview/block-diff.js:4-10 vs packages/editor/src/components/revision-fields-diff/index.js:4-9)
  6. [nit] crossesCurrentContent comment is slightly out of sync with the code (packages/editor/src/components/post-revisions-preview/block-diff.js:260-268)

1. [Possible issue] Asymmetric lookahead in pairSimilarBlocks ignores already-paired modifications

packages/editor/src/components/post-revisions-preview/block-diff.js:271-282

The new heuristic treats unchanged blocks (status === undefined) and unpaired added blocks as "crossing current-revision content," but ignores 'modified' blocks. In the loop, modifications produced by earlier iterations of the outer for ( const rem of removed ) are stored only in the modifications Map — blocks[ i ].__revisionDiffStatus.status for those indices still reads as 'added' or 'removed', so this works out for the current iteration. But once crossesCurrentContent is decided based on 'added' && ! pairedAdded.has( i ), an added block that has already been "absorbed" into a pairing at the removed position (i.e. is in pairedAdded) is treated as not crossing — which is what we want. However, the symmetric case (a removed block at the added position, i.e. in pairedRemoved) isn't checked at all, because the loop never breaks on 'removed'.

In practice the existing tests all pass, so this may be intentional (removed blocks don't exist in the current revision and so don't actually "cross" current-revision content). But the asymmetry is worth a one-line confirmation in the comment, e.g.:

// 'removed' blocks (and pairedRemoved blocks placed at an added
// position) are not in the current revision and so don't count as
// crossing it. 'added' blocks that have already been absorbed into a
// modification at a removed position (pairedAdded) similarly don't.

If you're confident the current behaviour is correct, ignore — just flagging because the semantic distinction "current-revision content" vs. "anything in the result list" is what the heuristic now hinges on, and the code reads as if it might be inadvertently asymmetric.


2. [minor] Add a focused test for whitespace-pseudo-block filtering

packages/editor/src/components/post-revisions-preview/test/block-diff.js

The whitespace-filter behaviour is the primary mechanism for keeping LCS output stable across diff major versions, but it's only exercised transitively via the 'pairs paragraphs in order when section is condensed' test (which doesn't fail on a regression of the filter; it would fail downstream in pairSimilarBlocks). A direct test would lock the contract:

Suggested test
it( 'ignores whitespace-only freeform pseudo-blocks between block markers', () => {
  // Two paragraphs separated by raw whitespace at the document level
  // (the grammar parser emits these as { blockName: null, innerHTML: '\n\n' }).
  // Swapping their order shouldn't latch onto the whitespace pseudo-block
  // as the LCS anchor.
  const previous =
    '<!-- wp:paragraph --><p>First</p><!-- /wp:paragraph -->\n\n' +
    '<!-- wp:paragraph --><p>Second</p><!-- /wp:paragraph -->';
  const current =
    '<!-- wp:paragraph --><p>Second</p><!-- /wp:paragraph -->\n\n' +
    '<!-- wp:paragraph --><p>First</p><!-- /wp:paragraph -->';
  const blocks = diffRevisionContent( current, previous );
  // … assert one unchanged + one removed/added pair (the swap invariant)
} );

That way, if a future diff upgrade or refactor breaks the filter (e.g. blockName === null semantics change), this test is the canary, instead of an unrelated paragraph-condensing test failing in a confusing way.


3. [minor] Defensive: assert the filter holds inside recursion

packages/editor/src/components/post-revisions-preview/block-diff.js:322-330

function diffRawBlocks( currentRaw, previousRaw ) {
  // Strip whitespace-only freeform pseudo-blocks before LCS — see
  // `isWhitespaceRawBlock` for why.
  const currentBlocks = currentRaw.filter(
    ( b ) => ! isWhitespaceRawBlock( b )
  );
  const previousBlocks = previousRaw.filter(
    ( b ) => ! isWhitespaceRawBlock( b )
  );

The filter now runs at the top of every recursive call, which is correct but does redundant work for inner recursive calls (their innerBlocks were already filtered when the parent was diffed and stored). Harmless, just worth either:

  • Documenting in the JSDoc that the filter is intentionally re-applied at every level (so the function is safe to call directly with raw grammar output, which is its public contract), or
  • Pulling the filter out so it only runs at the top-level entry (diffRevisionContent) and asserting the invariant inside diffRawBlocks.

The first option is probably the right one — it keeps the function self-contained and the duplicate work is negligible.


4. [minor] block-compare tree-shaking comment removal — verify the assumption

packages/block-editor/src/components/block-compare/index.js:5

The PR description says "v8 also marks the package sideEffects: false", which made the deep diff/lib/diff/character import unnecessary. That's almost accurate — v8's top-level package.json doesn't have sideEffects: false; the flag lives in the per-output sub-manifests at libcjs/package.json and libesm/package.json that kpdecker/jsdiff writes during its build. Webpack 4+ honors nested sideEffects declarations, so tree-shaking should still work, but it's not exactly the property the PR description implies.

The size-change report on this PR (+866 B total, +784 B in editor, +82 B in block-editor) is consistent with tree-shaking working correctly — the editor bump is the new pairSimilarBlocks heuristic plus the LCS work, not unused diff code. So this is mostly cosmetic / for the description, not the code.


5. [nit] Rationale comment placement inconsistent across files

packages/editor/src/components/post-revisions-preview/block-diff.js:4-10 vs. packages/editor/src/components/revision-fields-diff/index.js:4-9

The two files now use slightly different framings:

/*
 * `diffWordsWithSpace` keeps whitespace as its own token, matching the
 * behaviour `diffWords` had in `diff` v4. v6+ stopped treating whitespace
 * as a token, which would otherwise coalesce adjacent word changes into a
 * single removed/added pair instead of reporting them per-word.
 */
import { diffArrays, diffWordsWithSpace } from 'diff';
/*
 * `diffWordsWithSpace` preserves the v4-style per-word output. v6+
 * stopped treating whitespace as a token in `diffWords`, which coalesces
 * adjacent word changes into a single removed/added pair.
 */
import { diffWordsWithSpace } from 'diff';

These are saying the same thing in two different ways; using identical wording (or extracting to a shared comment block) makes future grep-ability easier. Take or leave.


6. [nit] crossesCurrentContent comment slightly out of sync with code

packages/editor/src/components/post-revisions-preview/block-diff.js:260-268

// Decide where to place the modified block by checking
// what's between the removed and added positions.
// If anything between them is part of the current revision
// (an unpaired added block, or an unchanged block),
// placing at the removed position would put the modified
// block before content that comes before it in the
// current revision — so use the added position.
// Otherwise, use the removed position to keep the
// previous revision's order intact.

The comment says "if anything between them is part of the current revision," but the code only checks two specific cases (unchanged via status === undefined, and unpaired added). Modifications previously produced by this same loop iteration aren't checked — which is fine in practice (see #1) but the comment overstates the generality. Suggest narrowing the wording, e.g.:

// If any block between the two positions is in the current
// revision (an unchanged block, or an unpaired added block),
// placing the modification at the removed position would put it
// before content that already comes before it in the current
// revision — so use the added position instead.

…and possibly add an inline note that "removed and pairedRemoved blocks aren't checked because they're not in the current revision."

Still, I think this PR should be reviewed by someone familiar with the WordPress/Gutenberg diffiing, too.

Addresses round-2 review feedback on #77992 (human #1, #3, #5, #6 + Codex
test gaps a, b).

- Add a `'filters whitespace-only freeform pseudo-blocks before LCS'`
  test that's a direct canary for the whitespace filter — without the
  filter, `pairSimilarBlocks` would mis-match two paragraphs across the
  whitespace pseudo-block as the LCS anchor and produce two confused
  modified blocks instead of one modified + one unchanged.
- Add a `'places paired modification at current-revision position when
  only unchanged blocks sit between'` test exercising the new
  `crossesCurrentContent` "unchanged between removed and added" branch
  in isolation. Previously only hit transitively through the
  `'handles block move with a tiny change'` test, which mixes that
  branch with the whitespace-filter path and other heuristics.
- Tighten the `crossesCurrentContent` comment so it matches what the
  code actually checks (unpaired-added + unchanged) and adds a one-line
  note that 'removed' / `pairedAdded` blocks aren't checked because
  they aren't in the current revision.
- Match the `diffWordsWithSpace` rationale comment between
  `block-diff.js` and `revision-fields-diff/index.js` for grep-ability.
- Document on `diffRawBlocks` that the whitespace filter is
  intentionally re-applied at every recursive level so the function
  stays self-contained when called directly with raw grammar output.

No logic changes. All 35 block-diff tests + the broader unit suite
(32598 tests) stay green.
@manzoorwanijk
Copy link
Copy Markdown
Member Author

@manzoorwanijk FWIW, sharing another round of AI-assisted review.

Thank you. I have addressed the feedback.

I think this PR should be reviewed by someone familiar with the WordPress/Gutenberg diffiing, too.

Yes, I agree. Let us see if @ellatrix finds some time to have a look at this.

@ciampo
Copy link
Copy Markdown
Contributor

ciampo commented May 11, 2026

cc'ing @aduth on this PR too, since he was partially involved in some npm / package.json / syncpack conversations

@manzoorwanijk manzoorwanijk requested a review from aduth May 12, 2026 10:39
@ellatrix
Copy link
Copy Markdown
Member

Thank you. I agree that we should update, but I'm not sure I agree that we should try to replicate old behavior. I'll have a look into this after 7.0 etc. I don't think we should backport this to 7.0.

@manzoorwanijk
Copy link
Copy Markdown
Member Author

I'll have a look into this after 7.0 etc. I don't think we should backport this to 7.0.

Thank you. We don’t need to backport this, it’s just a cleanup of inconsistent dependency versions in the monorepo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Block editor /packages/block-editor [Package] Editor /packages/editor [Type] Task Issues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post Revisions: Upgrade diff from v4 to v8

4 participants