让节点 offset 在反序列化时缺省成零偏移

ui_editor/layout/node.rs 给 Node.offset 加 #[serde(default)],历史设计文档缺该字段时按零偏移解析
ui_editor/persistence.rs 补 legacy_nodes_without_offset_field_fall_back_to_zero_offset 锁定该回退口径
This commit is contained in:
2026-09-24 15:45:25 +08:00
parent dc5a5a4a62
commit 9694faa620
2 changed files with 40 additions and 0 deletions
@@ -15,6 +15,8 @@ pub struct Node {
pub component: Option<Component>,
pub children_display_mode: ChildrenDisplayMode,
pub children: Vec<Node>,
// 偏移量是后加的字段:历史设计文档没有它,默认回落到零偏移,保证旧文档仍可读。
#[serde(default)]
pub offset: NodeOffset,
}
@@ -832,6 +832,7 @@ fn validate_id(value: &str, label: &str) -> Result<(), String> {
#[cfg(test)]
mod tests {
use super::*;
use crate::ui_editor::layout::offset::NodeOffset;
const PROJECT_ID: &str = "ui-design-persistence-project";
@@ -1444,6 +1445,43 @@ mod tests {
.is_err());
}
/// 历史设计文档没有节点 `offset` 字段:缺字段必须按零偏移解析,不能判成缺字段损坏。
#[test]
fn legacy_nodes_without_offset_field_fall_back_to_zero_offset() {
let mut value = serde_json::to_value(state_with_sprite_and_dragged_transform())
.expect("serialize dragged UI design state");
strip_offset_fields(&mut value);
let state: State = serde_json::from_value(value).expect("节点缺 offset 时仍可解析");
assert_eq!(
state.ui_trees[0].root.offset,
NodeOffset::default(),
"根节点缺 offset 时回落零偏移"
);
assert_eq!(
state.ui_trees[0].root.children[0].offset,
NodeOffset::default(),
"子节点缺 offset 时回落零偏移"
);
}
/// 递归删除夹具里所有节点级 `offset` 字段,模拟该字段引入前落盘的文档。
fn strip_offset_fields(value: &mut serde_json::Value) {
match value {
serde_json::Value::Object(fields) => {
fields.remove("offset");
for field in fields.values_mut() {
strip_offset_fields(field);
}
}
serde_json::Value::Array(items) => {
for item in items {
strip_offset_fields(item);
}
}
_ => {}
}
}
#[test]
fn rejects_text_component_with_missing_font_asset() {
let (directory, asset_id) = fixture();