Add HostEntityPropSource so content-entity-reference props can resolve to the rendering host entity
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3587374. --> Reported by: [penyaskito](https://www.drupal.org/user/959536) Related to !1060 >>> <h3 id="overview">Overview</h3> <p>When a Canvas <code>JavaScriptComponent</code> is placed on an entity-render page (a node, page, etc.), an editor configuring an entity-reference prop on that component has only two ways to populate it after <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3586613" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3586613</a></span> (merged 2026-05-12):</p> <ul> <li>Statically pick a specific entity via autocomplete (<code>StaticPropSource</code>).</li> <li>Link to an entity-reference field on the host entity (<code>EntityFieldPropSource</code>, established in <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-13"><a href="https://www.drupal.org/project/drupal/issues/3031367" title="Status: Needs work">#3031367: Generate JSON schema for content entity types</a></span>).</li> </ul> <p>The very common intent "use this page's entity itself" &mdash; i.e. pass the host node/page directly into the prop &mdash; has no representation: <code>HostEntityUrlPropSource</code> exists for the host entity's URL, but no sibling exists for the host entity object.</p> <p>This is the back-end follow-up to the entity-reference prop-shape work in <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3586613" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3586613</a></span>. The shape itself is usable without a host-entity source, so it has been lifted into this dedicated child of the META <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3573831" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3573831</a></span>.</p> <h3 id="proposed-resolution">Proposed resolution</h3> <p>Add a new <code>HostEntityPropSource</code> as the third valid source for entity-reference-shaped props, alongside <code>StaticPropSource</code> and <code>EntityFieldPropSource</code>. The change is purely additive.</p> <h4>New PropSource class and enum case</h4> <ul> <li>New <code>final</code> class <code>Drupal\canvas\PropSource\HostEntityPropSource</code> implementing the standard <code>PropSource</code> contract.</li> <li><code>evaluate(NULL, &hellip;)</code> always throws <code>MissingHostEntityException</code>; <code>evaluate($entity, &hellip;)</code> returns <code>new EvaluationResult($entity)</code>. The throw-from-evaluate contract is intentional &mdash; the generic <code>PropSource::parse()</code> + <code>$source-&gt;evaluate()</code> loop in <code>GeneratedFieldExplicitInputUxComponentSourceBase::getExplicitInput()</code> already wraps <code>evaluate()</code> in a try/catch that silently skips on this exception, which is what protects host-less render contexts (e.g. pattern previews). <code>JsComponent::getExplicitInput()</code> inherits the protection by calling <code>parent::getExplicitInput()</code> first.</li> <li>New enum case <code>PropSource::HostEntity = 'host-entity'</code>, plus the <code>getTypePrefix()</code> / <code>parse()</code> dispatch entries that route to the new class.</li> </ul> <h3 id="remaining-tasks">Remaining tasks</h3> <ul> <li>Add the <code>HostEntityPropSource</code> class and wire it into the <code>PropSource</code> enum. (Done &mdash; see <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-2"><a href="https://www.drupal.org/project/canvas/issues/3587374" title="Status: Fixed">#3587374: Add HostEntityPropSource so content-entity-reference props can resolve to the rendering host entity</a></span> MR !1060 draft scope.)</li> <li>Widen <code>LinkedPropSource</code> and <code>GeneratedFieldExplicitInputUxComponentSourceBase</code> to recognize the new class.</li> <li>Add a new <code>HostEntityPropSourceMatcher</code> class and inject it into <code>PropSourceSuggester</code> with a new <code>PropSource::HostEntity-&gt;value</code> bucket.</li> <li>Tests (all using programmatic <code>JavaScriptComponent::create([...])</code> fixtures &mdash; never SDC fixtures, since SDC content-entity-reference end-to-end support is not supported): focused <code>HostEntityPropSourceTest</code> (parse round-trip, evaluate semantics, label, dependencies); new <code>HostEntityPropSourceMatcherTest</code> covering the matcher's positive/negative bundle-gate logic; extend <code>PropSourceSuggesterTest</code> with integration coverage of the new bucket; extend <code>JavascriptComponentStorageTest</code> with one render against a real host and one host-less skip case.</li> <li>Update <code>docs/shape-matching.md</code> with a "Sources" subsection enumerating the three valid sources</li> </ul> > Related issue: [Issue #3586613](https://www.drupal.org/node/3586613) > Related issue: [Issue #3588438](https://www.drupal.org/node/3588438) > Related issue: [Issue #3573831](https://www.drupal.org/node/3573831)
issue