DefaultRelativeUrlPropSource does not sort properties keys for comparison
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3550165. -->
Reported by: [mglaman](https://www.drupal.org/user/2416470)
Related to !187
>>>
<h3 id="overview">Overview</h3>
<p>When using a code component with a prop of image or video you cannot publish a page using the default prop values. If you do, you get:</p>
<pre>Error 500: Extraneous JSON Schema information detected: { "properties": { "src": { "type": "string", "format": "uri-reference", "pattern": "^(\/|https?:\/\/)?(?!.*\\:\/\/)[^\\s]+$", "contentMediaType": "video\/*" }, "poster": { "type": "string", "format": "uri-reference", "pattern": "^(\/|https?:\/\/)?(?!.*\\:\/\/)[^\\s]+$", "contentMediaType": "image\/*" } }, "required": [ "src" ], "type": "object" } should have been just { "properties": { "src": { "type": "string", "contentMediaType": "video\/*", "format": "uri-reference", "pattern": "^(\/|https?:\/\/)?(?!.*\\:\/\/)[^\\s]+$" }, "poster": { "type": "string", "contentMediaType": "image\/*", "format": "uri-reference", "pattern": "^(\/|https?:\/\/)?(?!.*\\:\/\/)[^\\s]+$" } }, "required": [ "src" ], "type": "object" }.</pre><p>That's because the comparison logic doesn't sort recursively through the JSON schema.</p>
<pre> ksort($sdc_prop_source['jsonSchema']);<br> ksort($minimal);<br> if ($sdc_prop_source['jsonSchema'] !== $minimal) {</pre><p>The <code>properties</code> keys are not sorted the same.</p>
<h4>Steps to reproduce</h4>
<p>1. Create a <em>VideoCC</em> code component in the code editor with</p>
<pre>const Component = ({<br> video,<br>}) => {<br> return (<br> <div className="text-3xl"><br> <video controls width="250" poster={ video?.poster }><br> <source src={ video.src } type="video/mp4"/><br> </video><br> </div><br> );<br>};<br><br>export default Component;</pre><p>2. Ensure you add a <em>Video</em> prop with type <code>video</code>.<br>
3. Promote to available components in the library.<br>
4. Create a new page with that video. Link to a video from your media library. It works.<br>
5. Remove the video so it uses the defaults and save.<br>
6. The preview fails.<br>
7. If you manually go to <code>/canvas/api/v0/layout/canvas_page/1</code> you'll see the stacktrace:</p>
<pre>file: "/var/www/html/web/modules/contrib/canvas/src/PropSource/DefaultRelativeUrlPropSource.php",<br>line: 101,<br>trace: [<br>{<br>file: "/var/www/html/web/modules/contrib/canvas/src/PropSource/PropSource.php",<br>line: 33,<br>function: "parse",<br>class: "Drupal\canvas\PropSource\DefaultRelativeUrlPropSource",<br>type: "::"<br>},<br>{<br>file: "/var/www/html/web/modules/contrib/canvas/src/Plugin/Canvas/ComponentSource/GeneratedFieldExplicitInputUxComponentSourceBase.php",<br>line: 1263,<br>function: "parse",<br>class: "Drupal\canvas\PropSource\PropSource",<br>type: "::"<br>},<br>{<br>file: "/var/www/html/web/modules/contrib/canvas/src/Plugin/Canvas/ComponentSource/GeneratedFieldExplicitInputUxComponentSourceBase.php",<br>line: 342,<br>function: "uncollapse",<br>class: "Drupal\canvas\Plugin\Canvas\ComponentSource\GeneratedFieldExplicitInputUxComponentSourceBase",<br>type: "->"<br>},<br>{<br>file: "/var/www/html/web/modules/contrib/canvas/src/Plugin/Field/FieldType/ComponentTreeItemList.php",<br>line: 99,<br>function: "getExplicitInput",<br>class: "Drupal\canvas\Plugin\Canvas\ComponentSource\GeneratedFieldExplicitInputUxComponentSourceBase",<br>type: "->"<br>},</pre><h3 id="proposed-resolution">Proposed resolution</h3>
<p>Drupal doesn't have a recursive ksort, so hack it like</p>
<pre> ksort($sdc_prop_source['jsonSchema']);<br> foreach (array_keys($sdc_prop_source['jsonSchema']['properties']) as $property_key) {<br> ksort($sdc_prop_source['jsonSchema']['properties'][$property_key]);<br> }<br> ksort($minimal);<br> foreach (array_keys($minimal['properties']) as $property_key) {<br> ksort($minimal['properties'][$property_key]);<br> }</pre><h3 id="ui-changes">User interface changes</h3>
> Related issue: [Issue #3556987](https://www.drupal.org/node/3556987)
issue