use super::*;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DebugDocument {
pub document: Document,
pub value_sources: ValueSourceMap,
pub annotated_html: String,
}
#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
pub struct ValueSourceMap {
pub items: Vec<ItemDebugInfo>,
pub relations: BTreeMap<url::Url, RelationDebugInfo>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ItemDebugInfo {
pub r#type: Vec<Class>,
pub element: ElementSource,
pub properties: BTreeMap<String, Vec<PropertyDebugInfo>>,
pub children: Vec<ItemDebugInfo>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PropertyDebugInfo {
pub value: PropertyValue,
pub element: ElementSource,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RelationDebugInfo {
pub urls: Vec<String>,
pub elements: Vec<ElementSource>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ElementSource {
pub mf2_id: Option<String>,
pub tag: String,
pub classes: Vec<String>,
pub attributes: BTreeMap<String, String>,
pub position: SourcePosition,
pub parent_ids: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SourcePosition {
pub line: usize,
pub column: usize,
pub offset: usize,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize)]
pub struct DebugContext {
pub elements: HashMap<String, ElementSource>,
pub property_sources: Vec<PropertySourceRecord>,
pub original_html: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PropertySourceRecord {
pub path: String,
pub element_id: String,
pub property_name: String,
}
impl Document {
pub fn into_debug_document(self) -> Option<DebugDocument> {
let debug_ctx = self._debug_context.clone()?;
let value_sources = self.build_value_sources(&debug_ctx)?;
let annotated_html = debug_ctx.original_html.clone();
Some(DebugDocument {
document: self,
value_sources,
annotated_html,
})
}
fn build_value_sources(&self, ctx: &DebugContext) -> Option<ValueSourceMap> {
let items = self
.items
.iter()
.enumerate()
.filter_map(|(idx, item)| {
self.build_item_debug_info(item, &format!("items[{}]", idx), ctx)
})
.collect();
let relations = self.build_relation_debug_info(ctx)?;
Some(ValueSourceMap { items, relations })
}
fn build_item_debug_info(
&self,
item: &Item,
path: &str,
ctx: &DebugContext,
) -> Option<ItemDebugInfo> {
let element_id = ctx
.property_sources
.iter()
.find(|r| r.path == path && r.element_id.starts_with("mf2-"))
.map(|r| r.element_id.clone())
.or_else(|| {
ctx.property_sources
.iter()
.find(|r| r.path.starts_with(&format!("{}.children", path)))
.map(|r| r.element_id.clone())
})?;
let element = ctx.elements.get(&element_id)?.clone();
let mut properties = BTreeMap::new();
for (prop_name, values) in &item.properties {
let prop_path = format!("{}.{}", path, prop_name);
let prop_debug_info: Vec<_> = values
.iter()
.enumerate()
.filter_map(|(val_idx, value)| {
let val_path = format!("{}[{}]", prop_path, val_idx);
let val_element_id = ctx
.property_sources
.iter()
.find(|r| r.path == val_path || val_path.starts_with(&r.path))
.and_then(|r| ctx.elements.get(&r.element_id))
.and_then(|e| e.mf2_id.clone())?;
Some(PropertyDebugInfo {
value: value.clone(),
element: ctx.elements.get(&val_element_id)?.clone(),
})
})
.collect();
if !prop_debug_info.is_empty() {
properties.insert(prop_name.clone(), prop_debug_info);
}
}
let children = item
.children
.iter()
.filter_map(|child| {
let child_path = format!("{}.children", path);
self.build_item_debug_info(child, &child_path, ctx)
})
.collect();
Some(ItemDebugInfo {
r#type: item.r#type.clone(),
element,
properties,
children,
})
}
fn build_relation_debug_info(
&self,
_ctx: &DebugContext,
) -> Option<BTreeMap<url::Url, RelationDebugInfo>> {
let mut relations = BTreeMap::new();
for url in self.rels.items.keys() {
relations.insert(
url.clone(),
RelationDebugInfo {
urls: vec![url.to_string()],
elements: vec![], },
);
}
Some(relations)
}
}