use organic::types::StandardProperties; use url::Url; use super::get_web_path; use super::macros::intermediate; use super::IObject; use crate::context::RenderContext; use crate::error::CustomError; #[derive(Debug, Clone)] pub(crate) struct IRegularLink { pub(crate) raw_link: String, pub(crate) children: Vec, pub(crate) target: LinkTarget, pub(crate) post_blank: organic::types::PostBlank, } intermediate!( IRegularLink, &'orig organic::types::RegularLink<'parse>, original, intermediate_context, { let children = { let mut ret = Vec::new(); for obj in original.children.iter() { ret.push(IObject::new(intermediate_context.clone(), obj).await?); } ret }; let raw_link = original.get_raw_link(); let target = LinkTarget::from_string(&raw_link)?; Ok(IRegularLink { raw_link: raw_link.into_owned(), children, target, post_blank: original.get_post_blank(), }) } ); #[derive(Debug, Clone)] pub(crate) enum LinkTarget { Raw(String), Post { post_id: Option, subpath: String, }, } impl LinkTarget { pub(crate) fn from_string>(input: S) -> Result { fn impl_from_string(input: &str) -> Result { let parsed = Url::parse(input); if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed { // For URLs to targets. // TODO: This shouldn't be raw but instead a variant for targets. return Ok(LinkTarget::Raw(input.to_owned())); } let parsed = parsed?; match parsed.scheme() { "post" => { let post_id = parsed.host_str().map(str::to_owned); let subpath = { let subpath = parsed.path(); if let Some(subpath) = subpath.strip_prefix('/') { subpath } else { subpath } }; Ok(LinkTarget::Post { post_id, subpath: subpath.to_owned(), }) } _ => Ok(LinkTarget::Raw(input.to_owned())), } } impl_from_string(input.as_ref()) } pub(crate) fn generate_final_target( &self, render_context: RenderContext<'_>, ) -> Result, CustomError> { match self { LinkTarget::Raw(raw_link) => Ok(Some(raw_link.clone())), LinkTarget::Post { post_id, subpath } => { let path = post_id .as_ref() .map(|post_id| { let path_to_post = render_context .config .get_relative_path_to_post(post_id) .join(subpath); get_web_path( render_context.config, render_context.output_root_directory, render_context.output_file, path_to_post, ) }) .map_or(Ok(None), |r| r.map(Some))?; Ok(path) } } } }