refactor: improve Post's api for the conversion

This commit is contained in:
Gustavo "Guz" L. de Mello
2024-04-24 20:27:06 -03:00
parent b57435c728
commit 41cb734457
3 changed files with 98 additions and 60 deletions

View File

@@ -1,6 +1,7 @@
use std::{ use std::{
borrow::{Borrow, BorrowMut}, borrow::{Borrow, BorrowMut},
cell::RefCell, cell::RefCell,
collections::VecDeque,
}; };
use comrak::{ use comrak::{
@@ -15,9 +16,12 @@ pub mod objects;
pub mod text_formatting; pub mod text_formatting;
mod objects_post; mod objects_post;
use content_blocks::{BlockText, BlockValue}; use content_blocks::{BlockText, BlockValue};
use text_formatting::{FormatTypeBold, FormatTypeItalic, FormatValue}; use text_formatting::{FormatTypeBold, FormatTypeItalic, FormatValue};
use self::content_blocks::BlockImage;
#[derive(Debug)] #[derive(Debug)]
pub enum NPFConvertError { pub enum NPFConvertError {
TODO, TODO,
@@ -55,72 +59,41 @@ impl<'a> TryFrom<&'a Node<'a, RefCell<Ast>>> for objects::Post {
Ok(()) Ok(())
} }
NodeValue::Strong => { NodeValue::Strong => {
let mut content = Self::try_from(n)?.content; let mut content = Self::try_from(n)?
let mut res = content.iter_mut().fold( .fold_content()
BlockText::new(&String::new()), .for_each_content(|c| {
|mut acc, c| match c { if let BlockValue::Text(ref mut t) = c {
BlockValue::Text(t) => { let format = FormatValue::Bold(FormatTypeBold::from(&t.text));
let text = &t.text.trim(); if let Some(ref mut f) = t.formatting {
if let Some(ref mut f) = &mut t.formatting { f.push(format);
let offset = acc.text.chars().count() as u64; } else {
f.iter_mut().for_each(|f| { t.formatting = Some(vec![format]);
f.offset(offset);
});
if let Some(ref mut af) = acc.formatting {
af.append(f);
} else {
acc.formatting = Some(f.to_vec());
}
} }
acc.text.push_str(&format!("{} ", text)); t.text = String::from(t.text.trim());
acc
} }
_ => acc, })
}, .content;
); post.content.append(&mut content);
res.text = res.text.trim().to_string();
let format = FormatValue::Bold(FormatTypeBold::from(&res.text));
if let Some(ref mut f) = res.formatting {
f.push(format);
} else {
res.formatting = Some(vec![format]);
}
post.content.push(BlockValue::Text(res));
Ok(()) Ok(())
} }
NodeValue::Emph => { NodeValue::Emph => {
let mut content = Self::try_from(n)?.content; let mut content = Self::try_from(n)?
let mut res = content.iter_mut().fold( .fold_content()
BlockText::new(&String::new()), .for_each_content(|c| {
|mut acc, c| match c { if let BlockValue::Text(ref mut t) = c {
BlockValue::Text(t) => { let format = FormatValue::Italic(FormatTypeItalic::from(&t.text));
let text = &t.text.trim(); if let Some(ref mut f) = t.formatting {
if let Some(ref mut f) = &mut t.formatting { f.push(format);
let offset = acc.text.chars().count() as u64; } else {
f.iter_mut().for_each(|f| { t.formatting = Some(vec![format]);
f.offset(offset);
});
if let Some(ref mut af) = acc.formatting {
af.append(f);
} else {
acc.formatting = Some(f.to_vec());
}
} }
acc.text.push_str(&format!("{} ", text)); t.text = String::from(t.text.trim());
acc
} }
_ => acc, })
}, .content;
); post.content.append(&mut content);
res.text = res.text.trim().to_string(); // println!("{:#?}", post);
let format = FormatValue::Italic(FormatTypeItalic::from(&res.text));
if let Some(ref mut f) = res.formatting {
f.push(format);
} else {
res.formatting = Some(vec![format]);
}
// println!("italic {:#?}", res);
post.content.push(BlockValue::Text(res));
Ok(()) Ok(())
} }
_ => Ok(()), _ => Ok(()),
@@ -129,7 +102,7 @@ impl<'a> TryFrom<&'a Node<'a, RefCell<Ast>>> for objects::Post {
if let Err(e) = r { if let Err(e) = r {
Err(e) Err(e)
} else { } else {
// println!("{:#?}", post); println!("{:#?}", post);
Ok(post) Ok(post)
} }
} }

View File

@@ -13,6 +13,17 @@ pub enum BlockValue {
Audio(BlockAudio), Audio(BlockAudio),
Video(BlockVideo), Video(BlockVideo),
} }
impl BlockValue {
pub fn get_type(&self) -> String {
String::from(match &self {
BlockValue::Text(_) => "text",
BlockValue::Image(_) => "image",
BlockValue::Link(_) => "link",
BlockValue::Audio(_) => "audio",
BlockValue::Video(_) => "video",
})
}
}
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]

View File

@@ -1,4 +1,8 @@
use itertools::Itertools;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::content_blocks::{BlockText, BlockValue};
#[serde_with::skip_serializing_none] #[serde_with::skip_serializing_none]
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Post { pub struct Post {
@@ -56,6 +60,37 @@ impl Post {
false false
} }
} }
pub fn fold_content(mut self) -> Self {
// TODO: Some form of folding also the layout of the npf
let groups = self.content.iter_mut().group_by(|c| c.get_type() == "text");
self.content = groups
.into_iter()
.map(|a| {
if a.0 == true {
vec![BlockValue::Text(
a.1.fold(BlockText::new(&String::new()), fold_text_block),
)]
} else {
a.1.map(|c| c.to_owned()).collect::<Vec<_>>()
}
})
.flatten()
.map(|mut a| {
if let BlockValue::Text(ref mut t) = a {
t.text = String::from(t.text.trim());
}
a
})
.collect::<Vec<_>>();
self
}
pub fn for_each_content<F>(mut self, f: F) -> Self
where
F: Fn(&mut BlockValue),
{
self.content.iter_mut().for_each(f);
self
}
fn default() -> Self { fn default() -> Self {
Self { Self {
object_type: String::from("post"), object_type: String::from("post"),
@@ -114,3 +149,22 @@ impl From<u64> for Post {
} }
} }
fn fold_text_block(mut acc: BlockText, c: &mut BlockValue) -> BlockText {
if let BlockValue::Text(t) = c {
let text = &t.text.trim();
if let Some(ref mut f) = &mut t.formatting {
let offset = acc.text.chars().count() as u64;
f.iter_mut().for_each(|f| f.offset(offset));
if let Some(ref mut af) = acc.formatting {
af.append(f);
} else {
acc.formatting = Some(f.to_vec());
}
}
acc.text.push_str(&format!("{} ", text));
}
acc
}