Skip to content

fix: preserve node identity during type updates#1203

Merged
LucasXu0 merged 5 commits into
flutter/3_27_4from
fix/preserve-node-type-identity-flutter-3-27-4
Jun 12, 2026
Merged

fix: preserve node identity during type updates#1203
LucasXu0 merged 5 commits into
flutter/3_27_4from
fix/preserve-node-type-identity-flutter-3-27-4

Conversation

@appflowy

@appflowy appflowy commented May 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Small editor-only change to preserve node identity during safe block type conversions.

Scope is intentionally limited to appflowy-editor:

  • Add UpdateNodeTypeOperation for same-node type/data updates.
  • Add Transaction.updateNodeType and Document.updateNodeType.
  • Allow Node.copyWith to preserve ids only when explicitly requested.
  • Use in-place type updates for markdown shortcut conversions when descendant shape/content is unchanged.
  • Emit and apply same-id type diffs from diffDocuments / EditorState.
  • Resolve same-id type updates by stable node id when the operation path is stale.

Related GitHub Issues

Why

The old markdown conversion path replaced a block with insert+delete even when only the block type changed. That regenerated node ids and made downstream clients treat a type conversion as a structural replacement. Desktop/web integration can use this operation to preserve block identity instead.

The user-reported historical context from AppFlowy PR #6516 was also checked before adding coverage. That earlier fix showed two important constraints:

  • Conversions into childless block types, such as heading, must flatten nested children instead of keeping them inside the converted block.
  • Undo/redo must be verified for both same-id conversions and flattening conversions.

Test Coverage

Core operation/document coverage:

  • UpdateNodeTypeOperation serialization, inversion, copy, equality, and hash consistency.
  • Document.updateNodeType / Transaction.updateNodeType preserve node id, children, external values, and metadata.
  • diffDocuments emits UpdateNodeTypeOperation for same-id type changes.
  • Remote/local apply handles UpdateNodeTypeOperation.
  • Stale-path type updates resolve by nodeId instead of mutating the wrong path.
  • Missing nodeId targets are skipped instead of applying to a stale path.
  • Undo/redo for UpdateNodeTypeOperation preserves parent and child ids.

Markdown conversion coverage:

  • Safe no-child conversion: paragraph -> heading preserves node id through undo/redo.
  • Safe same-shape nested conversion: nested todo_list -> numbered_list preserves parent and child ids through undo/redo.
  • Childless target conversion: nested numbered_list -> heading flattens children into siblings.
  • Flattening undo/redo: undo restores the original nested numbered list, redo reapplies the heading plus flattened sibling list items.
  • Existing nested bulleted_list -> heading flattening behavior remains covered.

Diff Size

  • 13 files changed
  • 606 insertions
  • 13 deletions
  • No desktop, Rust, web, vendored dependency, generated, or lockfile changes

Verification

  • dart format --output=none --set-exit-if-changed ...
  • git diff --check
  • flutter test test/core/transform/operation_test.dart test/core/transform/transaction_test.dart test/new/block_component/heading_block_component/heading_character_shortcut_test.dart test/new/block_component/numbered_list_block_component/numbered_list_character_shortcut_test.dart

@CLAassistant

CLAassistant commented May 10, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ LucasXu0
❌ appflowy
You have signed the CLA already but the status is still pending? Let us recheck it.

@appflowy

Copy link
Copy Markdown
Collaborator Author

Web AppFlowy-IO/AppFlowy-Web#325

@LucasXu0 LucasXu0 merged commit 85b3f7e into flutter/3_27_4 Jun 12, 2026
2 of 3 checks passed
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.

3 participants