Contrib compatibility: process only Canvas JSON Schema `$ref`s in SDCs
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3550169. --> Reported by: [pdureau](https://www.drupal.org/user/1903334) Related to !188 >>> <h3 id="overview">Overview</h3> <p>Canvas is using JSON Schema references. Example:<br> <code>{$ref: 'json-schema-definitions://canvas.module/image'}</code></p> <p>They are resolved by <a href="https://git.drupalcode.org/project/canvas/-/blob/1.x/src/JsonSchemaDefinitionsStreamwrapper.php">JsonSchemaDefinitionsStreamwrapper</a> which is looking fine:</p> <pre>&nbsp; Drupal\canvas\JsonSchemaDefinitionsStreamwrapper:<br>&nbsp;&nbsp;&nbsp; public: true<br>&nbsp;&nbsp;&nbsp; tags:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - { name: stream_wrapper, scheme: json-schema-definitions }</pre><p>So it seems just letting the StreamWrapper do its job is enough. However, at a few places in Canvas code, the stream wrapper is replaced/overriden by a direct call to <code>json_decode()</code>.</p> <p>AdapterBase::resolveSchemaReferences():</p> <pre>&nbsp;&nbsp;&nbsp; if (isset($schema['$ref'])) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $schema = json_decode(file_get_contents($schema['$ref']) ?: '{}', TRUE);<br>&nbsp;&nbsp;&nbsp; }</pre><p>PropShape::resolveSchemaReferences():</p> <pre>&nbsp;&nbsp;&nbsp; if (isset($schema['$ref'])) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $schema = json_decode(file_get_contents($schema['$ref']) ?: '{}', TRUE);<br>&nbsp;&nbsp;&nbsp; }</pre><p>JsonSchemaFieldInstanceMatcher::resolveSchemaReferences():</p> <pre>&nbsp;&nbsp;&nbsp; if (isset($schema['$ref'])) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $schema = json_decode(file_get_contents($schema['$ref']) ?: '{}', TRUE);<br>&nbsp;&nbsp;&nbsp; }</pre><p>JsonSchemaObject::__construct():</p> <pre>&nbsp;&nbsp;&nbsp; $schema = \json_decode(\file_get_contents($ref) ?: '{}', TRUE, \JSON_THROW_ON_ERROR);</pre><p> and:</p> <pre>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (\array_key_exists('$ref', $detail)) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $prop_schema = \json_decode(\file_get_contents($detail['$ref']) ?: '{}', TRUE, \JSON_THROW_ON_ERROR);</pre><p>Maybe more...</p> <p>This is error prone for Canvas and this is breaking <strong>all</strong> other uses of JSON Schema references in SDC. The ones from <a href="https://www.drupal.org/project/ui_patterns">UI Patterns</a>, the module I am maintaining, but also any other a Drupaler may use (including the ones defined outside the Drupal ecosystem).</p> <h3 id="proposed-resolution">Proposed resolution</h3> <p>My knowledge of Canvas is not deep enough to propose a fix for the root causes (see "Follow-up"), but let's try a quick "damage control" fix:</p> <ol> <li>Some little changes to not block other SDC plugin managers decorators (necessary to test concurrent reference resolvers).</li> <li>Add a reference resolver in the component plugin manager (without resolving <code>json-schema-definitions://</code> until <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3515074" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3515074</a></span> is OK)</li> <li>Limit <code> json_decode(file_get_contents($schema['$ref']) </code> execution to <code>json-schema-definitions://</code> URI, to prevent the break of non Canvas JSON Schema references. </li> </ol> <h3>Follow-ups</h3> <p>To do once this first fix is merged:</p> <ol> <li>The root cause of "Don't block other SDC plugin managers decorators": It seems Canvas's ComponentPluginManager decorator is doing inheritance over composition, so it doesn't chain properly. Issue to be created.</li> <li>The root cause of the JSON schema issue: Remove all <code>json_decode(file_get_contents($schema['$ref'])</code>. <code>JsonSchemaDefinitionsStreamwrapper</code> is already executing <code>file_get_contents</code> and all parts of the Canvas app must work on the resolved JSON schema returned by this service.</li> <li>A related, but orthogonal, issue about JSON Schema references: <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3515074" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3515074</a></span></li> </ol> <p>Also, there are some weird stuff about JSON Schema management:</p> <ul> <li><code>Prop "XXX" is of type "object" without a $ref, which is not supported</code>: the schema retrieved from <code>$ref</code> will be merged with the existing schema, so it is common to never have a <code>type</code> property alongside a <code>$ref</code>.</li> <li><code>Prop "XXX" is required, but does not have example value</code>: this seems to be the role of the <code>default</code> property, no the <code>examples</code> property</li> <li><code>Component has no props schema</code>: "Canvas always requires schema, even for theme components" which don't fit with the real world where many components have only slots.</li> <li>...</li> </ul> <h3 id="ui-changes">User interface changes</h3> <p>None.</p> > Related issue: [Issue #3352063](https://www.drupal.org/node/3352063)
issue