fix: resolve markdown-style relative .md links to permalinks - #398
Merged
Conversation
Notes written with plain markdown links (e.g. [X](../concepts/x.md)) instead of wikilinks reached the rendered HTML untouched. Because pages are served at trailing-slash URLs, the browser resolved those hrefs one directory too deep (/wiki/concepts/concepts/x.md -> 404), and the graph showed no edges since link extraction only matched wikilinks and root-absolute hrefs. - linkUtils: resolveVaultPath() resolves relative/root link targets against the note's vault directory; convertMdHrefs() rewrites .md hrefs in rendered HTML; extractLinks() now also extracts markdown-style links so the graph and backlinks see them - .eleventy.js: new resolveMdLinks filter reusing getAnchorAttributes, so dead links get the same /404 handling as dead wikilinks - note/index layouts and the RSS feed apply the filter (the feed passes note.inputPath explicitly since this.page there is the feed template) Verified against a real affected garden: 0 unresolved internal .md hrefs in built output, graph edges went from 0 to 1196 across 167 notes, and all 166 feed entries carry resolved absolute permalinks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HWqT1iTxSSr3rRhDp4Uqhm
This was referenced Aug 10, 2026
oleeskild
added a commit
that referenced
this pull request
Aug 11, 2026
The resolveMdLinks filter added in 1.83.0 (#398) sent every dataview-generated link to /404, two defects compounding: - convertMdHrefs' anchor regex matched the tail of data-href=", so dataviewjs anchors (<a data-href="Folder/Note.md" href=...>) had their data-href clobbered to /404 before the dataview-js-links transform could resolve the anchor from it. The regex now requires href to be a standalone attribute. - resolveVaultPath treated vault-root targets (Folder/Note.md, as dataview and Obsidian's "absolute path in vault" setting emit) as note-relative, so links from nested notes resolved to paths that don't exist. Targets now yield ordered candidate interpretations, note-relative first, vault-root as fallback, and the filter picks the first that resolves to a real note. Dead links keep the /404 + is-unresolved handling. Verified with unit tests (TDD, 6 new failing tests before the fix) and an end-to-end build of the test garden covering dataviewjs anchors, vault-absolute and relative .md links. Fixes #399 Co-authored-by: Ole Eskild Steensen <6201338+oleeskild@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Gardens whose notes use plain markdown links (
[X](../concepts/x.md)) instead of wikilinks end up with broken links and an empty graph:convertLinksToFullPath, thelinkfilter,link_openrule) only handles[[wikilinks]], so relative.mdhrefs reach the published HTML untouched.../concepts/x.mdone directory too deep:/wiki/concepts/concepts/x.md→ 404 (reported by a user with exactly this duplicated segment).extractLinksonly matches wikilinks and root-absolute hrefs, so the graph shows isolated dots with no edges and backlinks are empty.Fix
src/helpers/linkUtils.jsresolveVaultPath(target, sourceDir): resolves relative/root-anchored link targets against the note's vault directory; rejects external schemes and paths escaping the vault.convertMdHrefs(html, sourceDir, resolveAnchor): rewrites.mdhrefs in rendered HTML, preserving fragments.extractLinks(content, sourcePath): now also extracts markdown-style.mdlinks (image embeds excluded) resolved to vault stems, so the graph and backlinks pick them up..eleventy.js— newresolveMdLinksfilter that derives the note's vault directory from itsinputPathand reusesgetAnchorAttributes, so unresolved targets get the same/404handling as dead wikilinks. Accepts an explicit input path for looped contexts.note.njk/index.njk/feed.njk: apply the filter; the feed passesnote.inputPathexplicitly sincethis.pagethere is the feed template, not the note.