Files

Turndown differential tests

Reference: mixmark-io/turndown, revision aa84dfa3e2361edea8c43acbfc2b7a9363494bfd, package version 7.2.4, using @mixmark-io/domino 2.2.0.

cases.json contains all 147 HTML fixtures from upstream test/index.html, plus the 50 independently written cases in additional.json. The upstream fixtures retain their MIT license in LICENSE. Production Rust code does not include the upstream JavaScript implementation.

What is compared

Turndown is configured to match Moli's ATX headings, dash bullets, star emphasis, fenced code, inline links, and horizontal rules. Per-case style-only options (such as referenced links or tilde fences) are normalized to this configuration. The semantic preformattedCode option is preserved and tested against Moli's preformatted_code option. This corpus tests conversion behavior, not Turndown's JavaScript plugin API or every output-style option.

Each case parses the source HTML through an independent test DOM implementing Dom, converts it, and checks that the DOM is unchanged. Both Markdown outputs are rendered with pulldown-cmark, then their HTML is compared exactly. This accepts equivalent delimiter choices and list indentation while detecting lost text, incorrect links, changed paragraph/list structure, and visible delimiters. There are also exact Markdown assertions in the original and regression suites.

expectations.json documents 12 deliberate differences with exact Moli outputs. These preserve bare pre blocks and avoid upstream losses of literal characters, emphasis, whitespace, and list boundaries. They remain active assertions; no case is skipped. A reference change that makes a difference obsolete also fails the test. Separate converter tests cover GFM tables and strikethrough as Moli extensions. Explicit table headers follow Turndown's GFM plugin; simple headerless tables receive empty headings. Complex tables retain the core's block expansion rather than the plugin's raw HTML fallback.

Findings tracked outside the reference corpus

The 12 exceptions above describe this corpus, not every design difference or every correctness issue. tracking.rs records these open review findings with active assertions of both Markdown and rendered HTML:

Tests Status Current behavior and comparison
track_nested_list_spacing_through_a_transparent_wrapper, track_nested_list_spacing_before_a_trailing_empty_element Open compatibility decision Moli keeps the outer list tight when an ins wraps the nested list or an empty span follows it. Turndown makes it loose. Both preserve the list items.
track_multiline_image_alt_becoming_a_heading Open bug, also present in Turndown An image alt containing first\n# heading breaks the image into text and a heading. The desired HTML retains the image and its full label.
track_multiline_link_title_becoming_a_heading Open bug, also present in Turndown A link title containing first\n# heading breaks the link into text and a heading. The desired HTML retains the link and its multiline title.
track_multiple_nested_spans_at_the_end_of_a_paragraph Open bug, also present in Turndown <em><strong>x</strong>b<strong>c</strong></em> produces ambiguous star delimiters at paragraph end, losing the second strong span and exposing literal stars.
track_mixed_emphasis_markers_at_an_intraword_opening Open bug in Moli's emphasis/strikethrough extension before<em><del><strong>x</strong></del></em> loses outer emphasis because its opener precedes generated punctuation.

These tests are not ignored or expected to panic. A change to a recorded output requires review; when fixing a bug, replace the current-output assertion with a regression asserting the desired semantics and remove its open entry here.

The inline-code br separator and nested-emphasis closing-delimiter fixes have independent semantic regressions in inline_boundaries.rs. Inline-code breaks follow Moli's whitespace mode (one space after collapsing), without copying the extra spaces from Turndown's Markdown hard-break syntax.

Regeneration

Normal Rust tests use the checked-in data and require neither Node nor network access. To update the reference intentionally:

git clone https://github.com/mixmark-io/turndown.git /tmp/moli-turndown/upstream
git -C /tmp/moli-turndown/upstream checkout aa84dfa3e2361edea8c43acbfc2b7a9363494bfd
npm install --prefix /tmp/moli-turndown --ignore-scripts --no-audit --no-fund @mixmark-io/domino@2.2.0
node moli-html2md/tests/turndown/generate.mjs /tmp/moli-turndown/upstream
cargo test -p moli-html2md

The generator executes the pinned upstream source. It adapts import extensions for Node's ESM loader and provides CommonJS require for Domino, without changing conversion rules. The corpus records both the upstream revision and normalized options. cases.rs provides a separate named Rust test for every fixture.