Skip to content

refactor: MCD-1297: Derive the schema type of @schemaRef props from the TypeScript type. - #202

Merged
fago merged 4 commits into
1.xfrom
feature/mcd-1297-schema-type
Aug 5, 2026
Merged

refactor: MCD-1297: Derive the schema type of @schemaRef props from the TypeScript type.#202
fago merged 4 commits into
1.xfrom
feature/mcd-1297-schema-type

Conversation

@drubot

@drubot drubot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

@schemaRef hard-coded type: 'string' on the generated prop definition. Canvas resolves a prop's storage from its JSON Schema type before it resolves the $ref, so a $ref pointing at an object definition never matched — only URI-ish string definitions were reachable. The visible symptom is a media picker silently degrading to a plain string field.

The prop's TypeScript declaration already states whether it is an object, and TypeScript is a hard prerequisite of the whole extraction, so the JSON Schema type is derived from the resolved type rather than restated in JSDoc:

/**
 * Image
 * @schemaRef lupus_image/image
 */
media?: LupusImage   // -> type: object

Nothing about existing @schemaRef props changes — string-typed props still map to type: string.

This unblocks Drupal extensions shipping their own schema.json definitions — the json-schema-definitions://<extension>.module/<name> stream wrapper reads a schema.json from any extension root, not only Canvas. MCD-1297 uses it for a richer image object (media copyright / caption / source / focal point) than Canvas' built-in canvas.module/image.

Why the checker needed schema: true

createChecker() was constructed without the schema option, which disables type resolution entirely — every prop.schema came back as a bare type string, so a named interface (LupusCanvasImage) was indistinguishable from a string. Deriving the type is only possible with resolution on.

Two things make that cheap and safe:

  • vue-component-meta exposes a resolved schema's members through lazy getters, so enabling it costs one level of kind determination per prop, not a tree walk.
  • The generated playground index is byte-identical before and after apart from the one object-typed $ref prop (verified by diffing the full generated index both ways). In particular the array-prop handling — which already had a structured-schema branch that had never been reachable — produces exactly the same output.

Changes

  • deriveSchemaRefType() reads the JSON Schema type off the prop's resolved schema: kind: 'object'object; an optional prop (kind: 'enum' over undefined | T) with an object member → object; otherwise the usual type-string mapping.
  • createChecker(…, { schema: true }) so prop types resolve at all.
  • Playground fixture prop TestSchemaRefFile.richImage, typed as a named interface to mirror real usage.
  • Tests: an object-typed $ref prop derives type: object; a string-typed one derives type: string.
  • README: the object-$ref paragraph documents derivation.

Testing

npm test130/130 pass. npm run lint — 0 errors (5 pre-existing warnings in an untouched file). Both re-run after merging 1.x (nuxt 4.5.1 / vitest 4).

Refs: MCD-1297

Drafted with Claude Code from claude-vm-1.

loki et fago and others added 2 commits August 3, 2026 13:20
…nitions.

Canvas resolves a prop's storage from its JSON Schema type before resolving
the $ref, so an object definition only matches when the prop declares
type: object. A prop typed as a TypeScript interface carries no JSON Schema
type, so the type has to be stated. Defaults to string, which is what the
Canvas URI refs need.
loki et fago added 2 commits August 4, 2026 13:46
…peScript.

Canvas resolves a prop's storage from its JSON Schema type before resolving
the $ref, so an object definition only matches a prop carrying type: object.
The prop's TypeScript declaration already states that, and TypeScript is a
hard prerequisite of the whole extraction, so the type is derived from the
resolved vue-component-meta schema instead of being restated in JSDoc.

Deriving it requires the checker to resolve prop types into structured
schemas (schema: true); without that every prop schema is a bare type string
and a named interface is indistinguishable from a string. The nested schema
members are lazy getters, so the cost is one level per prop, and the
generated playground index is unchanged apart from the object-typed $ref
prop.
@drubot drubot changed the title feat: MCD-1297: Add @schemaType so @schemaRef can point at object definitions. refactor: MCD-1297: Derive the schema type of @schemaRef props from the TypeScript type. Aug 4, 2026
@drubot

drubot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Claude Code: independent review, requested by fago via MCD-1297 ("not sure about this one").

Verdict: merge-ready.

  • deriveSchemaRefType() is correct for the cases that exist: required object prop (kind: 'object'), optional object prop (kind: 'enum' union with an object member), everything else falls back to the exact 1.0.1 mapping — so no released consumer's index changes unless a prop is genuinely object-typed.
  • The load-bearing change is schema: true on createChecker(), not the new function — without it a named interface is indistinguishable from a string, which is precisely the bug. Evidence it's inert elsewhere: the full playground index diffs by one line (richImage string→object); kickstart's real 32-component index passes 58/58 with this build vs 5 failures on 1.0.1; CI here is green (unit + e2e) on the current head after the 1.x merge, so index generation with schema resolution is not a perf problem in either the dev or prod path.
  • The gap is confirmed in production terms: the mcd-1297 CI env serves its media props as "type": "string" with the $ref today (built with released 1.0.1), and every Canvas image on that env is gone as a result. This PR is the fix for exactly that.

Non-blocking notes:

  • A string-typed prop carrying an object $ref (author error) still emits type: string silently and only surfaces Drupal-side. A build-time warning would be a nice follow-up, not a gate.
  • The @schemaType tag is now silently ignored where present; it never shipped in a release, so that's fine.

@fago
fago merged commit 4f1423c into 1.x Aug 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants