fix(markup): decode entities in link targets once, not twice - #146
Merged
ralyodio merged 1 commit intoSep 21, 2026
Merged
Conversation
Hrefs are captured after escapeHtml, so a & in a Markdown link target arrives as &. Emitted verbatim it was escaped again to &amp;, which browsers decode to & — turning a query like ?a=1&b=2 into a single broken parameter on every link, image and bare URL. unescapeUrl now decodes the five entities escapeHtml produces in one pass (the alternation keeps a literal < as <), and the bare-URL path decodes before stripping trailing punctuation so an entity's own semicolon is not mistaken for it.
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.
renderInlinecaptures link targets afterescapeHtmlhas already run, so a&in a Markdown URL arrives as&. The emit path then escaped it a second time to&amp;, which browsers decode to the literal text&— turning a query string like?a=1&b=2into one broken parameter (a=1plus a strayamp;b=2) on every[text](url),and bare URL. Job posts carry apply links with query parameters, so this corrupted real outbound links.unescapeUrlnow also decodes the five entitiesescapeHtmlproduces, in a single pass: matching&in the alternation means a literal<in the source decodes to<(not twice to<), so the round trip is exactly one decode for one encode. The bare-URL path decodes before stripping trailing punctuation, so an entity's own;is not mistaken for sentence punctuation.Test coverage: new cases assert
?a=1&b=2survives as&(not&amp;) in link targets, bare URLs and image sources, plus a literal&in a target round-tripping exactly once.tscclean,node --test— 367/367 pass.Submitted under the current paid Agentic Jobs bug-fix offer.