mf_model/
node_type.rs

1use super::attrs::Attrs;
2use super::content::ContentMatch;
3use super::id_generator::IdGenerator;
4use super::mark::Mark;
5use super::mark_type::MarkType;
6use super::node::Node;
7use super::schema::{compute_attrs, Attribute, AttributeSpec, Schema};
8use super::types::NodeId;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use std::collections::HashMap;
12use std::fmt::{self, Debug};
13
14#[derive(Clone, Debug, Serialize, Deserialize)]
15pub struct NodeEnum(pub Node, pub Vec<NodeEnum>);
16
17impl NodeEnum {
18    pub fn into_parts(self) -> (Node, Vec<NodeEnum>) {
19        match self {
20            NodeEnum(node, children) => (node, children),
21        }
22    }
23    pub fn from(
24        node: Node,
25        childs: Vec<Node>,
26    ) -> Self {
27        NodeEnum(
28            node,
29            childs.into_iter().map(|n| NodeEnum(n, vec![])).collect(),
30        )
31    }
32}
33/// 用于描述节点类型的行为规则和属性约束,通过[Schema](super::schema::Schema)进行统一管理
34#[derive(Clone, PartialEq, Eq)]
35pub struct NodeType {
36    /// 节点类型的唯一标识符(例如:"dw", "dxgc")
37    pub name: String,
38    /// 节点类型的详细配置规范
39    pub spec: NodeSpec,
40    /// 节点类型的描述信息
41    pub desc: String,
42    /// 节点所属的逻辑分组
43    pub groups: Vec<String>,
44    /// 节点支持的属性集合(属性名 -> 属性定义)
45    pub attrs: HashMap<String, Attribute>,
46    /// 节点属性的默认值集合
47    pub default_attrs: HashMap<String, Value>,
48    /// 内容匹配规则,定义允许的子节点结构
49    pub content_match: Option<ContentMatch>,
50    /// 允许附加的Mark类型集合
51    pub mark_set: Option<Vec<MarkType>>,
52}
53impl Debug for NodeType {
54    fn fmt(
55        &self,
56        f: &mut fmt::Formatter<'_>,
57    ) -> fmt::Result {
58        f.debug_struct("NodeType")
59            .field("name", &self.name)
60            .field("spec", &self.spec)
61            .field("desc", &self.desc)
62            .field("groups", &self.groups)
63            .field("attrs", &self.attrs)
64            .field("default_attrs", &self.default_attrs)
65            .field("mark_set", &self.mark_set)
66            .finish()
67    }
68}
69
70impl NodeType {
71    /// 将原始节点规范编译为可用的节点类型集合
72    ///
73    /// # 参数
74    /// - `nodes`: 节点名称到[NodeSpec]的映射
75    ///
76    /// # 返回值
77    /// 返回[HashMap]<String, [NodeType]> 类型节点集合
78    pub fn compile(
79        nodes: HashMap<String, NodeSpec>
80    ) -> HashMap<String, NodeType> {
81        let mut result = HashMap::new();
82
83        // First create all node types without content_match
84        for (name, spec) in &nodes {
85            result.insert(
86                name.clone(),
87                NodeType::new(name.clone(), spec.clone()),
88            );
89        }
90
91        // Then set up content_match for each node type
92        let result_clone = result.clone();
93        for (_, node_type) in result.iter_mut() {
94            if let Some(content) = &node_type.spec.content {
95                node_type.content_match =
96                    Some(ContentMatch::parse(content.clone(), &result_clone));
97            }
98        }
99
100        result
101    }
102    /// 创建新的节点类型实例
103    ///
104    /// # 参数
105    /// - `name`: 节点类型名称  
106    /// - `spec`: 节点规范定义  
107    ///
108    /// # 注意
109    /// 自动从spec中推导默认属性和内容匹配规则
110    pub fn new(
111        name: String,
112        spec: NodeSpec,
113    ) -> Self {
114        let attrs = spec.attrs.as_ref().map_or_else(HashMap::new, |attrs| {
115            attrs
116                .iter()
117                .map(|(name, spec)| {
118                    (name.clone(), Attribute::new(spec.clone()))
119                })
120                .collect()
121        });
122
123        let default_attrs = attrs
124            .iter()
125            .filter_map(|(name, attr)| {
126                if attr.has_default {
127                    Some((name.clone(), attr.default.clone().unwrap()))
128                } else {
129                    None
130                }
131            })
132            .collect();
133
134        NodeType {
135            name,
136            spec,
137            desc: "".to_string(),
138            groups: vec![],
139            attrs,
140            default_attrs,
141            content_match: None,
142            mark_set: None,
143        }
144    }
145    /// 验证节点内容是否符合类型约束
146    ///
147    /// # 参数
148    /// - `content`: 子节点切片  
149    /// - `schema`: 当前使用的文档模式  
150    ///
151    /// # 返回值
152    /// 返回`true`表示内容合法,`false`表示不合法
153    pub fn check_content(
154        &self,
155        content: &[Node],
156        schema: &Schema,
157    ) -> bool {
158        if let Some(content_match) = &self.content_match {
159            if let Some(result) = content_match.match_fragment(content, schema)
160            {
161                if !result.valid_end {
162                    return false;
163                }
164            }
165        }
166        true
167    }
168    /// 验证节点属性是否符合规范
169    ///
170    /// # 参数
171    /// - `values`: 待验证的属性集合  
172    ///
173    /// # Panics
174    /// 当遇到以下情况会panic:  
175    /// - 包含未定义的属性  
176    /// - 缺少必须的属性
177    pub fn check_attrs(
178        &self,
179        values: &Attrs,
180    ) {
181        for (key, _value) in values.attrs.iter() {
182            if !self.attrs.contains_key(key) {
183                panic!("节点 {} 属性 {}没有定义", self.name, key);
184            }
185        }
186        for (key, value) in &self.attrs {
187            if value.is_required() && !&values.contains_key(key) {
188                panic!("节点 {} 属性 {} 没有值,这个属性必填", self.name, key);
189            }
190        }
191    }
192
193    /// 检查节点是否包含必须的属性
194    pub fn has_required_attrs(&self) -> bool {
195        self.attrs.values().any(|attr: &Attribute| attr.is_required())
196    }
197
198    /// 创建节点并填充内容
199    ///
200    /// # 参数
201    /// - `id`: 可选的节点ID,如果未提供则自动生成
202    /// - `attrs`: 可选的属性映射,用于设置节点属性
203    /// - `content`: 子节点列表
204    /// - `marks`: 可选的标记列表,用于设置节点标记
205    /// - `schema`: 当前使用的文档模式
206    ///
207    /// # 返回值
208    /// 返回包含新创建的节点及其所有子节点的向量
209    pub fn create_and_fill(
210        &self,
211        id: Option<String>,
212        attrs: Option<&HashMap<String, Value>>,
213        content: Vec<Node>,
214        marks: Option<Vec<Mark>>,
215        schema: &Schema,
216    ) -> NodeEnum {
217        let id: String = id.unwrap_or_else(IdGenerator::get_id);
218        let attrs = self.compute_attrs(attrs);
219
220        // 首先创建需要填充的内容
221        let mut filled_nodes = Vec::new();
222        let mut content_ids = Vec::new();
223
224        if let Some(content_match) = &self.content_match {
225            if let Some(matched) =
226                content_match.match_fragment(&content, schema)
227            {
228                if let Some(needed_type_names) =
229                    matched.fill(&content, true, schema)
230                {
231                    // 对每个需要的类型名称,从 schema 中获取完整的 NodeType 并创建节点
232                    for type_name in needed_type_names {
233                        // 从 schema 中获取完整的 NodeType
234                        let complete_node_type =
235                            schema.nodes.get(&type_name).expect(&format!(
236                                "无法在 schema 中找到节点类型: {}",
237                                type_name
238                            ));
239
240                        // 在content中查找同类型的节点
241                        let existing_node =
242                            content.iter().find(|n| n.r#type == type_name);
243
244                        if let Some(node) = existing_node {
245                            // 复用现有节点
246                            content_ids.push(node.id.clone());
247                            // 递归创建节点及其子节点
248                            // 对于现有节点,我们需要让它重新填充其必需的子内容
249                            // 不传递现有的子节点,而是让 fill 方法重新推导需要的节点
250                            let child_nodes = complete_node_type
251                                .create_and_fill(
252                                    Some(node.id.clone()),
253                                    Some(
254                                        &node
255                                            .attrs
256                                            .attrs
257                                            .clone()
258                                            .into_iter()
259                                            .map(|(k, v)| {
260                                                (k.clone(), v.clone())
261                                            })
262                                            .collect(),
263                                    ), // 使用节点的原始属性
264                                    vec![], // 传递空内容,让 fill 方法推导需要的子节点
265                                    Some(
266                                        node.marks
267                                            .clone()
268                                            .into_iter()
269                                            .map(|m| m.clone())
270                                            .collect(),
271                                    ),
272                                    schema,
273                                );
274                            filled_nodes.push(child_nodes);
275                        } else {
276                            // 创建新节点 - 让子节点类型自己决定是否需要创建子内容
277                            let new_id = IdGenerator::get_id();
278                            content_ids.push(new_id.clone());
279                            let child_nodes = complete_node_type
280                                .create_and_fill(
281                                    Some(new_id),
282                                    None,
283                                    vec![], // 新节点从空内容开始,让递归调用处理必需的子节点
284                                    None,
285                                    schema,
286                                );
287                            filled_nodes.push(child_nodes);
288                        }
289                    }
290                }
291            }
292        }
293
294        // 重要修复:确保父节点的 content_ids 包含递归创建的所有子节点的 ID
295        // 从 filled_nodes 中提取实际创建的节点 ID,更新 content_ids
296        let mut final_content_ids = Vec::new();
297        for filled_node in &filled_nodes {
298            let (child_node, _) = filled_node.clone().into_parts();
299            final_content_ids.push(child_node.id);
300        }
301
302        NodeEnum(
303            Node::new(
304                &id,
305                self.name.clone(),
306                attrs,
307                final_content_ids,
308                self.compute_marks(marks),
309            ),
310            filled_nodes,
311        )
312    }
313
314    /// 创建节点
315    pub fn create(
316        &self,
317        id: Option<String>,
318        attrs: Option<&HashMap<String, Value>>,
319        content: Vec<NodeId>,
320        marks: Option<Vec<Mark>>,
321    ) -> Node {
322        // 实现...
323        let id: String = id.unwrap_or_else(IdGenerator::get_id);
324
325        Node::new(
326            &id,
327            self.name.clone(),
328            self.compute_attrs(attrs),
329            content,
330            self.compute_marks(marks),
331        )
332    }
333
334    fn compute_marks(
335        &self,
336        marks: Option<Vec<Mark>>,
337    ) -> Vec<Mark> {
338        match (&self.mark_set, marks) {
339            (Some(def), Some(marks)) => def
340                .iter()
341                .filter_map(|mark_type| {
342                    marks
343                        .iter()
344                        .find(|m| m.r#type == mark_type.name)
345                        .map(|m| m.clone())
346                })
347                .collect(),
348            (None, Some(marks)) => marks,
349            _ => vec![],
350        }
351    }
352
353    fn compute_attrs(
354        &self,
355        attrs: Option<&HashMap<String, Value>>,
356    ) -> Attrs {
357        match attrs {
358            Some(attr) => compute_attrs(&self.attrs, Some(attr)),
359            None => compute_attrs(&self.attrs, Some(&self.default_attrs)),
360        }
361    }
362}
363
364/// 定义节点类型的约束规范
365///
366/// 用于配置节点类型的元数据和行为规则,通过[NodeType::compile]转换为可用类型
367#[derive(Clone, PartialEq, Debug, Eq, Default)]
368pub struct NodeSpec {
369    /// 内容约束表达式(例如:"*")
370    pub content: Option<String>,
371    // 允许附加的Mark类型表达式(例如:"color")
372    pub marks: Option<String>,
373    /// 所属的逻辑分组
374    pub group: Option<String>,
375    /// 类型描述信息
376    pub desc: Option<String>,
377    /// 属性规范定义(属性名 -> 属性规范)
378    pub attrs: Option<HashMap<String, AttributeSpec>>,
379}