[lexical-code-core][lexical-code-prism][lexical-code-shiki] Refactor: move the duplicated updateCodeGutter into @lexical/code-core - #9164
Open
Om-singhaI wants to merge 6 commits into
Conversation
… move the duplicated updateCodeGutter into @lexical/code-core ## Description `@lexical/code-prism` and `@lexical/code-shiki` each had their own private copy of `updateCodeGutter`, and the two copies were identical line for line. @etrepum asked on facebook#8468 for this gutter code to be consolidated into `@lexical/code-core`, and it's the first step of the plan I posted on facebook#8459. This moves it into `@lexical/code-core` as `$updateCodeGutter` in a new `CodeGutter.ts`, exports it from the package index and declares it in the Flow file. Both highlighters now import it from there and their copies are gone. The function body is unchanged byte for byte, so the `data-gutter` string and the `__cachedChildrenLength` check are exactly what they were. I gave it the `$` prefix because it reads the node's children, so it has to run inside a read or an update. That's already where both callers use it: the CodeNode mutation listener, inside `editor.read('latest', ...)`. It's marked `@internal` like `registerCodeIndentation`, since only the two highlighters call it. I also added unit tests in `@lexical/code-core` that pin the exact `data-gutter` value for a single line, several lines, an empty trailing line and an edit that changes the line count, plus the cache that skips the write when the child count doesn't change. They run in a real editor with a copy of the mutation listener both highlighters register. Part of facebook#8459 ## Test plan ### Before On `origin/main` (84eabc3). The `packages/lexical-code` filter picks up `lexical-code`, `lexical-code-core`, `lexical-code-prism` and `lexical-code-shiki`. The `lexical-code` tests already pin `data-gutter` through prism's `registerCodeHighlighting`. ``` $ pnpm exec vitest --project unit --no-watch --maxWorkers=2 packages/lexical-code Test Files 15 passed (15) Tests 291 passed | 1 skipped (292) ``` ### After ``` $ pnpm exec vitest --project unit --no-watch --maxWorkers=2 --reporter=verbose packages/lexical-code ✓ |unit| packages/lexical-code-core/src/__tests__/unit/CodeGutter.test.ts > $updateCodeGutter > numbers a single line 108ms ✓ |unit| packages/lexical-code-core/src/__tests__/unit/CodeGutter.test.ts > $updateCodeGutter > numbers several lines 6ms ✓ |unit| packages/lexical-code-core/src/__tests__/unit/CodeGutter.test.ts > $updateCodeGutter > numbers an empty trailing line 6ms ✓ |unit| packages/lexical-code-core/src/__tests__/unit/CodeGutter.test.ts > $updateCodeGutter > follows an edit that changes the line count 7ms ✓ |unit| packages/lexical-code-core/src/__tests__/unit/CodeGutter.test.ts > $updateCodeGutter > only rewrites the attribute when the number of children changes 4ms Test Files 16 passed (16) Tests 296 passed | 1 skipped (297) $ pnpm run flow Found 0 errors ``` `tsc` over the four code packages passes, and eslint and prettier are clean on the changed files. I ran this on Node 25 locally, so Node 22 and 24 are left to CI. I didn't run the browser or e2e suites locally either. The playground e2e specs pin `data-gutter` in a lot of places, and since the output is unchanged they should stay green.
Om-singhaI
requested review from
acywatson,
etrepum,
fantactuka,
ivailop7,
potatowagon and
zurfyx
as code owners
September 13, 2026 04:09
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Author
etrepum
reviewed
Sep 16, 2026
etrepum
left a comment
Collaborator
There was a problem hiding this comment.
The editor argument is redundant, $getEditor can be used in the implementation
The editor argument was redundant. Every call site already runs inside a read or update context, so the implementation can reach the editor itself.
Contributor
Author
|
Done, thanks. Every call site already runs inside a read or an update context, so |
etrepum
reviewed
Sep 16, 2026
…utter The mutation listener was copied into both highlighters and the tests. Moving it behind one registration function leaves the gutter update as an implementation detail.
registerCodeIndentation carries the tag and both are exported from the package index, so without it the gutter registration would show up as supported API in the generated docs, which strip internal entries.
etrepum
approved these changes
Sep 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
@lexical/code-prismand@lexical/code-shikieach had their own private copy ofupdateCodeGutter, and the two copies were identical line for line. @etrepum asked on #8468 for this gutter code to be consolidated into@lexical/code-core, and it's the first step of the plan I posted on #8459.This moves it into
@lexical/code-coreas$updateCodeGutterin a newCodeGutter.ts, exports it from the package index and declares it in the Flow file. Both highlighters now import it from there and their copies are gone. The function body is unchanged byte for byte, so thedata-gutterstring and the__cachedChildrenLengthcheck are exactly what they were.I gave it the
$prefix because it reads the node's children, so it has to run inside a read or an update. That's already where both callers use it: the CodeNode mutation listener, insideeditor.read('latest', ...). It's marked@internallikeregisterCodeIndentation, since only the two highlighters call it.I also added unit tests in
@lexical/code-corethat pin the exactdata-guttervalue for a single line, several lines, an empty trailing line and an edit that changes the line count, plus the cache that skips the write when the child count doesn't change. They run in a real editor with a copy of the mutation listener both highlighters register.Part of #8459
Test plan
Before
On
origin/main(84eabc3). Thepackages/lexical-codefilter picks uplexical-code,lexical-code-core,lexical-code-prismandlexical-code-shiki. Thelexical-codetests already pindata-gutterthrough prism'sregisterCodeHighlighting.After
tscover the four code packages passes, and eslint and prettier are clean on the changed files. I ran this on Node 25 locally, so Node 22 and 24 are left to CI. I didn't run the browser or e2e suites locally either. The playground e2e specs pindata-gutterin a lot of places, and since the output is unchanged they should stay green.