Skip to content

fix: centralize key-path resolution in operation-to-patches#2342

Closed
christianhg wants to merge 1 commit intomainfrom
fix/key-path-patches
Closed

fix: centralize key-path resolution in operation-to-patches#2342
christianhg wants to merge 1 commit intomainfrom
fix/key-path-patches

Conversation

@christianhg
Copy link
Member

Extracts a resolveKeyPath function that converts positional Slate paths to key-based Portable Text paths. Refactors operation-to-patches.ts to use it instead of inline key lookups scattered across five functions.


operation-to-patches.ts translates Slate operations into Portable Text patches for collaboration. Each of its five functions - insertTextPatch, removeTextPatch, setNodePatch, insertNodePatch, removeNodePatch - takes a Slate operation with a positional path like [0, 1] and needs to produce a patch with a key-based path like [{_key: 'blockKey'}, 'children', {_key: 'spanKey'}, 'text']. Every function does this by reaching into the tree inline: children[operation.path[0]!]._key, block.children[operation.path[1]!]._key. The same pattern repeated five times, each with its own error handling and edge cases.

This PR extracts that pattern into resolveKeyPath(schema, tree, slatePath), which walks the tree once and returns the key-based path. The patch functions call resolveKeyPath and then use small helpers (withTextField, withProperty) to append field names. setNodePatch is decomposed into setBlockNodePatch and setChildNodePatch. insertNodePatch is decomposed into insertBlockNodePatch and insertChildNodePatch.

The current implementation handles the two-level block/children structure. When containers land, resolveKeyPath generalizes to walk nested container fields using resolveArrayFields from the schema - the patch functions don't need to change.

@vercel
Copy link

vercel bot commented Mar 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
portable-text-example-basic Ready Ready Preview, Comment Mar 9, 2026 9:26pm
portable-text-playground Ready Ready Preview, Comment Mar 9, 2026 9:26pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Mar 9, 2026

🦋 Changeset detected

Latest commit: 79ecdb8

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

📦 Bundle Stats — @portabletext/editor

Compared against main (d312abd5)

@portabletext/editor

Metric Value vs main (d312abd)
Internal (raw) 800.6 KB -458 B, -0.1%
Internal (gzip) 150.3 KB -27 B, -0.0%
Bundled (raw) 1.41 MB -458 B, -0.0%
Bundled (gzip) 313.2 KB -29 B, -0.0%
Import time 103ms -1ms, -0.5%

@portabletext/editor/behaviors

Metric Value vs main (d312abd)
Internal (raw) 467 B -
Internal (gzip) 207 B -
Bundled (raw) 424 B -
Bundled (gzip) 171 B -
Import time 6ms -0ms, -1.4%

@portabletext/editor/plugins

Metric Value vs main (d312abd)
Internal (raw) 2.5 KB -
Internal (gzip) 910 B -
Bundled (raw) 2.3 KB -
Bundled (gzip) 839 B -
Import time 12ms -0ms, -0.8%

@portabletext/editor/selectors

Metric Value vs main (d312abd)
Internal (raw) 60.2 KB -
Internal (gzip) 9.4 KB -
Bundled (raw) 56.7 KB -
Bundled (gzip) 8.6 KB -
Import time 10ms -0ms, -0.9%

@portabletext/editor/utils

Metric Value vs main (d312abd)
Internal (raw) 24.2 KB -
Internal (gzip) 4.7 KB -
Bundled (raw) 22.2 KB -
Bundled (gzip) 4.4 KB -
Import time 10ms -0ms, -1.4%
Details
  • Import time regressions over 10% are flagged with ⚠️
  • Treemap artifacts are attached to the CI run for detailed size analysis
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant