use super::attrs::Attrs;
use super::content::ContentMatch;
use super::mark::Mark;
use super::mark_definition::MarkDefinition;
use super::node::Node;
use super::schema::{compute_attrs, Attribute, AttributeSpec, Schema};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::fmt::{self, Debug};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NodeTree(pub Node, pub Vec<NodeTree>);
impl NodeTree {
pub fn into_parts(self) -> (Node, Vec<NodeTree>) {
match self {
NodeTree(node, children) => (node, children),
}
}
pub fn from(
node: Node,
childs: Vec<Node>,
) -> Self {
NodeTree(
node,
childs.into_iter().map(|n| NodeTree(n, vec![])).collect(),
)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct NodeDefinition {
pub name: String,
pub spec: NodeSpec,
pub desc: String,
pub groups: Vec<String>,
pub attrs: HashMap<String, Attribute>,
pub default_attrs: HashMap<String, Value>,
pub content_match: Option<ContentMatch>,
pub mark_set: Option<Vec<MarkDefinition>>,
}
impl Debug for NodeDefinition {
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.debug_struct("NodeType")
.field("name", &self.name)
.field("spec", &self.spec)
.field("desc", &self.desc)
.field("groups", &self.groups)
.field("attrs", &self.attrs)
.field("default_attrs", &self.default_attrs)
.field("mark_set", &self.mark_set)
.finish()
}
}
impl NodeDefinition {
pub fn compile(
nodes: HashMap<String, NodeSpec>
) -> HashMap<String, NodeDefinition> {
let mut result = HashMap::new();
for (name, spec) in &nodes {
result.insert(
name.clone(),
NodeDefinition::new(name.clone(), spec.clone()),
);
}
let result_clone = result.clone();
for (_, node_type) in result.iter_mut() {
if let Some(content) = &node_type.spec.content {
node_type.content_match =
Some(ContentMatch::parse(content.clone(), &result_clone));
}
}
result
}
pub fn new(
name: String,
spec: NodeSpec,
) -> Self {
let attrs = spec.attrs.as_ref().map_or_else(HashMap::new, |attrs| {
attrs
.iter()
.map(|(name, spec)| {
(name.clone(), Attribute::new(spec.clone()))
})
.collect()
});
let default_attrs = attrs
.iter()
.filter_map(|(name, attr)| {
match (&attr.has_default, &attr.default) {
(true, Some(v)) => Some((name.clone(), v.clone())),
_ => None,
}
})
.collect();
NodeDefinition {
name,
spec,
desc: "".to_string(),
groups: vec![],
attrs,
default_attrs,
content_match: None,
mark_set: None,
}
}
pub fn check_content(
&self,
content: &[Node],
schema: &Schema,
) -> bool {
if let Some(content_match) = &self.content_match {
if let Some(result) = content_match.match_fragment(content, schema)
{
if !result.valid_end {
return false;
}
}
}
true
}
pub fn check_attrs(
&self,
values: &Attrs,
) {
for (key, _value) in values.attrs.iter() {
if !self.attrs.contains_key(key) {
panic!("节点 {} 属性 {}没有定义", self.name, key);
}
}
for (key, value) in &self.attrs {
if value.is_required() && !&values.contains_key(key) {
panic!("节点 {} 属性 {} 没有值,这个属性必填", self.name, key);
}
}
}
pub fn has_required_attrs(&self) -> bool {
self.attrs.values().any(|attr: &Attribute| attr.is_required())
}
pub(crate) fn compute_marks(
&self,
marks: Option<Vec<Mark>>,
) -> Vec<Mark> {
match (&self.mark_set, marks) {
(Some(def), Some(marks)) => def
.iter()
.filter_map(|mark_type| {
marks.iter().find(|m| m.r#type == mark_type.name).cloned()
})
.collect(),
(None, Some(marks)) => marks,
_ => vec![],
}
}
pub(crate) fn compute_attrs(
&self,
attrs: Option<&HashMap<String, Value>>,
) -> Attrs {
match attrs {
Some(attr) => compute_attrs(&self.attrs, Some(attr)),
None => compute_attrs(&self.attrs, Some(&self.default_attrs)),
}
}
}
#[derive(Clone, PartialEq, Debug, Eq, Default)]
pub struct NodeSpec {
pub content: Option<String>,
pub marks: Option<String>,
pub group: Option<String>,
pub desc: Option<String>,
pub attrs: Option<HashMap<String, AttributeSpec>>,
}