Add infrastructure to support finding commonalities in a set of scalar prop expressions
## Overview #3585354 introduced ~650 lines of generic infrastructure for combining ("folding") sets of scalar `PropExpression`s. Two cases are handled: expressions that overlap at the field-item (delta) point but target different field properties (folded into `FieldObjectPropsExpression`), and expressions that overlap at the reference point but target different bundles (folded into `ReferencedBundleSpecificBranches`). Without this folding, the payload passed to `content-entity-reference` props is shaped in a way that gives code-component developers a poor DX. This infrastructure is independent of `JavaScriptComponent` (its only current caller) and naturally belongs in `Drupal\canvas\PropExpressions\StructuredData`, next to `Evaluator` and `Labeler`. Per Wim's review of !1112 (notes 939464 and 939546 §B.2), keeping the folding logic inside `JavaScriptComponent` inflates that config entity class by ~50% (~400 net new LoC, for a problem domain not strictly tied to the entity) and leaves the logic without a unit-test surface — it is currently only exercised end-to-end. Lifting it into a dedicated class lets #3585354 land in a substantially smaller, easier-to-review form and gives the folding logic proper unit coverage. ## Proposed resolution Extract the following from the !1112 branch into a dedicated MR that can land independently and quickly: 1. **New method** `::withFinalTargetReplaced()` on the relevant `PropExpression` value object(s) — clones an expression while swapping its leaf. 2. **Refactor** `hasSameStartingPointAs()` → `getStartingPointKey()`, so callers can group expressions by starting point without N×N pairwise comparisons. 3. **New class** in `Drupal\canvas\PropExpressions\StructuredData\` — name TBD; Wim suggested `Consolidator`, `Coalescer`, `Synthesizer`, or (since the input is `ScalarPropExpressionInterface` leaves and the output is non-scalar) `Descaler`. Responsibilities: - Take a set of `EntityFieldBasedPropExpressionInterface` instances whose leaves are all `ScalarPropExpressionInterface`. - Identify expressions that overlap at the field-item (delta) point but point to different properties → combine using `FieldObjectPropsExpression`. - Identify expressions that overlap at the reference point but point to different target bundles → combine using `ReferencedBundleSpecificBranches`. 4. **Unit-test coverage** for the new class — the equivalent logic in !1112 currently has only E2E coverage, which will be hard to maintain. 5. **Kernel-test coverage** for `Evaluator`'s multi-bundle branching including the `is_required: true` case. This gap was flagged on !1112 (notes 939465/939466), with a suggestion to defer it to #3563309 (note 939484). Closing it here instead avoids landing a behavior change without a regression test, and keeps #3563309 focused on its actual scope. Commit message (per Wim's suggestion): `feat(Data model): Infrastructure to support finding commonalities in a set of scalar prop expressions`. ## UI changes None — pure data-model infrastructure refactor.
issue