Convert ButtonLinkDispatchTrait into a ButtonLinkDispatcher collaborator (#242) - #1317
Merged
Conversation
…tor (#242) Anchor and button dispatch now runs against an explicit ButtonLinkDispatchContext. All call sites were migrated, so the trait is deleted rather than hollowed out. POSITIONED_FRAGMENT_LINK_CARRIER_CLASS moves onto the dispatcher, which owns the rule that writes it; the transformer reads it back from there when inspecting serialized output.
This was referenced Aug 28, 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.
Slice 5 for #242, workstream 1. Follows #1310, #1312, #1315, #1316.
Second trait eliminated, same shape as #1316.
What changed
ButtonLinkDispatchTrait→ButtonLinkDispatcherbehind a 15-operationButtonLinkDispatchContext. All call sites migrated, trait deleted — no forwarding shims.POSITIONED_FRAGMENT_LINK_CARRIER_CLASSmoves fromHtmlTransformeronto the dispatcher. The dispatcher owns the rule that writes that class; the transformer reads it back when inspecting serialized output, so ownership now sits with the writer rather than the reader.Two internal helpers (
nonButtonAnchorWrapperAttributes,isPositionedFragmentLink) became genuinely private — they were only ever called from within the trait, but as trait members they were part of the transformer's method surface.Behavior preservation
composer testexit 0.Coverage
tests/unit/button-link-dispatcher.php— 15 assertions, constructs no transformer.The rule worth having a direct test for is the anchor class-identity split: source classes belong exclusively to the saved link, and only generated geometry classes may ride the paragraph host. Previously observable only by transforming a document and reading serialized output. Now asserted directly, including the edge case where everything mapped was a source class and
classNameis dropped entirely rather than emitted empty.Also covered:
aria-label+ safe href, but drops when the href isjavascript:absolute/fixed, and never whenrole="button"makes the anchor a controlImpact
HtmlTransformer.phpHtmlTransformer.phpgrows 34 lines again — the context factory costs more than theusestatement. Consistent with the previous slices and still not the metric.Cumulative across five slices:
convertElement()441 → 301, 13 collaborator files, 147 isolation assertions, two traits eliminated.Scope
Five single-consumer traits remain:
StyleResolutionTrait(2,822),FormDispatchTrait(1,865),NavigationStyleProjectionTrait(1,319),SvgMaterializationTrait(983),NavigationToggleSuppressionTrait(781),ElementConversionTrait(594).ElementConversionTraitis the natural next one: smallest remaining, and its dependency on the runtime-island analyzer is already migrated by #1316.AI assistance disclosure: implemented and drafted by Claude Sonnet 4.6 running in Claude Code, operated by @chubes4. The AI captured the pre-change corpus baseline, converted the trait, migrated all call sites, verified byte-identical
serializedBlocksand fallback counts across 385 fixtures, and wrote the isolation test. Reviewed by a human before opening.