use super::WikiLinkStyle;
pub fn format_link(target: &str, alias: &str, style: WikiLinkStyle) -> String {
match style {
WikiLinkStyle::Obsidian => format!("[[{}|{}]]", target, alias),
WikiLinkStyle::Markdown => format!("[{}]({}.md)", alias, target),
}
}
pub fn safe_filename(raw: &str) -> String {
let mut out = String::with_capacity(raw.len());
let mut last_dash = false;
for c in raw.chars() {
match c {
'/' | '\\' => {
out.push('/');
last_dash = false;
}
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' => {
out.push(c);
last_dash = false;
}
'-' => {
if !last_dash {
out.push('-');
last_dash = true;
}
}
_ => {
if !last_dash {
out.push('-');
last_dash = true;
}
}
}
}
out.trim_matches('-').trim_start_matches('/').to_string()
}
pub fn module_note_target(community_slug: &str, file_path: &str) -> String {
format!("30-Modules/{}/{}", community_slug, safe_filename(file_path))
}
pub fn file_group(file_path: &str) -> String {
let parent = file_path.rsplit_once('/').map(|(p, _)| p).unwrap_or("");
if parent.is_empty() {
return "root".to_string();
}
let trimmed = parent
.trim_start_matches("./")
.trim_start_matches("crates/")
.trim_start_matches("packages/")
.trim_start_matches("apps/")
.trim_start_matches("services/");
let parts: Vec<&str> = trimmed
.split('/')
.filter(|s| !s.is_empty() && *s != "src")
.collect();
if parts.is_empty() {
return "root".to_string();
}
let take = parts.len().min(2);
let joined: String = parts[..take].join("/");
safe_filename(&joined)
}
pub fn file_group_slug(file_path: &str) -> String {
let g = file_group(file_path);
g.replace('/', "-")
}
pub fn public_api_target(community_slug: &str) -> String {
format!("10-PublicAPI/{}", community_slug)
}
pub fn community_slug(label: &str, id: i64) -> String {
let slug = safe_filename(label).to_lowercase().replace('/', "-");
let slug = slug.trim_matches('-').to_string();
if slug.is_empty() {
format!("community-{}", id)
} else {
slug
}
}