0.6.0 — wikilinks stop needing a hand-written resolver
Describe your vault's paths as config and wikilinks resolve themselves, including bare ones, and ambiguous links refuse to guess.
[!note] Written after the fact 0.6.0 went to JSR on 2026-09-08 with no git tag, GitHub release, or release notes. These notes, the
v0.6.0tag and the GitHub release were added on 2026-11-01, written from the commit history and two changelog entries. A comparison of the 29 published files confirms they match commit66790f6, ignoring the import paths JSR rewrites at publish.
Why Care?
remarkLfmWikilinks has always asked each site for a resolver function, because where a wikilink goes is a per-site decision. In practice, four sites each wrote the same chain of startsWith branches by hand, and anything those branches missed silently became plain text.
That missed a lot. 26.7% of the wikilinks in the Lossless vault have no folder at all, like [[DevOps]], and no prefix rule can ever match those.
With 0.6.0, you describe your paths as config and the package does the rest. It’s opt-in, so nothing changes if you leave it out.
What’s New?
Added
createPathResolverandslugifyPath, exported from the root and from a new./resolve-pathsubpath.- A
pathsoption on wikilinks, taking either the config object or a built resolver. scripts/measure-vault.mjs, which regenerates every corpus number quoted in the README.scripts/publish-jsr.sh, which runsdeno publishdirectly on machines where thejsrCLI’s bundled binary can’t start, such as NixOS.
Changed
lfm:publishno longer stops if GitHub Packages fails. Sites install from JSR, so a failed mirror shouldn’t block the release.- CI now runs the test suite on push and pull request and dry-runs the JSR publish. Dependabot keeps the GitHub Actions current.
- The splash demos became real Markdown files, checked by
test/demo-fixtures.test.mjs, and every diagram handler now has a worked example.
Using it
parseMarkdown(content, {
wikilinks: {
paths: {
index: vaultPaths,
routes: [
{ match: ['concepts', 'vocabulary', 'organizations', 'sources'],
to: 'https://www.lossless.group/more-about/{slug}' },
{ match: 'tooling', to: '/tools/{slug}' },
],
},
},
});
A hand-written resolver still works, and wins if both are given.
How it resolves
Each result reports which tier answered, so a site can trust exact hits and audit the rest:
| Tier | Matches |
|---|---|
exact | The full path as written |
suffix | The end of a path in the index |
basename | The file name alone, which is how bare [[Page]] links resolve |
route | A routing rule, when the index has no answer |
An ambiguous match stops there. It doesn’t fall through to the next tier. It records a diagnostic and renders as plain text, because a link that’s wrong without anyone noticing is worse than no link. Writing the tests caught a real bug here: ambiguous results were reaching the route tier, so a site with a * catch-all would have emitted a confidently wrong link. Sites that prefer otherwise can set onAmbiguous.
The numbers, and a correction
The design was argued from measurements of the Lossless vault, and the first table couldn’t be reproduced because its scripts were never committed. It also counted ![[embeds]] as links. We committed the script and re-derived everything before release:
| First claimed | Re-derived | |
|---|---|---|
| Navigational wikilinks | 13,846 | 13,556 |
| Wikilinks with no folder | 28% | 26.7% |
| Files with a unique basename | 98.4% | 97.0% |
| Bare links hitting a collision | 0.7% | 0.5% |
| Exact hits among pathed links | 89.8% | 91.7% |
| Cost per link | 5.09 µs | 7.65 µs |
Every conclusion survived. Resolving the whole vault still takes about 104 ms, because the index is built once and each lookup uses Maps rather than scanning. With four routes and no catch-all, 79.2% of links resolve.
Upgrading
pnpm add jsr:@lossless-group/lfm@^0.6.0
Purely additive. To adopt it, swap your hand-written resolver for paths.
Known gaps
- The resolver wasn’t human-reviewed at release. As of the 2026-09-08 changelog entry, no person had read the 806 lines of
resolve-path.ts. It has 39 test assertions and was measured against the real vault. We have no later record of a review. - GitHub Packages missed this release at the time. The mirror stopped at 0.4.1 until 2026-11-01, when 0.3.0, 0.5.0, 0.5.1, 0.6.0 and 0.6.1 were published to it from commits verified against JSR.
See also
changelog/2026-08-23_01.md: the feature, with its original numbers and a correction notechangelog/2026-09-08_01.md: why the numbers movedcontext-v/specs/Maintain-Path-Resolution-for-Wikilinks.md: the design recordchangelog/releases/0.6.1.md: the next release