feat: prototype of the markdown to npf conversion
This commit is contained in:
@@ -1,3 +1 @@
|
||||
pub mod npf;
|
||||
|
||||
fn test() {}
|
||||
|
||||
@@ -1,5 +1,143 @@
|
||||
use std::{
|
||||
borrow::{Borrow, BorrowMut},
|
||||
cell::RefCell,
|
||||
};
|
||||
|
||||
use comrak::{
|
||||
arena_tree::Node,
|
||||
nodes::{Ast, AstNode, NodeValue},
|
||||
};
|
||||
|
||||
pub mod attributions;
|
||||
pub mod content_blocks;
|
||||
pub mod layout_blocks;
|
||||
pub mod objects;
|
||||
pub mod text_formatting;
|
||||
|
||||
use content_blocks::{BlockText, BlockValue};
|
||||
use text_formatting::{FormatTypeBold, FormatTypeItalic, FormatValue};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NPFConvertError {
|
||||
TODO,
|
||||
}
|
||||
|
||||
fn extract_text(contents: &Vec<BlockValue>) -> String {
|
||||
contents
|
||||
.iter()
|
||||
.fold(String::new(), |mut a, c| {
|
||||
if let BlockValue::Text(block) = c {
|
||||
a.push_str(&format!(" {}", block.text));
|
||||
}
|
||||
a
|
||||
})
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a Node<'a, RefCell<Ast>>> for objects::Post {
|
||||
type Error = NPFConvertError;
|
||||
fn try_from(value: &'a Node<'a, RefCell<Ast>>) -> Result<Self, Self::Error> {
|
||||
let mut post = Self::new(0);
|
||||
|
||||
let nodes = value.children().into_iter();
|
||||
let r: Result<Vec<_>, NPFConvertError> = nodes
|
||||
.map(|n| match &n.data.borrow().value {
|
||||
NodeValue::Paragraph => {
|
||||
let mut paragraph_contents = Self::try_from(n)?.content;
|
||||
post.content.append(&mut paragraph_contents);
|
||||
Ok(())
|
||||
}
|
||||
NodeValue::Text(t) => {
|
||||
let block_text = BlockText::from(String::from(t.clone()));
|
||||
post.content.push(BlockValue::Text(block_text));
|
||||
Ok(())
|
||||
}
|
||||
NodeValue::Strong => {
|
||||
let mut content = Self::try_from(n)?.content;
|
||||
let mut res = content.iter_mut().fold(
|
||||
BlockText::new(&String::new()),
|
||||
|mut acc, c| match c {
|
||||
BlockValue::Text(t) => {
|
||||
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
|
||||
}
|
||||
_ => acc,
|
||||
},
|
||||
);
|
||||
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(())
|
||||
}
|
||||
NodeValue::Emph => {
|
||||
let mut content = Self::try_from(n)?.content;
|
||||
let mut res = content.iter_mut().fold(
|
||||
BlockText::new(&String::new()),
|
||||
|mut acc, c| match c {
|
||||
BlockValue::Text(t) => {
|
||||
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
|
||||
}
|
||||
_ => acc,
|
||||
},
|
||||
);
|
||||
res.text = res.text.trim().to_string();
|
||||
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(()),
|
||||
})
|
||||
.collect();
|
||||
if let Err(e) = r {
|
||||
Err(e)
|
||||
} else {
|
||||
// println!("{:#?}", post);
|
||||
Ok(post)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from<'a>(node: &'a Node<'a, RefCell<Ast>>) -> Result<objects::Post, NPFConvertError> {
|
||||
objects::Post::try_from(node)
|
||||
}
|
||||
|
||||
/*
|
||||
Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa duis
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::objects;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum AttributionValue {
|
||||
Post(AttributionPost),
|
||||
@@ -12,7 +12,7 @@ pub enum AttributionValue {
|
||||
Blog(AttributionBlog),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct AttributionPost {
|
||||
r#type: String,
|
||||
pub url: url::Url,
|
||||
@@ -41,7 +41,7 @@ impl AttributionPost {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct AttributionLink {
|
||||
r#type: String,
|
||||
pub url: url::Url,
|
||||
@@ -66,7 +66,7 @@ impl From<url::Url> for AttributionLink {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct AttributionBlog {
|
||||
r#type: String,
|
||||
pub url: Option<url::Url>,
|
||||
@@ -103,7 +103,7 @@ impl TryFrom<objects::BlogInfo> for AttributionBlog {
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct AttributionApp {
|
||||
r#type: String,
|
||||
pub url: url::Url,
|
||||
|
||||
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{attributions, objects};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum BlockValue {
|
||||
Text(BlockText),
|
||||
@@ -14,7 +14,7 @@ pub enum BlockValue {
|
||||
Video(BlockVideo),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum BlockTextSubtype {
|
||||
Heading1,
|
||||
@@ -28,7 +28,7 @@ pub enum BlockTextSubtype {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockText {
|
||||
r#type: String,
|
||||
pub subtype: Option<BlockTextSubtype>,
|
||||
@@ -68,7 +68,7 @@ impl From<&str> for BlockText {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockImage {
|
||||
r#type: String,
|
||||
pub media: Vec<objects::Media>,
|
||||
@@ -111,7 +111,7 @@ impl From<objects::Media> for BlockImage {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockLink {
|
||||
r#type: String,
|
||||
pub url: url::Url,
|
||||
@@ -149,7 +149,7 @@ impl From<url::Url> for BlockLink {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockAudio {
|
||||
r#type: String,
|
||||
pub media: Option<objects::Media>,
|
||||
@@ -210,7 +210,7 @@ impl From<url::Url> for BlockAudio {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockVideo {
|
||||
r#type: String,
|
||||
pub url: Option<url::Url>,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum BlockValue {
|
||||
Rows(BlockRows),
|
||||
Ask(BlockAsk),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockRows {
|
||||
r#type: String,
|
||||
pub display: Vec<DisplayBlocks>,
|
||||
@@ -42,7 +42,7 @@ impl From<DisplayBlocks> for BlockRows {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct DisplayBlocks {
|
||||
pub blocks: Vec<u64>,
|
||||
pub mode: Option<String>,
|
||||
@@ -75,7 +75,7 @@ impl From<u64> for DisplayBlocks {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlockAsk {
|
||||
r#type: String,
|
||||
blocks: Vec<u64>,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BlogInfo {
|
||||
pub uuid: String,
|
||||
pub name: Option<String>,
|
||||
@@ -48,14 +48,14 @@ impl From<url::Url> for BlogInfo {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct ReblogTrailPost {
|
||||
pub id: String,
|
||||
pub timestamp: Option<String>,
|
||||
pub is_commercial: Option<bool>,
|
||||
}
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct ReblogTrail {
|
||||
pub post: Option<ReblogTrailPost>,
|
||||
pub blog: Option<BlogInfo>,
|
||||
@@ -65,7 +65,7 @@ pub struct ReblogTrail {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Avatar {
|
||||
pub width: u64,
|
||||
pub height: u64,
|
||||
@@ -74,7 +74,7 @@ pub struct Avatar {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Post {
|
||||
object_type: String,
|
||||
pub id: u64,
|
||||
@@ -188,7 +188,7 @@ impl From<u64> for Post {
|
||||
}
|
||||
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Media {
|
||||
pub r#type: Option<String>,
|
||||
pub url: url::Url,
|
||||
@@ -223,7 +223,7 @@ impl From<url::Url> for Media {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct EmbedIframe {
|
||||
pub url: url::Url,
|
||||
pub width: u64,
|
||||
|
||||
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::objects;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum FormatValue {
|
||||
Bold(FormatTypeBold),
|
||||
@@ -15,12 +15,25 @@ pub enum FormatValue {
|
||||
Mention(FormatTypeMention),
|
||||
Color(FormatTypeColor),
|
||||
}
|
||||
impl FormatValue {
|
||||
pub fn offset(&mut self, offset: u64) {
|
||||
match self {
|
||||
FormatValue::Bold(ref mut f) => f.offset(offset),
|
||||
FormatValue::Italic(ref mut f) => f.offset(offset),
|
||||
FormatValue::Link(ref mut f) => f.offset(offset),
|
||||
FormatValue::Small(ref mut f) => f.offset(offset),
|
||||
FormatValue::Color(ref mut f) => f.offset(offset),
|
||||
FormatValue::Mention(ref mut f) => f.offset(offset),
|
||||
FormatValue::StrikeThrough(ref mut f) => f.offset(offset),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait FormatType: From<Range<u64>> + From<String> {
|
||||
fn default() -> Self;
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct FormatTypeLink {
|
||||
r#type: String,
|
||||
pub start: u64,
|
||||
@@ -46,7 +59,7 @@ impl FormatType for FormatTypeLink {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct FormatTypeMention {
|
||||
r#type: String,
|
||||
pub start: u64,
|
||||
@@ -72,7 +85,7 @@ impl FormatType for FormatTypeMention {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct FormatTypeColor {
|
||||
r#type: String,
|
||||
pub start: u64,
|
||||
@@ -120,6 +133,15 @@ macro_rules! ImplInlines {
|
||||
}
|
||||
}
|
||||
})*
|
||||
$(impl From<&String> for $t {
|
||||
fn from(value: &String) -> Self {
|
||||
Self {
|
||||
start: 0,
|
||||
end: value.chars().count() as u64,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
})*
|
||||
$(impl From<&str> for $t {
|
||||
fn from(value: &str) -> Self {
|
||||
Self {
|
||||
@@ -129,11 +151,17 @@ macro_rules! ImplInlines {
|
||||
}
|
||||
}
|
||||
})*
|
||||
$(impl $t {
|
||||
pub fn offset(&mut self, offset: u64) {
|
||||
self.start += offset;
|
||||
self.end += offset;
|
||||
}
|
||||
})*
|
||||
};
|
||||
// Defines the struct and implements Default trait if the token is an
|
||||
// identifier and a literal
|
||||
(for $($t:ident $s:literal),+) => {
|
||||
$(#[derive(Debug, Deserialize, Serialize)]
|
||||
$(#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct $t {
|
||||
r#type: String,
|
||||
pub start: u64,
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::path::PathBuf;
|
||||
use clap::{ArgAction, Parser, Subcommand};
|
||||
use clio::Input;
|
||||
|
||||
use mdparser::convert;
|
||||
use mdparser::frontmatter::Frontmatter;
|
||||
use mdparser::links;
|
||||
use mdparser::utils;
|
||||
@@ -72,6 +73,9 @@ fn main() {
|
||||
let arena = comrak::Arena::new();
|
||||
let ast = comrak::parse_document(&arena, &file, &mdparser::utils::default_options());
|
||||
|
||||
let _ = convert::npf::from(ast);
|
||||
// println!("{:#?}", ast);
|
||||
|
||||
let result = match cli.command {
|
||||
Commands::Links { list, replace_url } => {
|
||||
let list = if replace_url.len() == 0 && !list {
|
||||
|
||||
Reference in New Issue
Block a user