Skip to content

Conversation

@larbish
Copy link
Collaborator

@larbish larbish commented Dec 11, 2025

πŸ”— Linked issue

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

Need it in Studio to build form based on Schema

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@larbish larbish requested a review from farnabaz December 11, 2025 15:20
@vercel
Copy link

vercel bot commented Dec 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
content Ready Ready Preview Comment Dec 11, 2025 4:41pm

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 11, 2025

Deploying content with Β Cloudflare Pages Β Cloudflare Pages

Latest commit: 3d64bfd
Status:Β βœ…Β  Deploy successful!
Preview URL: https://2d4085d0.content-f0q.pages.dev
Branch Preview URL: https://chore-schema-types.content-f0q.pages.dev

View logs

Copy link

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestions:

  1. The isJSONProperty and getPropertyType functions don't handle the new Draft07DefinitionPropertyOneOf type, causing oneOf schema properties to be misclassified.
View Details
πŸ“ Patch Details
diff --git a/src/runtime/internal/schema.ts b/src/runtime/internal/schema.ts
index 50614143..c68c81a7 100644
--- a/src/runtime/internal/schema.ts
+++ b/src/runtime/internal/schema.ts
@@ -1,4 +1,4 @@
-import type { Draft07, Draft07DefinitionProperty, Draft07DefinitionPropertyAllOf, Draft07DefinitionPropertyAnyOf } from '@nuxt/content'
+import type { Draft07, Draft07DefinitionProperty, Draft07DefinitionPropertyAllOf, Draft07DefinitionPropertyAnyOf, Draft07DefinitionPropertyOneOf } from '@nuxt/content'
 
 const propertyTypes = {
   string: 'VARCHAR',
@@ -20,15 +20,16 @@ export function getOrderedSchemaKeys(schema: Draft07) {
   return Array.from(keys) as string[]
 }
 
-function isJSONProperty(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf) {
+function isJSONProperty(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf | Draft07DefinitionPropertyOneOf) {
   const propertyType = (property as Draft07DefinitionProperty).type
   return propertyType === 'object'
     || propertyType === 'array'
     || !!(property as Draft07DefinitionPropertyAnyOf).anyOf
     || !!(property as Draft07DefinitionPropertyAllOf).allOf
+    || !!(property as Draft07DefinitionPropertyOneOf).oneOf
 }
 
-function getPropertyType(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf) {
+function getPropertyType(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf | Draft07DefinitionPropertyOneOf) {
   const propertyType = (property as Draft07DefinitionProperty).type
   let type = propertyTypes[propertyType as keyof typeof propertyTypes] || 'TEXT'
 
@@ -52,6 +53,18 @@ function getPropertyType(property: Draft07DefinitionProperty | Draft07Definition
     }
   }
 
+  if ((property as Draft07DefinitionPropertyOneOf).oneOf) {
+    type = 'TEXT'
+
+    const oneOf = (property as Draft07DefinitionPropertyOneOf).oneOf
+    const nullIndex = oneOf.findIndex(t => t.type === 'null')
+    if (oneOf.length === 2 && nullIndex !== -1) {
+      type = nullIndex === 0
+        ? getPropertyType(oneOf[1]!)
+        : getPropertyType(oneOf[0]!)
+    }
+  }
+
   if (Array.isArray(propertyType) && propertyType.includes('null') && propertyType.length === 2) {
     type = propertyType[0] === 'null'
       ? propertyTypes[propertyType[1] as keyof typeof propertyTypes] || 'TEXT'
@@ -85,6 +98,12 @@ export function describeProperty(schema: Draft07, property: string) {
     }
   }
 
+  if ((shape[property] as Draft07DefinitionPropertyOneOf).oneOf) {
+    if (((shape[property] as Draft07DefinitionPropertyOneOf).oneOf).find(t => t.type === 'null')) {
+      result.nullable = true
+    }
+  }
+
   if (Array.isArray(type) && type.includes('null')) {
     result.nullable = true
   }

Analysis

Missing oneOf property handling in schema runtime functions

What fails: isJSONProperty() and getPropertyType() functions in src/runtime/internal/schema.ts don't recognize Draft07DefinitionPropertyOneOf type, causing oneOf schema properties to be incorrectly classified as non-JSON and missing nullable detection logic.

How to reproduce:

// Using a schema with oneOf property:
const schema = {
  $schema: 'http://json-schema.org/draft-07/schema#',
  definitions: {
    Content: {
      properties: {
        config: {
          oneOf: [
            { type: 'object', properties: { key: { type: 'string' } } },
            { type: 'object', properties: { value: { type: 'number' } } }
          ]
        }
      },
      required: []
    }
  }
}

const property = describeProperty(schema, 'config')
console.log(property.json) // Returns false, should be true

Result: isJSONProperty() returns false for oneOf properties (should return true), and getPropertyType() doesn't apply nullable detection when oneOf contains a null type. This causes oneOf properties to be misclassified in the database schema generation.

Expected: oneOf properties should be treated as JSON properties (like anyOf and allOf are), and nullable detection should work correctly for oneOf combinations with null types.

Fix: Updated src/runtime/internal/schema.ts to:

  • Import Draft07DefinitionPropertyOneOf type
  • Add Draft07DefinitionPropertyOneOf to type parameters in isJSONProperty() and getPropertyType()
  • Add || !!(property as Draft07DefinitionPropertyOneOf).oneOf check to isJSONProperty()
  • Add oneOf handling block in getPropertyType() with nullable detection (mirrors anyOf logic)
  • Add oneOf nullable detection in describeProperty()

This ensures oneOf properties are handled consistently with anyOf and allOf patterns already in the codebase.

2. The nullable detection logic in `describeProperty` only checks `anyOf` for null types\, but won\'t detect null types in the new `oneOf` variant\.
View Details
πŸ“ Patch Details
diff --git a/src/runtime/internal/schema.ts b/src/runtime/internal/schema.ts
index 50614143..c68c81a7 100644
--- a/src/runtime/internal/schema.ts
+++ b/src/runtime/internal/schema.ts
@@ -1,4 +1,4 @@
-import type { Draft07, Draft07DefinitionProperty, Draft07DefinitionPropertyAllOf, Draft07DefinitionPropertyAnyOf } from '@nuxt/content'
+import type { Draft07, Draft07DefinitionProperty, Draft07DefinitionPropertyAllOf, Draft07DefinitionPropertyAnyOf, Draft07DefinitionPropertyOneOf } from '@nuxt/content'
 
 const propertyTypes = {
   string: 'VARCHAR',
@@ -20,15 +20,16 @@ export function getOrderedSchemaKeys(schema: Draft07) {
   return Array.from(keys) as string[]
 }
 
-function isJSONProperty(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf) {
+function isJSONProperty(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf | Draft07DefinitionPropertyOneOf) {
   const propertyType = (property as Draft07DefinitionProperty).type
   return propertyType === 'object'
     || propertyType === 'array'
     || !!(property as Draft07DefinitionPropertyAnyOf).anyOf
     || !!(property as Draft07DefinitionPropertyAllOf).allOf
+    || !!(property as Draft07DefinitionPropertyOneOf).oneOf
 }
 
-function getPropertyType(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf) {
+function getPropertyType(property: Draft07DefinitionProperty | Draft07DefinitionPropertyAllOf | Draft07DefinitionPropertyAnyOf | Draft07DefinitionPropertyOneOf) {
   const propertyType = (property as Draft07DefinitionProperty).type
   let type = propertyTypes[propertyType as keyof typeof propertyTypes] || 'TEXT'
 
@@ -52,6 +53,18 @@ function getPropertyType(property: Draft07DefinitionProperty | Draft07Definition
     }
   }
 
+  if ((property as Draft07DefinitionPropertyOneOf).oneOf) {
+    type = 'TEXT'
+
+    const oneOf = (property as Draft07DefinitionPropertyOneOf).oneOf
+    const nullIndex = oneOf.findIndex(t => t.type === 'null')
+    if (oneOf.length === 2 && nullIndex !== -1) {
+      type = nullIndex === 0
+        ? getPropertyType(oneOf[1]!)
+        : getPropertyType(oneOf[0]!)
+    }
+  }
+
   if (Array.isArray(propertyType) && propertyType.includes('null') && propertyType.length === 2) {
     type = propertyType[0] === 'null'
       ? propertyTypes[propertyType[1] as keyof typeof propertyTypes] || 'TEXT'
@@ -85,6 +98,12 @@ export function describeProperty(schema: Draft07, property: string) {
     }
   }
 
+  if ((shape[property] as Draft07DefinitionPropertyOneOf).oneOf) {
+    if (((shape[property] as Draft07DefinitionPropertyOneOf).oneOf).find(t => t.type === 'null')) {
+      result.nullable = true
+    }
+  }
+
   if (Array.isArray(type) && type.includes('null')) {
     result.nullable = true
   }

Analysis

Missing nullable detection for oneOf schema properties in describeProperty()

What fails: Properties using oneOf with a null option are not detected as nullable. The describeProperty(), isJSONProperty(), and getPropertyType() functions only check anyOf and allOf, ignoring oneOf.

How to reproduce:

// Schema using oneOf with null option
const schema = {
  definitions: {
    __SCHEMA__: {
      properties: {
        field: {
          oneOf: [
            { type: 'string' },
            { type: 'null' }
          ]
        }
      }
    }
  }
}

// Current behavior
describeProperty(schema, 'field').nullable // Returns false (WRONG)

// Expected behavior
describeProperty(schema, 'field').nullable // Should return true

Result:

  • describeProperty() returns nullable: false for oneOf properties containing null
  • isJSONProperty() does not recognize oneOf as JSON properties
  • getPropertyType() does not extract the correct type from oneOf[type|null]

Expected: Per JSON Schema Draft 7 specification, oneOf is a valid keyword for union types alongside anyOf. Properties with oneOf containing a null option should be marked as nullable, similar to how anyOf properties are handled.

Root cause: The functions in src/runtime/internal/schema.ts only check for anyOf and allOf but do not handle the oneOf keyword, which is part of the schema property types as defined in src/types/schema.ts.

Fix applied:

  • Added Draft07DefinitionPropertyOneOf to imports
  • Updated isJSONProperty() to check for oneOf
  • Updated getPropertyType() to extract types from oneOf with null similar to anyOf handling
  • Updated describeProperty() to detect nullable from oneOf with null option
3. The zod4 schema converter doesn\'t import or include `Draft07DefinitionPropertyOneOf` in its type union\, preventing correct typing of oneOf properties from zod schemas\.
View Details
πŸ“ Patch Details
diff --git a/src/utils/schema/zod4.ts b/src/utils/schema/zod4.ts
index d3ee67cb..ab17b51c 100644
--- a/src/utils/schema/zod4.ts
+++ b/src/utils/schema/zod4.ts
@@ -1,5 +1,5 @@
 import { z as zod } from 'zod/v4'
-import type { Draft07, Draft07DefinitionProperty, Draft07DefinitionPropertyAllOf, Draft07DefinitionPropertyAnyOf } from '../../types'
+import type { Draft07, Draft07DefinitionProperty, Draft07DefinitionPropertyAllOf, Draft07DefinitionPropertyAnyOf, Draft07DefinitionPropertyOneOf } from '../../types'
 
 export function toJSONSchema(
   _schema: unknown,
@@ -34,6 +34,7 @@ export function toJSONSchema(
               | Draft07DefinitionProperty
               | Draft07DefinitionPropertyAnyOf
               | Draft07DefinitionPropertyAllOf
+              | Draft07DefinitionPropertyOneOf
             >) || {},
           required: (baseSchema.required as string[]) || [],
           additionalProperties:

Analysis

Missing Draft07DefinitionPropertyOneOf type in zod4.ts schema converter

What fails: The zod4.ts schema converter has incomplete type annotations for JSON Schema properties. The Draft07Definition type includes Draft07DefinitionPropertyOneOf in its valid property types (line 11 of schema.ts), but zod4.ts does not include this type in its property union cast (lines 34-36), creating a type mismatch.

How to reproduce:

  1. Create a zod schema that produces a property with oneOf (e.g., from a future version of zod/v4 or when manually providing such properties)
  2. Pass it through the toJSONSchema() function in src/utils/schema/zod4.ts
  3. The TypeScript compiler will report a type error when the resulting schema is assigned to Draft07Definition

Result: While Zod v4's current toJSONSchema implementation generates anyOf (not oneOf), the type system should be consistent with the Draft07Definition interface which explicitly allows Draft07DefinitionPropertyOneOf in its property union. The missing import and type union cause TypeScript type checking to fail if a property with oneOf structure were present.

Expected: The import statement should include Draft07DefinitionPropertyOneOf and the property type cast should include Draft07DefinitionPropertyOneOf in its union, matching the requirements defined in src/types/schema.ts line 11.

Fix: Added Draft07DefinitionPropertyOneOf to both the import statement (line 2) and the property type union (lines 34-36) to align with the Draft07Definition type definition.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 11, 2025

npm i https://pkg.pr.new/@nuxt/content@3639

commit: 3d64bfd

Copy link

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

Missing nullable detection for oneOf properties. Properties using oneOf with a null variant won't be marked as nullable, even though properties using anyOf with the same pattern are correctly handled.

View Details
πŸ“ Patch Details
diff --git a/src/runtime/internal/schema.ts b/src/runtime/internal/schema.ts
index de479f80..c68c81a7 100644
--- a/src/runtime/internal/schema.ts
+++ b/src/runtime/internal/schema.ts
@@ -98,6 +98,12 @@ export function describeProperty(schema: Draft07, property: string) {
     }
   }
 
+  if ((shape[property] as Draft07DefinitionPropertyOneOf).oneOf) {
+    if (((shape[property] as Draft07DefinitionPropertyOneOf).oneOf).find(t => t.type === 'null')) {
+      result.nullable = true
+    }
+  }
+
   if (Array.isArray(type) && type.includes('null')) {
     result.nullable = true
   }

Analysis

Missing nullable detection for oneOf properties in describeProperty()

What fails: Properties using oneOf with a null variant are not marked as nullable in the describeProperty() function, even though equivalent anyOf properties are correctly marked. This causes inconsistent behavior when both schema patterns represent optional fields.

How to reproduce:

const schema: Draft07 = {
  definitions: {
    __SCHEMA__: {
      type: 'object',
      properties: {
        testProp: {
          oneOf: [
            { type: 'null' },
            { type: 'string' }
          ]
        }
      },
      required: ['testProp']
    }
  }
}

const result = describeProperty(schema, 'testProp')
// Result: nullable = false (INCORRECT)

Expected behavior: Should return nullable: true because the property supports null values via the oneOf pattern, matching the behavior of anyOf.

Root cause: describeProperty() in src/runtime/internal/schema.ts (lines 95-98) checks anyOf properties for null variants, but has no corresponding check for oneOf properties. The getPropertyType() function already correctly handles both patterns (lines 56-66), but the nullable flag detection is incomplete.

Fix: Added nullable detection for oneOf properties matching the existing anyOf pattern in describeProperty().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants