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                match (&attr.has_default, &attr.default) {
127                    (true, Some(v)) => Some((name.clone(), v.clone())),
128                    _ => None,
129                }
130            })
131            .collect();
132
133        NodeType {
134            name,
135            spec,
136            desc: "".to_string(),
137            groups: vec![],
138            attrs,
139            default_attrs,
140            content_match: None,
141            mark_set: None,
142        }
143    }
144    /// 验证节点内容是否符合类型约束
145    ///
146    /// # 参数
147    /// - `content`: 子节点切片  
148    /// - `schema`: 当前使用的文档模式  
149    ///
150    /// # 返回值
151    /// 返回`true`表示内容合法,`false`表示不合法
152    pub fn check_content(
153        &self,
154        content: &[Node],
155        schema: &Schema,
156    ) -> bool {
157        if let Some(content_match) = &self.content_match {
158            if let Some(result) = content_match.match_fragment(content, schema)
159            {
160                if !result.valid_end {
161                    return false;
162                }
163            }
164        }
165        true
166    }
167    /// 验证节点属性是否符合规范
168    ///
169    /// # 参数
170    /// - `values`: 待验证的属性集合  
171    ///
172    /// # Panics
173    /// 当遇到以下情况会panic:  
174    /// - 包含未定义的属性  
175    /// - 缺少必须的属性
176    pub fn check_attrs(
177        &self,
178        values: &Attrs,
179    ) {
180        for (key, _value) in values.attrs.iter() {
181            if !self.attrs.contains_key(key) {
182                panic!("节点 {} 属性 {}没有定义", self.name, key);
183            }
184        }
185        for (key, value) in &self.attrs {
186            if value.is_required() && !&values.contains_key(key) {
187                panic!("节点 {} 属性 {} 没有值,这个属性必填", self.name, key);
188            }
189        }
190    }
191
192    /// 检查节点是否包含必须的属性
193    pub fn has_required_attrs(&self) -> bool {
194        self.attrs.values().any(|attr: &Attribute| attr.is_required())
195    }
196
197    /// 创建节点并填充内容
198    ///
199    /// # 参数
200    /// - `id`: 可选的节点ID,如果未提供则自动生成
201    /// - `attrs`: 可选的属性映射,用于设置节点属性
202    /// - `content`: 子节点列表
203    /// - `marks`: 可选的标记列表,用于设置节点标记
204    /// - `schema`: 当前使用的文档模式
205    ///
206    /// # 返回值
207    /// 返回包含新创建的节点及其所有子节点的向量
208    pub fn create_and_fill(
209        &self,
210        id: Option<NodeId>,
211        attrs: Option<&HashMap<String, Value>>,
212        content: Vec<Node>,
213        marks: Option<Vec<Mark>>,
214        schema: &Schema,
215    ) -> NodeEnum {
216        let id: NodeId = id.unwrap_or_else(IdGenerator::get_id);
217        let attrs = self.compute_attrs(attrs);
218
219        // 首先创建需要填充的内容
220        let mut filled_nodes = Vec::new();
221        let mut content_ids = Vec::new();
222
223        if let Some(content_match) = &self.content_match {
224            if let Some(matched) =
225                content_match.match_fragment(&content, schema)
226            {
227                if let Some(needed_type_names) =
228                    matched.fill(&content, true, schema)
229                {
230                    // 对每个需要的类型名称,从 schema 中获取完整的 NodeType 并创建节点
231                    for type_name in needed_type_names {
232                        // 从 schema 中获取完整的 NodeType
233                        let complete_node_type =
234                            match schema.nodes.get(&type_name) {
235                                Some(nt) => nt,
236                                None => panic!(
237                                    "无法在 schema 中找到节点类型: {type_name}"
238                                ),
239                            };
240
241                        // 在content中查找同类型的节点
242                        let existing_node =
243                            content.iter().find(|n| n.r#type == type_name);
244
245                        if let Some(node) = existing_node {
246                            // 复用现有节点
247                            content_ids.push(node.id.clone());
248                            // 递归创建节点及其子节点
249                            // 对于现有节点,我们需要让它重新填充其必需的子内容
250                            // 不传递现有的子节点,而是让 fill 方法重新推导需要的节点
251                            let child_nodes = complete_node_type
252                                .create_and_fill(
253                                    Some(node.id.clone()),
254                                    Some(
255                                        &node
256                                            .attrs
257                                            .attrs
258                                            .clone()
259                                            .into_iter()
260                                            .map(|(k, v)| {
261                                                (k.clone(), v.clone())
262                                            })
263                                            .collect(),
264                                    ), // 使用节点的原始属性
265                                    vec![], // 传递空内容,让 fill 方法推导需要的子节点
266                                    Some(
267                                        node.marks
268                                            .clone()
269                                            .into_iter()
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<NodeId>,
318        attrs: Option<&HashMap<String, Value>>,
319        content: Vec<NodeId>,
320        marks: Option<Vec<Mark>>,
321    ) -> Node {
322        // 实现...
323        let id: NodeId = 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.iter().find(|m| m.r#type == mark_type.name).cloned()
343                })
344                .collect(),
345            (None, Some(marks)) => marks,
346            _ => vec![],
347        }
348    }
349
350    fn compute_attrs(
351        &self,
352        attrs: Option<&HashMap<String, Value>>,
353    ) -> Attrs {
354        match attrs {
355            Some(attr) => compute_attrs(&self.attrs, Some(attr)),
356            None => compute_attrs(&self.attrs, Some(&self.default_attrs)),
357        }
358    }
359}
360
361/// 定义节点类型的约束规范
362///
363/// 用于配置节点类型的元数据和行为规则,通过[NodeType::compile]转换为可用类型
364#[derive(Clone, PartialEq, Debug, Eq, Default)]
365pub struct NodeSpec {
366    /// 内容约束表达式(例如:"*")
367    pub content: Option<String>,
368    // 允许附加的Mark类型表达式(例如:"color")
369    pub marks: Option<String>,
370    /// 所属的逻辑分组
371    pub group: Option<String>,
372    /// 类型描述信息
373    pub desc: Option<String>,
374    /// 属性规范定义(属性名 -> 属性规范)
375    pub attrs: Option<HashMap<String, AttributeSpec>>,
376}