Skip to content

doc: backslashes in code blocks rendered as URL-encoded sequences on docs site #8792

@hyf0-agent

Description

@hyf0-agent

Description

Backslashes inside fenced code blocks in packages/rolldown/src/options/docs/*.md files are rendered as URL-encoded sequences (%5C) on rolldown.rs.

Example: rolldown.rs/reference/InputOptions.external

The regex example:

// Source (.md file)
external: /^[^./](?!:\\)/,

// Rendered on site
external: /^[^./](?!:%5C%5C)/,

%5B = [, %5C = \, %5D = ] — the characters are being URL-encoded instead of rendered literally.

Originally reported by @bddjr in #8780 (comment).

Root Cause

The docs flow is:

  1. external.md contains correct markdown with fenced code blocks
  2. {@include ./docs/external.md} injects the content into a JSDoc comment in input-options.ts
  3. TypeDoc's comment parser processes the injected content as JSDoc markdown, including the contents of fenced code blocks — backslashes get treated as escape sequences
  4. extract-options-plugin.ts extracts the (already mangled) content
  5. VitePress renders the mangled output

The issue is that TypeDoc's {@include} does not preserve code block boundaries when processing escape sequences in its block lexer (see blockLexer.ts — it handles \{, \}, \@, \/, \` as escape pairs).

Why codeSplitting docs are not affected: The regex [\\/] in output-code-splitting-example.md survives because \/ is a recognized escape pair that resolves to / — which happens to be correct. But \\ followed by ] does not match any escape pair, so it goes through a different path and gets URL-encoded.

Possible Fixes

  1. Best: bypass TypeDoc for doc contentextract-options-plugin.ts already knows which property maps to which docs/*.md file. Instead of extracting the content from TypeDoc's processed output, read the original .md file directly and splice it in. This avoids the TypeDoc parser entirely.

  2. Upstream: fix TypeDoc{@include} should skip escape processing inside fenced code blocks. Correct but depends on TypeDoc team.

  3. Workaround: post-process URL decoding — Add section.replace(/%5B/g, "[").replace(/%5C/g, "\\").replace(/%5D/g, "]") in extract-options-plugin.ts. Quick but fragile.

Affected Pages

Any docs/*.md file with backslashes in code blocks that is {@include}'d into a JSDoc comment. Currently:

  • external.md — regex with \\

Metadata

Metadata

Assignees

No one assigned

    Type

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions