Skip to content

Release 5.2.0 - #10

Merged
micschk merged 20 commits into
mainfrom
night-fixes
Oct 11, 2026
Merged

micschk merged 20 commits into
mainfrom
night-fixes

Conversation

@micschk

@micschk micschk commented Oct 11, 2026

Copy link
Copy Markdown
Member

See CHANGELOG.md.

micschk added 20 commits October 8, 2026 13:11
…h6/pre/address/dt/summary (#9)

Option (b) from #9, chosen by mic for 5.1.1. A block shortcode closes inline ancestors and the
nearest block element only if that element cannot hold block content. div, li, td, dd,
blockquote, section and other containers are left whole on any number of lines, so list items and
table cells around a block shortcode are no longer deleted or split. This also changes the 5.1.0
result for a one-line <div>[sc]</div>: the div is now kept (README + CHANGELOG).

The #9 test rows now assert this behaviour (was an incomplete test), plus browser rows.
CHANGELOG 5.1.1 dated 2026-10-11.
`<a title="a>b" href="/x">x [sc] y</a>` was cut at `a>`, so the reopened copy of the link pulled
the following text into its title attribute. A tag now runs to the first '>' outside a quoted
value (double or single quotes), with possessive quantifiers so an unterminated quote fails the
tag instead of backtracking. Found by the verifier pass; 5.1.0 did not have this.
)

WHATWG HTML Living Standard, content models: dt is "Flow content, but with no header, footer,
sectioning content, or heading content descendants" (4.4.10); address is "Flow content, but with
no heading content descendants, no sectioning content descendants, and no header, footer, or
address element descendants" (4.3.10). Both can hold a <div>, and closing a <dt> put the block
output directly inside the <dl>. They are now containers like dd and li. p, h1-h6, pre (phrasing
content) and summary (phrasing content, optionally with headings) are still closed.
Decision by mic on the verifier pass.
…d= text in other values (#8)

The id/name strip matched `\s+id=` anywhere in the tag, so title=" id=1" lost its value and
title="see id=" href="/x" was merged into one broken attribute. The tag is now walked with the
same quote-aware alternation as the tag match: quoted values are consumed whole, and only a real
id (or a link's name) attribute is dropped. Found by the verifier pass.
…pth at 10 (#8)

Two shapes were not linear (verifier pass):
- every stray closing tag scanned the whole open-element stack (20000 open divs and 20000 stray
  closers: 6 s). A per-name open count makes a stray closer O(1).
- every shortcode closed and reopened every inline ancestor, so the output grew with depth x
  shortcodes (1600 nested spans and 1600 shortcodes: 43 KB in, 59 MB out). Past 10 inline
  ancestors (MAX_INLINE_DEPTH) the shortcode is now left in place.
Perf rows and a depth test added; README and CHANGELOG note the limit.
The tag walk tokenised every page, also pages without any block shortcode: a 3 MB page peaked at
~45 MB against ~5 MB for the 5.1.0 regex. One cheap preg_match for the configured tags now
returns early. Memory test (PHP 8.2+, skipped on 8.1: needs memory_reset_peak_usage()).
…has attributes (#8)

After a shortcode the parent is reopened bare (<p>), but the open-element stack still held the
original <p class="lead">, so the empty-element check for a following shortcode did not match and
left <p></p> (or <p> </p>) between the two. The stack entry now takes the reopened tag.
Found by the verifier pass.
…gs to reopen exceed 1 KB (#8)

Each reopened inline element repeats its whole opening tag, so a long tag around many shortcodes
grew the output with tag length x shortcodes (a 20 KB title around 1000 shortcodes: 31 KB in,
20 MB out). Past MAX_REOPEN_LENGTH (1 KB of inline opening tags) the shortcode is left in place,
as for MAX_INLINE_DEPTH. Test, README and CHANGELOG note. Decision by the coordinator on the
verifier pass.
…r row (#8)

The absolute limit goes from 1.5 s to 5 s so a slow CI runner does not flake it, and each row now
also checks its exact output, so the nested-spans row catches the inline caps being removed by
its output (59 MB instead of 43 KB) rather than by time. The stray-closer row is 30000 (15.7 s
with the stack scan back, 5 s limit): a purely quadratic regression leaves the output unchanged,
so time stays the guard there.
The quote-aware tag pattern let a quoted value or the unquoted run cross a '<', so every
'<a href="x ' in a run of unclosed tags scanned on to the end of the content (80000 of them:
24.8 s; 5.1.0: 0 s). '<' is now excluded from both (verifier's pattern), so such a tag is plain
text, as in 5.1.0; HTMLValue writes a raw '<' in a value as &lt; anyway. Timing rows with output
checks for '<a href="x ', "<a '", '<a "' and '<a ' x 20000 (the old pattern fails their output)
and '<a href="x ' x 60000 without any '>' (old pattern 13.8 s against the 5 s limit).
…ll reopened (#8)

An Outlook safelinks href is about 1.1 KB, so the 1 KB MAX_REOPEN_LENGTH left a block shortcode
inside such a link untouched. The cap is now 8 KB. Tests: a 1.1 KB safelinks-style href is
reopened, a tag just under 8 KB is reopened, one just over is left as it was. README and
CHANGELOG updated, including the "linear" sentence (reopened markup per shortcode is bounded).
@micschk
micschk merged commit bbb9368 into main Oct 11, 2026
9 checks passed
@micschk
micschk deleted the night-fixes branch October 11, 2026 15:48
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.

1 participant