// 共享的 Markdown 文档渲染工具。
// 纯函数,不依赖 HTTP/存储层;供后端 cmd/server 复用,
// 保障渲染安全边界不被重写。
///|
pub struct DocumentMeta {
body : String
title : String
tags : String
status : String
category : String
}
///|
/// 解析 Markdown front matter(`title` / `tags` / `status` / `category`),返回结构体。
pub fn document_meta(raw : String) -> DocumentMeta {
let fallback_title = match raw.find("# ") {
Some(i) => {
let line = raw[i + 2:]
match line.find("\n") {
Some(end) => line[:end].to_owned()
None => line.to_owned()
}
}
None => "rootwarren"
}
if !raw.has_prefix("---\n") {
return {
body: raw,
title: fallback_title,
tags: "",
status: "public",
category: "",
}
}
let end = match raw.find("\n---\n") {
Some(i) => i
None =>
return {
body: raw,
title: fallback_title,
tags: "",
status: "public",
category: "",
}
}
let header = raw[4:end]
let body = raw[end + 5:].to_owned()
let mut title = fallback_title
let mut tags = ""
let mut status = "public"
let mut category = ""
for line in header.split("\n") {
let line = line.to_owned()
if line.has_prefix("title:") {
title = line[6:].trim().to_owned()
} else if line.has_prefix("tags:") {
tags = line[5:].trim().to_owned()
} else if line.has_prefix("status:") {
status = line[7:].trim().to_owned()
} else if line.has_prefix("category:") {
category = line[9:].trim().to_owned()
}
}
{ body, title, tags, status, category, }
}
///|
/// 将已渲染的 Markdown HTML 中的相对 Wiki 链接重写为 `/d/{slug}` 形式。
/// `base_slug` 是当前文档的 slug(用于解析相对路径目录)。
/// 规则:不以 `/`、`http(s):`、`#`、`mailto:` 开头的目标视为站点内相对链接,
/// 基于 `base_slug` 的目录解析成绝对 `/d/{slug}`,并去掉 `.md` 后缀。
pub fn rewrite_wiki_links(html : String, base_slug : String) -> String {
rewrite_hrefs(html, base_slug)
}
///|
/// 从已重写的渲染 HTML 中提取所有指向站点文档的 slug(去重),用于链接台账。
pub fn extract_link_slugs(html : String) -> Array[String] {
let seen : Map[String, Bool] = Map([])
let acc : Array[String] = []
let mut rest = html
while rest.length() > 0 {
match rest.find("/d/") {
None => break
Some(i) => {
let after = rest[i + 3:].to_owned()
let slug = take_slug(after)
if !slug.is_empty() && !seen.contains(slug) {
seen[slug] = true
ignore(acc.push(slug))
}
rest = after
}
}
}
acc
}
///|
/// 从 `/d/` 之后的字符串提取一个 slug 片段。
fn take_slug(s : String) -> String {
let sb = StringBuilder()
let mut i = 0
while i < s.length() {
match s.get_char(i) {
Some(c) =>
if (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '/' ||
c == '-' ||
c == '_' ||
c == '.' {
sb.write_char(c)
i += 1
} else {
break
}
None => break
}
}
sb.to_string()
}
///|
/// 把站点内路径(可能含 `./`/`../`/`.md`)归一化为不带前导斜杠的 slug。
fn resolve_abs(path : String) -> String {
let p = strip_md(path)
let parts : Array[String] = []
for seg in p.split("/") {
let s = seg.trim().to_owned()
if s.is_empty() || s == "." {
continue
} else if s == ".." {
if parts.length() > 0 {
ignore(parts.pop())
}
} else {
parts.push(s)
}
}
parts.join("/")
}
///|
/// 去掉末尾 `.md` 后缀。
fn strip_md(p : String) -> String {
if p.has_suffix(".md") {
p[:p.length() - 3].to_owned()
} else {
p
}
}
///|
/// 扫描已渲染 HTML 的所有 `href="..."`,把相对链接重写为 `/d/{slug}`。
fn rewrite_hrefs(html : String, base_slug : String) -> String {
recur_rewrite_hrefs(html, base_slug, "")
}
///|
/// 递归扫描剩余字符串,累积重写结果。
fn recur_rewrite_hrefs(
rest : String,
base_slug : String,
out : String,
) -> String {
let dir = base_dir_of(base_slug)
match rest.find("href=\"") {
None => out + rest
Some(i) => {
let before = rest[:i + 6].to_owned()
let after = rest[i + 6:]
match after.find("\"") {
None => out + before + after.to_owned()
Some(j) => {
let val = after[:j].to_owned()
let rewritten = rewrite_one_href(val, dir)
recur_rewrite_hrefs(
after[j + 1:].to_owned(),
base_slug,
out + before + rewritten + "\"",
)
}
}
}
}
}
///|
/// 根据 dir 目录重写一条 href:站点内相对链接 → `/d/{slug}`,否则保持。
fn rewrite_one_href(val : String, dir : String) -> String {
if val.is_empty() {
return val
}
if ["/", "http://", "https://", "#", "mailto:", "data:"].any(fn(p) {
val.has_prefix(p)
}) {
return val
}
// 相对链接:基于当前文档目录 dir 解析,再归一化到站点内 slug。
let base = if dir.is_empty() { "" } else { dir + "/" }
let rel = strip_md(val)
let full = base + rel
let slug = resolve_abs(full)
if slug.is_empty() {
val
} else {
"/d/" + slug
}
}
///|
/// 取 base_slug 去掉最后一段后的目录前缀(如 `guide/getting-started` → `guide`)。
fn base_dir_of(base_slug : String) -> String {
let parts = base_slug.split("/")
if parts.length() <= 1 {
""
} else {
parts[0:parts.length() - 1].join("/")
}
}
///|
/// 渲染一篇 Markdown 文档为可展示的 HTML 段落(不含页面骨架)。
/// `slug` 用于把正文里的相对链接解析成 `/d/{slug}`。
pub fn render_doc_html(raw : String, slug : String) -> String {
let meta = document_meta(raw)
let html = @cmark_html.render(meta.body, safe=true) catch { _ => "" }
rewrite_wiki_links(html, slug)
}
///|
pub fn config_site_title(value : String?) -> String {
match value {
Some(v) if !v.is_empty() => v
_ => "rootwarren"
}
}