Skip to content

v1.59.2.0 fix(make-pdf): stop smartypants URL carve from swallowing the next placeholder (#2084)#2108

Open
genisis0x wants to merge 2 commits into
garrytan:mainfrom
genisis0x:fix/2084-smartypants-url-placeholder-leak
Open

v1.59.2.0 fix(make-pdf): stop smartypants URL carve from swallowing the next placeholder (#2084)#2108
genisis0x wants to merge 2 commits into
garrytan:mainfrom
genisis0x:fix/2084-smartypants-url-placeholder-leak

Conversation

@genisis0x

Copy link
Copy Markdown
Contributor

Closes #2084.

make-pdf generate mangled any bare/autolinked http(s):// URL into a literal SMARTPANTS_PRESERVED_<n> token and left an unclosed <a> that bled link-blue into every following block to the end of the document.

Root cause

make-pdf/src/smartypants.ts carves code/tags/URLs into U+0000-delimited placeholder tokens, transforms the remaining text, then restores the tokens. The URL pattern was /\bhttps?:\/\/\S+/g. \S matches non-whitespace, and the placeholder delimiter U+0000 is non-whitespace, so for an autolinked URL (<a href="URL">URL</a>) the link-text URL match greedily swallowed the trailing </a> placeholder. The nested placeholder never restored (the restore is a single left-to-right pass), so SMARTPANTS_PRESERVED_<n> leaked into the text and the </a> was dropped.

Fix

Exclude U+0000 from the URL character class ([^\s]+) so the URL match stops at the placeholder boundary. Real URLs never contain U+0000, so the match is identical to \S+ except that it no longer crosses a carve boundary.

Before / after on the issue's repro (via the real smartypants()):

  • before: <a href="https://example.com">https://example.com SMARTPANTS_PRESERVED_2 here. (leak, no </a>)
  • after: <a href="https://example.com">https://example.com</a> here.

Test

Added a regression test in make-pdf/test/render.test.ts (the existing smartypants block): an autolinked URL keeps its <a>...</a> intact and leaks no placeholder. Verified it fails on the old \S+ regex and passes on the fix. Full render.test.ts: 67 pass. Quotes, em dashes, ellipses, code/pre zones, and href-only URLs are unaffected.

@trunk-io

trunk-io Bot commented Jun 25, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

…aceholder (garrytan#2084)

The URL carve used \S+, which matches non-whitespace and so eats the
U+0000 sentinel of a following placeholder token. For an autolinked URL
(<a href=URL>URL</a>), the link-text URL swallowed the </a> placeholder,
nesting it so neither restored: a raw SMARTPANTS_PRESERVED_n token leaked
into the rendered text and the unclosed <a> bled link styling into every
later block. Exclude U+0000 from the URL character class so the match
stops at the placeholder boundary. Adds a regression test that fails on
the old greedy regex.
@genisis0x genisis0x force-pushed the fix/2084-smartypants-url-placeholder-leak branch from 973c629 to 28329d0 Compare June 26, 2026 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

make-pdf: bare/visible http(s):// URLs become SMARTPANTS_PRESERVED tokens and bleed link-blue into the rest of the doc

1 participant