use organic::types::StandardProperties; use url::Url; use super::get_web_path; use super::macros::intermediate; use super::IntermediateContext; 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(intermediate_context.clone(), raw_link.clone().into_owned())?; 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, }, Target { target_id: String, }, } impl LinkTarget { pub(crate) fn from_string( intermediate_context: IntermediateContext<'_, '_>, input: String, ) -> Result { let parsed = Url::parse(&input); if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed { let target_id = { let mut registry = intermediate_context.registry.lock().unwrap(); let target_id = registry.get_target(input).to_owned(); target_id }; return Ok(LinkTarget::Target { target_id }); } 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())), } } 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) } LinkTarget::Target { target_id } => Ok(Some(format!( "#{}{}", render_context .id_addition .map(|id_addition| format!("sec{}.", id_addition)) .unwrap_or_default(), target_id ))), } } }