Skip to content

Convert ButtonLinkDispatchTrait into a ButtonLinkDispatcher collaborator (#242) - #1317

Merged
chubes4 merged 1 commit into
trunkfrom
refactor/242-button-link-dispatch
Aug 28, 2026
Merged

Convert ButtonLinkDispatchTrait into a ButtonLinkDispatcher collaborator (#242)#1317
chubes4 merged 1 commit into
trunkfrom
refactor/242-button-link-dispatch

Conversation

@chubes4

@chubes4 chubes4 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Slice 5 for #242, workstream 1. Follows #1310, #1312, #1315, #1316.

Second trait eliminated, same shape as #1316.

What changed

ButtonLinkDispatchTraitButtonLinkDispatcher behind a 15-operation ButtonLinkDispatchContext. All call sites migrated, trait deleted — no forwarding shims.

POSITIONED_FRAGMENT_LINK_CARRIER_CLASS moves from HtmlTransformer onto 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

385 fixtures — DIFFERING: 0 — threw: 0

composer test exit 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 className is dropped entirely rather than emitted empty.

Also covered:

  • a runtime-targeted anchor is preserved and skips pattern recognition entirely (asserted by proving the recognizer is never called, not just by the returned block)
  • a runtime-targeted button additionally records a control island
  • an icon-only anchor survives on aria-label + safe href, but drops when the href is javascript:
  • positioned-fragment-link carrier class applies only when position is absolute/fixed, and never when role="button" makes the anchor a control
  • dispatch precedence: a linked logo wins over pattern recognition

Impact

trunk after
HtmlTransformer.php 12,650 12,684
single-consumer trait lines 8,079 7,960

HtmlTransformer.php grows 34 lines again — the context factory costs more than the use statement. 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).

ElementConversionTrait is 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 serializedBlocks and fallback counts across 385 fixtures, and wrote the isolation test. Reviewed by a human before opening.

…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.
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