use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use super::tables::TableGrid;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DocumentStructure {
pub nodes: Vec<DocumentNode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_format: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DocumentNode {
pub id: String,
pub content: NodeContent,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<u32>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub children: Vec<u32>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub annotations: Vec<TextAnnotation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attributes: Option<HashMap<String, String>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "node_type", rename_all = "snake_case")]
pub enum NodeContent {
Heading {
level: u8,
text: String,
},
Paragraph {
text: String,
},
List {
ordered: bool,
},
ListItem {
text: String,
},
Table {
grid: TableGrid,
},
Image {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
src: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
image_index: Option<u32>,
},
Code {
text: String,
#[serde(skip_serializing_if = "Option::is_none")]
language: Option<String>,
},
Quote,
DefinitionList,
DefinitionItem {
term: String,
definition: String,
},
RawBlock {
format: String,
content: String,
},
MetadataBlock {
entries: Vec<(String, String)>,
},
Group {
#[serde(skip_serializing_if = "Option::is_none")]
label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
heading_level: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
heading_text: Option<String>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TextAnnotation {
pub start: u32,
pub end: u32,
pub kind: AnnotationKind,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "annotation_type", rename_all = "snake_case")]
#[derive(Default)]
pub enum AnnotationKind {
#[default]
Bold,
Italic,
Underline,
Strikethrough,
Code,
Subscript,
Superscript,
Highlight,
Link {
url: String,
#[serde(skip_serializing_if = "Option::is_none")]
title: Option<String>,
},
}
impl Default for NodeContent {
fn default() -> Self {
Self::Heading {
level: 1,
text: String::new(),
}
}
}