让节点 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:
@@ -15,6 +15,8 @@ pub struct Node {
|
|||||||
pub component: Option<Component>,
|
pub component: Option<Component>,
|
||||||
pub children_display_mode: ChildrenDisplayMode,
|
pub children_display_mode: ChildrenDisplayMode,
|
||||||
pub children: Vec<Node>,
|
pub children: Vec<Node>,
|
||||||
|
// 偏移量是后加的字段:历史设计文档没有它,默认回落到零偏移,保证旧文档仍可读。
|
||||||
|
#[serde(default)]
|
||||||
pub offset: NodeOffset,
|
pub offset: NodeOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -832,6 +832,7 @@ fn validate_id(value: &str, label: &str) -> Result<(), String> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::ui_editor::layout::offset::NodeOffset;
|
||||||
|
|
||||||
const PROJECT_ID: &str = "ui-design-persistence-project";
|
const PROJECT_ID: &str = "ui-design-persistence-project";
|
||||||
|
|
||||||
@@ -1444,6 +1445,43 @@ mod tests {
|
|||||||
.is_err());
|
.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]
|
#[test]
|
||||||
fn rejects_text_component_with_missing_font_asset() {
|
fn rejects_text_component_with_missing_font_asset() {
|
||||||
let (directory, asset_id) = fixture();
|
let (directory, asset_id) = fixture();
|
||||||
|
|||||||
Reference in New Issue
Block a user