fix(converter): escape literal fence-like prose so it cannot capture code blocks - #269
Merged
Merged
Conversation
…code blocks A prose line starting with 3+ backticks was indistinguishable from a fence the converter emitted. splitOnFences paired it with the next real fence, so the real code body fell outside the fence and went through whitespace cleanup, silently changing the code. This affected both html → markdown and storage → markdown (the read path). Escape the first backtick of a line-leading run in prose (``` becomes \```) in both converters, through one shared helper. Code bodies, code spans, attribute values and mid-line runs are left alone, and backtick entities in html prose are decoded first so they cannot reintroduce a literal fence. The escaped text also round-trips as prose instead of turning into a code block on write-back. Fixes #254
- Escape every backtick of the leading run, not just the first, so the rest cannot pair with later backticks into a code span on write-back. - Treat NBSP (literal, ,  ,  ) as indentation before the run, in both converters. - Only treat `<` followed by a letter, `/` or `!` as a tag in html → markdown, so prose like `a < b` no longer hides a fence line. - Skip the <pre>/<code> region patterns when no closing tag exists, which removes a quadratic rescan on unclosed <pre>. - Document that text starting at an inline-element boundary counts as a line start.
|
🎉 This PR is included in version 2.27.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A prose line that starts with three or more backticks is indistinguishable from a fence the converter emitted itself.
splitOnFencespairs it with the next real fence, so the real code body falls outside the fence and goes through whitespace cleanup. The code is changed silently.This affects both converters. Besides html → markdown (
convert --input-format html, reported in #254), storage → markdown is affected too, which is thereadpath: a<p>```</p>followed by acodemacro loses the indentation of the code body.Changes
escapeFenceLikeText()inlib/markdown-cleanup.js. It backslash-escapes every backtick of a line-leading run of 3+ backticks in prose (```becomes\`\`\`). Escaping only the first would leave the rest free to pair with later backticks into a code span on write-back. NBSP (literal or as an entity) counts as indentation before the run.StorageWalker.renderText(), except inside code spans and link labels (which already escape backticks).<pre>and<code>regions and tag attributes are left alone. Backtick entities (`,`) in prose are decoded first, because the entity pass runs after the fence-aware cleanup and would otherwise bring back a literal fence line. Only<followed by a letter,/or!is treated as a tag (so prose likea < bis not skipped), and the<pre>/<code>region patterns are used only when a closing tag exists, which avoids a quadratic rescan on unclosed<pre>.Output change
A literal fence-like line in prose is now written as
\`\`\`instead of```. The old output turned into a real code block when written back to Confluence; the escaped form round-trips as prose. Five existing expectations that pinned the unescaped output (#243, #244) were updated to the escaped form. One of them has loose text directly after a callout paragraph with no blank line, which Markdown treats as a continuation of that paragraph, so its write-back assertion now expects that.Testing
<br>before the literal, backtick entities and CDATA, a callout, and round-trip. Also checks that code bodies, code spans, mid-line runs and attribute values are untouched.npm test(40 suites, 1578 tests) andeslintpass.Fixes #254