wikilink.mjs
44 lines 1.4 KB
Raw
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 1 day ago
1 /**
2 * Obsidian-style `[[wikilink]]` parsing shared by local `lib/backlinks.mjs` and hosted MCP `backlinks`.
3 */
4
5 const WIKILINK = /\[\[([^\]|#]+)(?:#[^\]|]+)?(?:\|[^\]]+)?\]\]/g;
6
7 /**
8 * Normalize wikilink inner text to comparable basename (no `.md`), lowercase.
9 * @param {string} raw
10 */
11 export function wikilinkTargetKey(raw) {
12 const s = String(raw).trim();
13 const last = s.split(/[/\\]/).pop() || s;
14 return last.replace(/\.md$/i, '').toLowerCase();
15 }
16
17 /**
18 * Target key for the note at `vaultRelativePath` (basename stem), same as local backlinks target.
19 * @param {string} vaultRelativePath
20 */
21 export function vaultBasenameTargetKey(vaultRelativePath) {
22 const target = String(vaultRelativePath).replace(/\\/g, '/');
23 return wikilinkTargetKey(target.split('/').pop() || target);
24 }
25
26 /**
27 * If `body` contains a wikilink whose target normalizes to `targetKey`, return trimmed context around
28 * the first match; otherwise `null`.
29 * @param {string} body
30 * @param {string} targetKey
31 * @returns {string|null}
32 */
33 export function findFirstWikilinkToTargetInBody(body, targetKey) {
34 const text = body != null ? String(body) : '';
35 WIKILINK.lastIndex = 0;
36 let m;
37 while ((m = WIKILINK.exec(text)) !== null) {
38 if (wikilinkTargetKey(m[1]) !== targetKey) continue;
39 const start = Math.max(0, m.index - 60);
40 const end = Math.min(text.length, m.index + m[0].length + 60);
41 return text.slice(start, end).replace(/\s+/g, ' ').trim();
42 }
43 return null;
44 }
File History 1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 1 day ago