← Changelog

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.0 tag 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 commit 66790f6, 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

  • createPathResolver and slugifyPath, exported from the root and from a new ./resolve-path subpath.
  • A paths option 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 runs deno publish directly on machines where the jsr CLI’s bundled binary can’t start, such as NixOS.

Changed

  • lfm:publish no 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:

TierMatches
exactThe full path as written
suffixThe end of a path in the index
basenameThe file name alone, which is how bare [[Page]] links resolve
routeA 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 claimedRe-derived
Navigational wikilinks13,84613,556
Wikilinks with no folder28%26.7%
Files with a unique basename98.4%97.0%
Bare links hitting a collision0.7%0.5%
Exact hits among pathed links89.8%91.7%
Cost per link5.09 µs7.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 note
  • changelog/2026-09-08_01.md: why the numbers moved
  • context-v/specs/Maintain-Path-Resolution-for-Wikilinks.md: the design record
  • changelog/releases/0.6.1.md: the next release