diff --git a/package.json b/package.json index ca0ccd490..fd6e9e09f 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "micromatch": "^4.0.8", "minimark": "^0.2.0", "minimatch": "^10.0.3", - "nuxt-component-meta": "^0.12.1", + "nuxt-component-meta": "https://pkg.pr.new/nuxt-component-meta@ff0edad", "nypm": "^0.6.0", "ohash": "^2.0.11", "pathe": "^2.0.3", diff --git a/playground/components/PropsExample.vue b/playground/components/PropsExample.vue new file mode 100644 index 000000000..d13b4b319 --- /dev/null +++ b/playground/components/PropsExample.vue @@ -0,0 +1,76 @@ + + + Props Example Component + + Count (number): {{ count }} + Title (string): {{ title }} + Is Active (boolean): {{ isActive ? 'Yes' : 'No' }} + + + + This content is shown when isActive is true! + Current count multiplied by 2: {{ count * 2 }} + + + + {{ title }} + + + + + + + diff --git a/playground/components/TestD.vue b/playground/components/TestD.vue new file mode 100644 index 000000000..63b2227a1 --- /dev/null +++ b/playground/components/TestD.vue @@ -0,0 +1,21 @@ + + + + + Test C + + diff --git a/playground/content.config.ts b/playground/content.config.ts index 44b32fc2a..69ebe7b13 100644 --- a/playground/content.config.ts +++ b/playground/content.config.ts @@ -34,6 +34,7 @@ const content = defineCollection({ schema: z.object({ date: z.date(), rawbody: z.string(), + testd: z.component('components/TestD.vue'), }), }) @@ -69,6 +70,11 @@ const collections = { content, data, pages, + buttons: defineCollection({ + type: 'data', + source: 'testd/**', + schema: z.component('@nuxt/ui/components/Button.vue'), + }), contentV2: defineCollection({ type: 'page', source: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4e77de12..53fd080dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,8 +99,8 @@ importers: specifier: ^10.0.3 version: 10.0.3 nuxt-component-meta: - specifier: ^0.12.1 - version: 0.12.1(magicast@0.3.5)(vue-component-type-helpers@2.2.12) + specifier: https://pkg.pr.new/nuxt-component-meta@ff0edad + version: https://pkg.pr.new/nuxt-component-meta@ff0edad(magicast@0.3.5)(vue-component-type-helpers@2.2.12) nypm: specifier: ^0.6.0 version: 0.6.0 @@ -5043,6 +5043,10 @@ packages: engines: {node: '>=16.0.0'} hasBin: true + json-schema-to-zod@2.6.1: + resolution: {integrity: sha512-uiHmWH21h9FjKJkRBntfVGTLpYlCZ1n98D0izIlByqQLqpmkQpNTBtfbdP04Na6+43lgsvrShFh2uWLkQDKJuQ==} + hasBin: true + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -5817,8 +5821,9 @@ packages: engines: {node: ^16.10.0 || >=18.0.0} hasBin: true - nuxt-component-meta@0.12.1: - resolution: {integrity: sha512-w0ZgRCE9wGZLbmAnCUV2F4/Gjwy1J6L9FejrpTHSHM8Igrf2THwe809QOXbdV8g4+Elkz2MeC/34ZFyt05tKCg==} + nuxt-component-meta@https://pkg.pr.new/nuxt-component-meta@ff0edad: + resolution: {tarball: https://pkg.pr.new/nuxt-component-meta@ff0edad} + version: 0.12.1 hasBin: true nuxt-llms@0.1.3: @@ -13709,6 +13714,8 @@ snapshots: prettier: 3.6.2 tinyglobby: 0.2.14 + json-schema-to-zod@2.6.1: {} + json-schema-traverse@0.4.1: {} json-schema@0.4.0: {} @@ -14765,10 +14772,11 @@ snapshots: nuxi@3.25.1: {} - nuxt-component-meta@0.12.1(magicast@0.3.5)(vue-component-type-helpers@2.2.12): + nuxt-component-meta@https://pkg.pr.new/nuxt-component-meta@ff0edad(magicast@0.3.5)(vue-component-type-helpers@2.2.12): dependencies: '@nuxt/kit': 3.17.6(magicast@0.3.5) citty: 0.1.6 + json-schema-to-zod: 2.6.1 mlly: 1.7.4 ohash: 2.0.11 scule: 1.3.0 diff --git a/src/utils/collection.ts b/src/utils/collection.ts index ce5381f24..e82eabc3c 100644 --- a/src/utils/collection.ts +++ b/src/utils/collection.ts @@ -4,7 +4,7 @@ import type { Collection, ResolvedCollection, CollectionSource, DefinedCollectio import { getOrderedSchemaKeys, describeProperty, getCollectionFieldsTypes } from '../runtime/internal/schema' import type { Draft07, ParsedContentFile } from '../types' import { defineLocalSource, defineGitHubSource, defineBitbucketSource } from './source' -import { emptyStandardSchema, mergeStandardSchema, metaStandardSchema, pageStandardSchema } from './schema' +import { emptyStandardSchema, mergeStandardSchema, metaStandardSchema, pageStandardSchema, replaceComponentSchemas } from './schema' import { z, zodToStandardSchema } from './zod' import { logger } from './dev' @@ -17,6 +17,7 @@ export function defineCollection(collection: Collection>(obj: T) { return Object.values(obj) as [(typeof obj)[keyof T]] @@ -204,3 +207,33 @@ export function mergeStandardSchema(s1: Draft07, s2: Draft07): Draft07 { ), } } + +export function replaceComponentSchemas(property: T): T { + if (property.type !== 'object') { + return property + } + + // If the property has a _inherit property, replace it with the component's props schema + if (property.properties?._inherit) { + const nuxt = useNuxt() + let path = String((property.properties._inherit as Draft07DefinitionProperty).default) + try { + path = resolveModule(path) + } + catch { + // Ignore error + } + + const meta = getComponentMeta(path, { rootDir: nuxt.options.rootDir }) + return propsToJsonSchema(meta.props) as T + } + + // Look for _inherit properties in nested objects + if (property.properties) { + Object.entries(property.properties).forEach(([key, value]) => { + property.properties![key] = replaceComponentSchemas(value as Draft07DefinitionProperty) as Draft07DefinitionProperty + }) + } + + return property +} diff --git a/src/utils/zod.ts b/src/utils/zod.ts index 481a2dc05..bbcc653b2 100644 --- a/src/utils/zod.ts +++ b/src/utils/zod.ts @@ -30,7 +30,14 @@ export type SqlFieldType = 'VARCHAR' | 'INT' | 'BOOLEAN' | 'DATE' | 'TEXT' return this } -export const z = zod +export const z = { + ...zod, + component(component: string) { + return zod.object({ + _inherit: zod.string().default(component), + }) + }, +} // Function to get the underlying Zod type export function getUnderlyingType(zodType: ZodType): ZodType {
Count (number): {{ count }}
Title (string): {{ title }}
Is Active (boolean): {{ isActive ? 'Yes' : 'No' }}
This content is shown when isActive is true!
Current count multiplied by 2: {{ count * 2 }}