use crate::cel;
use crate::tree::{
Blockquote, FootnoteDefinition, Heading, Image, ImageReference, Link, LinkDefinition,
LinkReference, List, ListItem, Literal, Math, Parent, Point, Reference, Table, Void, WikiLink,
};
use serde::ser::SerializeMap;
use serde::{Serialize, Serializer};
use serde_json::Value;
use std::rc::Rc;
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
#[serde(tag = "type", rename = "root")]
pub struct Root {
pub children: Vec<Node>,
#[serde(skip_serializing_if = "Inputs::is_empty")]
pub inputs: Inputs,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Inputs(pub(crate) Vec<Input>);
impl Inputs {
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> std::slice::Iter<'_, Input> {
self.0.iter()
}
pub(crate) fn value(&self) -> cel::Value {
let values = self.iter().map(|input| {
(
cel::Key::String(Rc::from(input.name.as_str())),
cel::Value::from_json(&input.value),
)
});
cel::Value::Map(Rc::new(values.collect()))
}
}
impl<'a> IntoIterator for &'a Inputs {
type Item = &'a Input;
type IntoIter = std::slice::Iter<'a, Input>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl Serialize for Inputs {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(self.0.len()))?;
for input in self {
map.serialize_entry(&input.name, input)?;
}
map.end()
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct Input {
#[serde(skip)]
pub name: String,
#[serde(rename = "type")]
pub kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub members: Option<Vec<String>>,
pub value: Value,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct Node {
#[serde(flatten)]
pub content: Content,
#[serde(skip_serializing_if = "Option::is_none")]
pub origin: Option<Origin>,
}
impl Node {
pub(crate) fn new(content: Content) -> Self {
Self {
content,
origin: None,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum Content {
Blockquote(Blockquote<Node>),
Break(Void),
Code(Code),
ComponentContainer(Container),
ComponentInline(Leaf),
ComponentLeaf(Leaf),
ComponentPending(Pending),
Definition(LinkDefinition),
Delete(Parent<Node>),
Emphasis(Parent<Node>),
FootnoteDefinition(FootnoteDefinition<Node>),
FootnoteReference(Reference),
Heading(Heading<Node>),
Html(Literal),
Image(Image),
ImageReference(ImageReference),
InlineCode(Literal),
InlineMath(Literal),
Link(Link<Node>),
LinkReference(LinkReference<Node>),
List(List<Node>),
ListItem(ListItem<Node>),
Math(Math),
Paragraph(Parent<Node>),
Strong(Parent<Node>),
Table(Table<Node>),
TableCell(Parent<Node>),
TableRow(Parent<Node>),
Text(Literal),
ThematicBreak(Void),
WikiLink(WikiLink),
}
impl Content {
#[must_use]
pub fn children(&self) -> &[Node] {
match self {
Self::Blockquote(Blockquote { children, .. })
| Self::Delete(Parent { children, .. })
| Self::Emphasis(Parent { children, .. })
| Self::Paragraph(Parent { children, .. })
| Self::Strong(Parent { children, .. })
| Self::TableCell(Parent { children, .. })
| Self::TableRow(Parent { children, .. })
| Self::FootnoteDefinition(FootnoteDefinition { children, .. })
| Self::Heading(Heading { children, .. })
| Self::Link(Link { children, .. })
| Self::LinkReference(LinkReference { children, .. })
| Self::List(List { children, .. })
| Self::ListItem(ListItem { children, .. })
| Self::Table(Table { children, .. })
| Self::ComponentContainer(Container { children, .. })
| Self::ComponentPending(Pending { children, .. }) => children,
Self::ComponentLeaf(leaf) | Self::ComponentInline(leaf) => &leaf.fallback,
_ => &[],
}
}
pub(crate) fn lists(&self) -> Vec<&[Node]> {
let mut lists = vec![self.children()];
if let Self::ComponentContainer(container) = self {
lists.extend(instances(container.instances.as_deref()));
for slot in &container.slots {
lists.push(&slot.children);
lists.extend(instances(slot.instances.as_deref()));
}
}
lists
}
pub(crate) fn lists_mut(&mut self) -> Vec<&mut Vec<Node>> {
let Self::ComponentContainer(container) = self else {
return self.children_mut().into_iter().collect();
};
let mut lists = vec![&mut container.children];
lists.extend(instances_mut(container.instances.as_deref_mut()));
for slot in &mut container.slots {
lists.push(&mut slot.children);
lists.extend(instances_mut(slot.instances.as_deref_mut()));
}
lists
}
pub(crate) fn children_mut(&mut self) -> Option<&mut Vec<Node>> {
match self {
Self::Blockquote(Blockquote { children, .. })
| Self::Delete(Parent { children, .. })
| Self::Emphasis(Parent { children, .. })
| Self::Paragraph(Parent { children, .. })
| Self::Strong(Parent { children, .. })
| Self::TableCell(Parent { children, .. })
| Self::TableRow(Parent { children, .. })
| Self::FootnoteDefinition(FootnoteDefinition { children, .. })
| Self::Heading(Heading { children, .. })
| Self::Link(Link { children, .. })
| Self::LinkReference(LinkReference { children, .. })
| Self::List(List { children, .. })
| Self::ListItem(ListItem { children, .. })
| Self::Table(Table { children, .. })
| Self::ComponentContainer(Container { children, .. })
| Self::ComponentPending(Pending { children, .. }) => Some(children),
Self::ComponentLeaf(leaf) | Self::ComponentInline(leaf) => Some(&mut leaf.fallback),
_ => None,
}
}
}
fn instances(instances: Option<&[Instance]>) -> impl Iterator<Item = &[Node]> {
instances
.into_iter()
.flatten()
.map(|instance| instance.children.as_slice())
}
fn instances_mut(instances: Option<&mut [Instance]>) -> impl Iterator<Item = &mut Vec<Node>> {
instances
.into_iter()
.flatten()
.map(|instance| &mut instance.children)
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Container {
pub name: String,
pub params: Vec<Param>,
pub children: Vec<Node>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instances: Option<Vec<Instance>>,
pub slots: Vec<Slot>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
#[serde(tag = "type", rename = "componentSlot")]
pub struct Slot {
pub name: String,
pub children: Vec<Node>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instances: Option<Vec<Instance>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub origin: Option<Origin>,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct Instance {
pub value: Value,
pub children: Vec<Node>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Code {
pub lang: Option<String>,
pub meta: Option<String>,
pub value: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub component: Option<Rendered>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alt: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Rendered {
pub name: String,
pub params: Vec<Param>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Leaf {
pub name: String,
pub params: Vec<Param>,
pub fallback: Vec<Node>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Pending {
pub name: String,
pub pack: String,
pub children: Vec<Node>,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct Param {
pub key: String,
pub breakpoint: Option<String>,
pub value: Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct Origin {
pub start: Point,
pub end: Point,
pub occurrence: usize,
}