Repository navigation
MD-2768 Cut replaceRange with one callback - #43
Merged
benney merged 4 commits intoNov 6, 2026
Merged
Conversation
🦋 Changeset detectedLatest commit: a64457d The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
benney
force-pushed
the
feature/md-2768-mos-proxy-cut-replacerange-with-one-callback
branch
from
November 5, 2026 11:10
3b5e01b to
230bd7f
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The optimization can produce malformed output through descendant marker matches and missed MathML containers, and can delete or reorder insertions from earlier components.
3 open issues
What changed in this PR
Optimizes surface-component range replacement with a two-pass wrapper approach, building on #42’s element-by-element fixes and retaining that path as a fallback.
Changes:
- Buffers eligible responses and removes wrapped ranges with one callback.
- Requires
removeAndKeepContentin rewriter adapters. - Adds equivalence, fallback, and seeded fuzz tests, plus a minor changeset.
| File | Description |
|---|---|
test/stages/wrappedRange.spec.ts |
Tests wrapper output, fallbacks, component interactions, and fuzz equivalence. |
test/stages/voidElements.spec.ts |
Keeps void-element tests on the element-by-element path. |
test/fakes/LolHtmlRewriter.ts |
Adds unwrapping support and handles responses without bodies. |
test/fakes/EndTagSpyRewriter.ts |
Extracts the reusable end-tag callback spy. |
src/stages/wrappedRange.ts |
Plans wrapper segments, fallback checks, and range removal. |
src/stages/surfaceComponents.ts |
Coordinates buffering, wrapper passes, and fallback. |
src/adapters/HtmlRewriterAdapter.ts |
Requires removeAndKeepContent on rewriter elements. |
.changeset/range-wrapper-cut.md |
Documents the optimization and adapter contract change. |
Review effort: Balanced
benney
force-pushed
the
feature/md-2768-mos-proxy-cut-replacerange-with-one-callback
branch
from
November 5, 2026 12:39
230bd7f to
2e2ebb0
Compare
benney
force-pushed
the
feature/md-2768-mos-proxy-cut-replacerange-with-one-callback
branch
2 times, most recently
from
November 5, 2026 16:34
3de0133 to
0e43518
Compare
Base automatically changed from
feature/md-3007-mos-proxy-fix-replacerange-edge-cases
to
main
November 6, 2026 09:14
Removing a range element by element costs a callback per element. Pass 1 now splits the container into keep and cut `<mos-range-*>` segments by inserting tags at the container's edges and next to the markers, and pass 2 unwraps the keep segments and drops the cut one with a single callback. The wrapper handlers run ahead of every other component, so what those insert lands outside the segments. The split only balances when both markers are direct children of the container. A nested marker or container, a marker removed by an earlier component, or a raw text container makes the wrapper report the page unsupported, and the page is redone element by element from a buffered copy. A seeded fuzz checks both paths give the same page. `RewriterElement.removeAndKeepContent` is now required; lol-html and HTMLRewriter elements already have it, so every adapter gets the cut. HTML comments inside the cut are now removed with it.
A marker selector with a combinator could match a grandchild through the direct-child selector, and a container selector list matched more than it should, so both now go straight to the element path. A component ahead of the range that inserts on the container, the start marker or inside the cut now sends the page to the element path, which places those inserts differently. The fuzz covers inserts from components on both sides of the range.
benney
force-pushed
the
feature/md-2768-mos-proxy-cut-replacerange-with-one-callback
branch
from
November 6, 2026 09:14
0e43518 to
99c5739
Compare
JFL110
approved these changes
Nov 6, 2026
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.


Stacked on #42.
When a range's markers are direct children of its container, pass 1 splits the container into keep and cut
<mos-range-*>segments and pass 2 drops the cut segment with one callback, instead of one callback per element. Other shapes (nested markers or containers, a marker removed by another component, raw text containers such astextarea) are redone element by element from a buffered copy. A seeded fuzz checks both paths give the same page.RewriterElement.removeAndKeepContentis now requiredMinor changeset.