use crate::ast::*;
pub trait Transformer {
fn transform_document(&mut self, doc: Document) -> Document {
self.walk_transform_document(doc)
}
fn transform_block(&mut self, block: Block) -> Block {
self.walk_transform_block(block)
}
fn transform_inline(&mut self, inline: Inline) -> Inline {
self.walk_transform_inline(inline)
}
fn transform_table_cell(&mut self, cell: TableCell) -> TableCell {
self.walk_transform_table_cell(cell)
}
fn transform_list_item(&mut self, item: ListItem) -> ListItem {
self.walk_transform_list_item(item)
}
fn transform_table_row(&mut self, row: TableRow) -> TableRow {
self.walk_transform_table_row(row)
}
fn transform_heading(&mut self, heading: Heading) -> Heading {
self.walk_transform_heading(heading)
}
fn transform_link(&mut self, link: Link) -> Link {
self.walk_transform_link(link)
}
fn transform_image(&mut self, image: Image) -> Image {
self.walk_transform_image(image)
}
fn transform_code_block(&mut self, code_block: CodeBlock) -> CodeBlock {
self.walk_transform_code_block(code_block)
}
fn transform_text(&mut self, text: String) -> String {
self.walk_transform_text(text)
}
fn transform_footnote_definition(
&mut self,
footnote: FootnoteDefinition,
) -> FootnoteDefinition {
self.walk_transform_footnote_definition(footnote)
}
fn transform_github_alert(&mut self, alert: GitHubAlert) -> GitHubAlert {
self.walk_transform_github_alert(alert)
}
fn walk_transform_document(&mut self, mut doc: Document) -> Document {
doc.blocks = doc
.blocks
.into_iter()
.map(|block| self.transform_block(block))
.collect();
doc
}
fn walk_transform_block(&mut self, block: Block) -> Block {
match block {
Block::Paragraph(inlines) => Block::Paragraph(
inlines
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect(),
),
Block::Heading(heading) => Block::Heading(self.transform_heading(heading)),
Block::BlockQuote(blocks) => Block::BlockQuote(
blocks
.into_iter()
.map(|block| self.transform_block(block))
.collect(),
),
Block::List(mut list) => {
list.items = list
.items
.into_iter()
.map(|item| self.transform_list_item(item))
.collect();
Block::List(list)
}
Block::Table(mut table) => {
table.rows = table
.rows
.into_iter()
.map(|row| self.transform_table_row(row))
.collect();
Block::Table(table)
}
Block::FootnoteDefinition(footnote) => {
Block::FootnoteDefinition(self.transform_footnote_definition(footnote))
}
Block::GitHubAlert(alert) => Block::GitHubAlert(self.transform_github_alert(alert)),
Block::Definition(mut def) => {
def.label = def
.label
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect();
Block::Definition(def)
}
Block::CodeBlock(code_block) => Block::CodeBlock(self.transform_code_block(code_block)),
other => other,
}
}
fn walk_transform_inline(&mut self, inline: Inline) -> Inline {
match inline {
Inline::Emphasis(inlines) => Inline::Emphasis(
inlines
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect(),
),
Inline::Strong(inlines) => Inline::Strong(
inlines
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect(),
),
Inline::Strikethrough(inlines) => Inline::Strikethrough(
inlines
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect(),
),
Inline::Link(link) => Inline::Link(self.transform_link(link)),
Inline::LinkReference(mut link_ref) => {
link_ref.label = link_ref
.label
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect();
link_ref.text = link_ref
.text
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect();
Inline::LinkReference(link_ref)
}
Inline::Image(image) => Inline::Image(self.transform_image(image)),
Inline::Text(text) => Inline::Text(self.transform_text(text)),
other => other,
}
}
fn walk_transform_table_cell(&mut self, cell: TableCell) -> TableCell {
cell.into_iter()
.map(|inline| self.transform_inline(inline))
.collect()
}
fn walk_transform_list_item(&mut self, mut item: ListItem) -> ListItem {
item.blocks = item
.blocks
.into_iter()
.map(|block| self.transform_block(block))
.collect();
item
}
fn walk_transform_table_row(&mut self, row: TableRow) -> TableRow {
row.into_iter()
.map(|cell| self.transform_table_cell(cell))
.collect()
}
fn walk_transform_heading(&mut self, mut heading: Heading) -> Heading {
heading.content = heading
.content
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect();
heading
}
fn walk_transform_link(&mut self, mut link: Link) -> Link {
link.children = link
.children
.into_iter()
.map(|inline| self.transform_inline(inline))
.collect();
link
}
fn walk_transform_image(&mut self, image: Image) -> Image {
image
}
fn walk_transform_code_block(&mut self, code_block: CodeBlock) -> CodeBlock {
code_block
}
fn walk_transform_text(&mut self, text: String) -> String {
text
}
fn expand_document(&mut self, doc: Document) -> Vec<Document> {
vec![self.transform_document(doc)]
}
fn expand_block(&mut self, block: Block) -> Vec<Block> {
vec![self.transform_block(block)]
}
fn expand_inline(&mut self, inline: Inline) -> Vec<Inline> {
vec![self.transform_inline(inline)]
}
fn expand_table_cell(&mut self, cell: TableCell) -> Vec<TableCell> {
vec![self.transform_table_cell(cell)]
}
fn expand_list_item(&mut self, item: ListItem) -> Vec<ListItem> {
vec![self.transform_list_item(item)]
}
fn expand_table_row(&mut self, row: TableRow) -> Vec<TableRow> {
vec![self.transform_table_row(row)]
}
fn expand_heading(&mut self, heading: Heading) -> Vec<Heading> {
vec![self.transform_heading(heading)]
}
fn expand_link(&mut self, link: Link) -> Vec<Link> {
vec![self.transform_link(link)]
}
fn expand_image(&mut self, image: Image) -> Vec<Image> {
vec![self.transform_image(image)]
}
fn expand_code_block(&mut self, code_block: CodeBlock) -> Vec<CodeBlock> {
vec![self.transform_code_block(code_block)]
}
fn expand_text(&mut self, text: String) -> Vec<String> {
vec![self.transform_text(text)]
}
fn expand_footnote_definition(
&mut self,
footnote: FootnoteDefinition,
) -> Vec<FootnoteDefinition> {
vec![self.transform_footnote_definition(footnote)]
}
fn expand_github_alert(&mut self, alert: GitHubAlert) -> Vec<GitHubAlert> {
vec![self.transform_github_alert(alert)]
}
fn walk_expand_document(&mut self, mut doc: Document) -> Vec<Document> {
doc.blocks = doc
.blocks
.into_iter()
.flat_map(|block| self.walk_expand_block(block))
.collect();
vec![doc]
}
fn walk_expand_block(&mut self, block: Block) -> Vec<Block> {
match block {
Block::Paragraph(inlines) => {
let expanded_inlines: Vec<Inline> = inlines
.into_iter()
.flat_map(|inline| self.walk_expand_inline(inline))
.collect();
vec![Block::Paragraph(expanded_inlines)]
}
Block::Heading(mut heading) => {
heading.content = heading
.content
.into_iter()
.flat_map(|inline| self.walk_expand_inline(inline))
.collect();
vec![Block::Heading(heading)]
}
Block::BlockQuote(blocks) => {
let expanded_blocks: Vec<Block> = blocks
.into_iter()
.flat_map(|block| self.walk_expand_block(block))
.collect();
vec![Block::BlockQuote(expanded_blocks)]
}
Block::List(mut list) => {
list.items = list
.items
.into_iter()
.flat_map(|item| self.walk_expand_list_item(item))
.collect();
vec![Block::List(list)]
}
Block::Table(mut table) => {
table.rows = table
.rows
.into_iter()
.flat_map(|row| self.walk_expand_table_row(row))
.collect();
vec![Block::Table(table)]
}
Block::FootnoteDefinition(mut footnote) => {
footnote.blocks = footnote
.blocks
.into_iter()
.flat_map(|block| self.walk_expand_block(block))
.collect();
vec![Block::FootnoteDefinition(footnote)]
}
Block::GitHubAlert(mut alert) => {
alert.blocks = alert
.blocks
.into_iter()
.flat_map(|block| self.walk_expand_block(block))
.collect();
vec![Block::GitHubAlert(alert)]
}
Block::Definition(mut def) => {
def.label = def
.label
.into_iter()
.flat_map(|inline| self.walk_expand_inline(inline))
.collect();
vec![Block::Definition(def)]
}
other => vec![self.transform_block(other)],
}
}
fn walk_expand_inline(&mut self, inline: Inline) -> Vec<Inline> {
vec![self.transform_inline(inline)]
}
fn walk_expand_table_cell(&mut self, cell: TableCell) -> Vec<TableCell> {
let expanded_cell = cell
.into_iter()
.flat_map(|inline| self.expand_inline(inline))
.collect();
vec![expanded_cell]
}
fn walk_expand_list_item(&mut self, mut item: ListItem) -> Vec<ListItem> {
item.blocks = item
.blocks
.into_iter()
.flat_map(|block| self.expand_block(block))
.collect();
vec![item]
}
fn walk_expand_table_row(&mut self, row: TableRow) -> Vec<TableRow> {
let expanded_row = row
.into_iter()
.flat_map(|cell| self.expand_table_cell(cell))
.collect();
vec![expanded_row]
}
fn walk_expand_heading(&mut self, mut heading: Heading) -> Vec<Heading> {
heading.content = heading
.content
.into_iter()
.flat_map(|inline| self.expand_inline(inline))
.collect();
vec![heading]
}
fn walk_expand_link(&mut self, mut link: Link) -> Vec<Link> {
link.children = link
.children
.into_iter()
.flat_map(|inline| self.expand_inline(inline))
.collect();
vec![link]
}
fn walk_expand_image(&mut self, image: Image) -> Vec<Image> {
vec![image]
}
fn walk_expand_code_block(&mut self, code_block: CodeBlock) -> Vec<CodeBlock> {
vec![code_block]
}
fn walk_expand_text(&mut self, text: String) -> Vec<String> {
vec![text]
}
fn walk_expand_footnote_definition(
&mut self,
mut footnote: FootnoteDefinition,
) -> Vec<FootnoteDefinition> {
footnote.blocks = footnote
.blocks
.into_iter()
.flat_map(|block| self.expand_block(block))
.collect();
vec![footnote]
}
fn walk_expand_github_alert(&mut self, mut alert: GitHubAlert) -> Vec<GitHubAlert> {
alert.blocks = alert
.blocks
.into_iter()
.flat_map(|block| self.expand_block(block))
.collect();
vec![alert]
}
fn walk_transform_footnote_definition(
&mut self,
mut footnote: FootnoteDefinition,
) -> FootnoteDefinition {
footnote.blocks = footnote
.blocks
.into_iter()
.map(|block| self.transform_block(block))
.collect();
footnote
}
fn walk_transform_github_alert(&mut self, mut alert: GitHubAlert) -> GitHubAlert {
alert.blocks = alert
.blocks
.into_iter()
.map(|block| self.transform_block(block))
.collect();
alert
}
}
pub trait TransformWith {
fn transform_with<T: Transformer>(self, transformer: &mut T) -> Self;
}
impl TransformWith for Document {
fn transform_with<T: Transformer>(self, transformer: &mut T) -> Self {
transformer.transform_document(self)
}
}
impl TransformWith for Block {
fn transform_with<T: Transformer>(self, transformer: &mut T) -> Self {
transformer.transform_block(self)
}
}
impl TransformWith for Inline {
fn transform_with<T: Transformer>(self, transformer: &mut T) -> Self {
transformer.transform_inline(self)
}
}
pub trait ExpandWith {
fn expand_with<T: Transformer>(self, transformer: &mut T) -> Vec<Self>
where
Self: Sized;
}
impl ExpandWith for Document {
fn expand_with<T: Transformer>(self, transformer: &mut T) -> Vec<Self> {
transformer.walk_expand_document(self)
}
}
impl ExpandWith for Block {
fn expand_with<T: Transformer>(self, transformer: &mut T) -> Vec<Self> {
transformer.walk_expand_block(self)
}
}
impl ExpandWith for Inline {
fn expand_with<T: Transformer>(self, transformer: &mut T) -> Vec<Self> {
transformer.walk_expand_inline(self)
}
}
pub struct CompositeTransformer {
transformers: Vec<Box<dyn Transformer>>,
}
impl CompositeTransformer {
pub fn new() -> Self {
Self {
transformers: Vec::new(),
}
}
pub fn add_transformer<T: Transformer + 'static>(mut self, transformer: T) -> Self {
self.transformers.push(Box::new(transformer));
self
}
}
impl Default for CompositeTransformer {
fn default() -> Self {
Self::new()
}
}
impl Transformer for CompositeTransformer {
fn transform_document(&mut self, mut doc: Document) -> Document {
for transformer in &mut self.transformers {
doc = transformer.transform_document(doc);
}
doc
}
fn transform_block(&mut self, mut block: Block) -> Block {
for transformer in &mut self.transformers {
block = transformer.transform_block(block);
}
block
}
fn transform_inline(&mut self, mut inline: Inline) -> Inline {
for transformer in &mut self.transformers {
inline = transformer.transform_inline(inline);
}
inline
}
}