Bundle of seven correctness fixes surfaced by an independent ultrareview of 2.2.4. Semver-patch — no public API changes. Behavior changes are limited to outputs that were previously buggy: collision overwrites, mangled fenced code, silent broken images, dropped Tabs blocks, malformed-hash crashes, and the auto-closing dropdown.
Fixed
intro.mdcollision onslug: '/'routes — sites with bothdocs/intro.mdand a doc routed to/docs/had their build output collide onintro.md, with the second route silently overwriting the first. Trailing-slash routes now resolve toindex.md.- Code fences corrupted by MDX/Docusaurus transforms — docs demonstrating Docusaurus syntax inside fenced code blocks had imports stripped and
<Tabs>rewritten right out of their own examples. Added a fence-aware protection pass that handles backtick and tilde fences (length ≥ 3, ≤3 leading spaces, supports CRLF and unclosed fences), and supports legitimate<Tabs>blocks containing fenced code. - Image dirs only copied to the first route's destination — sibling docs in the same source dir routed to different URL spaces had silent broken images. Switched to
Map<src, Set<dest>>so each source dir is copied to every destination it serves. <TabItem>and YouTube iframe regexes rejected valid attribute orders — reverse-order TabItems silently emptied the entire<Tabs>block; reverse-order YouTube iframes survived as raw HTML. Both now parse attrs independently with single- or double-quote support.- Multi-line and side-effect imports now stripped (
.*?couldn't cross newlines,import './x.css';wasn't matched). - Component scrubber now backreferences the opening tag so siblings like
<Outer><Inner>x</Inner></Outer>no longer leave an orphan</Outer>. (Deeply nested same-name components remain a known regex limitation.) <details>allows attributes on the opening tag and mixed-content summaries; body cleanup only trims outer blank padding so 4-space indents and intentional blank lines survive.Root.jsdecodeURIComponentcrash — malformed hashes like#%foono longer crash the scroll-to-anchor effect.Root.jsscroll-to-anchor timer/listener leaks — quickly clicking different hash links no longer piles up timers that could scroll the page out from under the user.- Dropdown copy-reset timer no longer auto-closes the menu or leaks on unmount.
Internal
- Added a
node --testsuite (zero new dependencies). Run withnpm test. - Extracted
cleanMarkdownForDisplay, fence protection, image mapping, URL building, and hash decoding into focusedlib/modules for testability.
PR: #9