From 2a3bf1e8d588dc0e317499fe59ea8357346a9e31 Mon Sep 17 00:00:00 2001 From: Oleksandr Ostrovskyi Date: Wed, 27 May 2026 17:48:02 +0300 Subject: [PATCH] fix(graph): unescape escaped pipe in table-aliased wikilinks Markdown tables escape the wikilink alias pipe as \| (e.g. [[Vlad Apukhtin\|Vlad]]). extract_wikilink_targets split on | without unescaping, capturing "Vlad Apukhtin\" as the target, so valid table-aliased wikilinks stayed permanently unresolved (polluting unresolved_links + dropping graph edges). Unescape \| -> | before splitting. Regression test added. --- src/graph.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/graph.rs b/src/graph.rs index 6eb21e9..370afa6 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -23,8 +23,11 @@ pub fn extract_wikilink_targets(text: &str) -> Vec { { let inner = &rest[..close]; if !is_embed && !inner.is_empty() && !inner.contains('\n') { + // Obsidian escapes the alias pipe as `\|` inside tables; + // unescape it so the `|` separator is recognized. + let inner = inner.replace("\\|", "|"); // Strip heading: [[Note#Section]] → "Note" - let target = inner.split('#').next().unwrap_or(inner); + let target = inner.split('#').next().unwrap_or(inner.as_str()); // Strip display: [[Note|Display]] → "Note" let target = target.split('|').next().unwrap_or(target); let target = target.trim().to_string(); @@ -195,6 +198,15 @@ mod tests { assert_eq!(targets, vec!["Note"]); // strip both heading and display } + #[test] + fn test_extract_wikilinks_escaped_pipe_in_table() { + // Obsidian escapes the alias pipe as `\|` inside tables; the target + // must still resolve to the note name, not "Name\". + let text = "| [[Vlad Apukhtin\\|Vlad]] | done |"; + let targets = extract_wikilink_targets(text); + assert_eq!(targets, vec!["Vlad Apukhtin"]); + } + #[test] fn test_extract_query_terms() { let terms = extract_query_terms("BRE-2579 delivery date");