Skip to content

Fix list deserialization - #4030

Merged
acywatson merged 5 commits into
mainfrom
list-deser
Mar 7, 2023
Merged

acywatson merged 5 commits into
mainfrom
list-deser

Conversation

@acywatson

@acywatson acywatson commented Mar 4, 2023 •

Copy link
Copy Markdown
Contributor

This one was a bit gnarly and probably requires a deeper fix at some point. We've had reports of people encountering issues when deserializing lists, and it all goes back to this issue: #3227

What we're doing here is basically trying to update Lexical nodes during the reconciliation phase, which typically works fine, but encounters some issues in a few cases. One of those is when reconciliation runs asynchronously, which seems to be what's happening in the case of state being initialized from a string via LexicalComposer. Basically, we "freeze" the node map after the update cycle to ensure that state can't be further updated outside of that cycle. In this case, we were freezing the map, then createDOM was running, calling these list item update functions, which tried to update the nodes. There are several interrelated issues here, including the underlying structure/function of lists, which we will ultimately probably change (as discussed elsewhere).

The fix I'm proposing here is to introduce a method to nodes that allows them to declare a transform on themselves, rather than registering it through the register API. This allows us to keep this logic encapsulated at the node level, rather than moving it to the plugin, and it should otherwise function the same.

fixes #3975 and #3227

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 4, 2023
@vercel

vercel Bot commented Mar 4, 2023 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
lexical ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Mar 7, 2023 at 2:22PM (UTC)
lexical-playground ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Mar 7, 2023 at 2:22PM (UTC)

@github-actions

github-actions Bot commented Mar 4, 2023 •

Copy link
Copy Markdown

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
packages/lexical/dist/Lexical.js 26.09 KB (+0.03% 🔺) 522 ms (+0.03% 🔺) 60 ms (+18.41% 🔺) 581 ms
packages/lexical-rich-text/dist/LexicalRichText.js 36.91 KB (+0.06% 🔺) 739 ms (+0.06% 🔺) 45 ms (-4.93% 🔽) 783 ms
packages/lexical-plain-text/dist/LexicalPlainText.js 36.88 KB (+0.06% 🔺) 738 ms (+0.06% 🔺) 46 ms (-7.52% 🔽) 783 ms

Comment thread packages/lexical/src/LexicalUpdates.ts Resolved
Comment thread packages/lexical/src/LexicalNode.ts Resolved
@moy2010

moy2010 commented Mar 4, 2023

Copy link
Copy Markdown
Contributor

One deserialization error that I've had before is caused by the fact that markdown's shortcut's regex for the numeric list matches on any number, so it's possible to create numeric lists that do not start from 1..

@acywatson

Copy link
Copy Markdown
Contributor Author

One deserialization error that I've had before is caused by the fact that markdown's shortcut's regex for the numeric list matches on any number, so it's possible to create numeric lists that do not start from 1..

Oh weird. I guess starting a list at a number other than 1 should be possible. Might need to look into that separately.

etrepum pushed a commit to etrepum/lexical that referenced this pull request Aug 2, 2026
…s and deprecate static transform()

## Description

Audit of APIs still marked experimental whose signatures have been unchanged
for more than 6 months, comparing the experimental surface at v0.40.0
(2026-02-02, the 6-month boundary) against main. Of 225 experimental
annotations on main, only 11 existed 6 months ago -- everything else (named
slots, DOM import/render, mdast, shadow DOM) landed 2026-04 or later. Collab v2
is intentionally left experimental.

Three APIs qualified, and the repo marks experimental status two ways
(`@experimental` tags and prose `EXPERIMENTAL`), so a tag-only scan misses some.

**Graduated (leftovers from meta#8354).** That PR removed the experimental
designation from the Extension and NodeState APIs, including the "This API is
experimental" stability section in `docs/concepts/node-state.md`, but only
cleaned up the `@experimental` tags. Two NodeState APIs spelled the marker as
prose `EXPERIMENTAL` and were missed:

- `makeStateWrapper` (`@lexical/utils`) -- its signature and the
  `StateConfigWrapper` interface are unchanged since meta#7117 (2025-02-27)
- `stateConfigs` in `StaticNodeConfigValue` (`lexical`) -- declaration unchanged
  since meta#7258 (2025-06-22), and it is the documented entry point in
  `node-state.md` whose experimental notice was already removed

**Deprecated instead of graduated.** `LexicalNode.transform()` is the oldest
qualifier -- `@experimental` since meta#4030 (2023-03-07) with a byte-identical
signature for 3 years 5 months -- but blessing it as stable would be the wrong
call: it is superseded by the `$transform` property of the config returned by
`$config()`, which the codebase already steered people toward. Per AGENTS.md,
it is deprecated with the replacement documented rather than removed, and it
keeps working unchanged. The `$transform` doc no longer describes
`transform()` as "internal" now that it is deprecated and publicly documented.

Two APIs were considered and deliberately left alone:

- `hasNestedTables` (`@lexical/react`, `@lexical/table`) qualifies mechanically
  at 8.7 months with an unchanged declaration, but its marker reads "Nested
  tables are not officially supported" -- a product-support caveat, not an
  API-stability one, so clearing it would assert support. Its sibling
  `hasFitNestedTables` (meta#8097) is 5.9 months old and misses the cutoff, so
  graduating one would split the pair.
- `StaticNodeConfigValue` had its type parameter widened from `string` to
  `string | symbol` in meta#8645 (2026-06-05), so it fails the unchanged-API test.

## Test plan

Comment-only changes: no type or runtime surface is modified. `transform()`
remains fully functional, and `getTransformSetFromKlass` still collects both it
and `$transform` into the same transform set, so no behavior changes for
existing callers. Existing test coverage (including the `static transform()`
override in `LexicalNestedComposer.test.tsx`) applies unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
etrepum pushed a commit to etrepum/lexical that referenced this pull request Aug 3, 2026
…ic transform(), normalize makeStateWrapper marker

## Description

Audit of APIs still marked experimental whose signatures have been unchanged
for more than 6 months, comparing the experimental surface at v0.40.0
(2026-02-02, the 6-month boundary) against main. Of 225 experimental
annotations on main, only 11 existed 6 months ago -- everything else (named
slots, DOM import/render, mdast, shadow DOM) landed 2026-04 or later. Collab v2
is intentionally left experimental.

The repo marks experimental status two ways (`@experimental` tags and prose
`EXPERIMENTAL`), so a tag-only scan misses some. This PR makes three changes.

**Graduated: `stateConfigs`** in `StaticNodeConfigValue` (`lexical`). Its
declaration is unchanged since meta#7258 (2025-06-22) and it is the documented
entry point in `docs/concepts/node-state.md`, whose "This API is experimental"
stability section was already removed by meta#8354. That PR graduated the Extension
and NodeState APIs but only cleaned up the `@experimental` tags, so this prose
`EXPERIMENTAL` marker was left behind.

**Deprecated: `LexicalNode.transform()`.** It is the oldest qualifier --
`@experimental` since meta#4030 (2023-03-07) with a byte-identical signature for 3
years 5 months -- but blessing it as stable would be the wrong call: it is
superseded by the `$transform` property of the config returned by `$config()`,
which the codebase already steered people toward. Per AGENTS.md it is
deprecated with the replacement documented rather than removed, and it keeps
working unchanged. The `$transform` doc no longer describes `transform()` as
"internal" now that it is deprecated and publicly documented.

**Left experimental, marker normalized: `makeStateWrapper`**
(`@lexical/utils`). Its signature and the `StateConfigWrapper` interface are
unchanged since meta#7117 (2025-02-27), so it qualifies on age, but it is a public
export with no call sites, tests, or documentation references anywhere in the
repo. An API that nothing exercises has not really been validated by that time,
so it stays experimental; only the prose `EXPERIMENTAL` is rewritten to the
`@experimental` tag so tooling and future audits can see it.

Two APIs were considered and deliberately left alone:

- `hasNestedTables` (`@lexical/react`, `@lexical/table`) qualifies mechanically
  at 8.7 months with an unchanged declaration, but its marker reads "Nested
  tables are not officially supported" -- a product-support caveat, not an
  API-stability one, so clearing it would assert support. Its sibling
  `hasFitNestedTables` (meta#8097) is 5.9 months old and misses the cutoff, so
  graduating one would split the pair.
- `StaticNodeConfigValue` had its type parameter widened from `string` to
  `string | symbol` in meta#8645 (2026-06-05), so it fails the unchanged-API test.

## Test plan

Comment-only changes: no type or runtime surface is modified. `transform()`
remains fully functional, and `getTransformSetFromKlass` still collects both it
and `$transform` into the same transform set, so no behavior changes for
existing callers. Existing test coverage (including the `static transform()`
override in `LexicalNestedComposer.test.tsx`) applies unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch was successfully deployed

2 active deployments
Preview – lexical-playground — 08dce8b9 Deployed Mar 7, 2023 by vercel[bot]
Preview – lexical — 08dce8b9 Deployed Mar 7, 2023 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: List/ListItem Nodes From DOM results in invalid editor state

4 participants