diff --git a/packages/astro/src/content/loaders.ts b/packages/astro/src/content/loaders.ts index 5a964fd995613..f34c0e0fff43d 100644 --- a/packages/astro/src/content/loaders.ts +++ b/packages/astro/src/content/loaders.ts @@ -2,7 +2,7 @@ import type { ZodSchema } from 'zod'; import type { AstroSettings } from '../@types/astro.js'; import type { AstroIntegrationLogger, Logger } from '../core/logger/core.js'; import { DataStore, globalDataStore, type MetaStore, type ScopedDataStore } from './data-store.js'; -import { globalContentConfigObserver } from './utils.js'; +import { getEntryData, globalContentConfigObserver } from './utils.js'; import { promises as fs, existsSync } from 'fs'; export interface LoaderContext { @@ -14,6 +14,11 @@ export interface LoaderContext { logger: AstroIntegrationLogger; settings: AstroSettings; + + parseData = Record>( + id: string, + data: T + ): T; } export interface Loader { @@ -45,12 +50,33 @@ export async function syncDataLayer({ if (collection.type !== 'experimental_data') { return; } + + function parseData = Record>( + id: string, + data: T + ): T { + return getEntryData( + { + id, + collection: name, + unvalidatedData: data, + _internal: { + rawData: undefined, + filePath: '#invalid', + }, + }, + collection, + false + ) as unknown as T; + } + return collection.loader.load({ collection: name, store: store.scopedStore(name), meta: store.metaStore(name), logger: logger.forkIntegrationLogger('content'), settings, + parseData }); }) ); diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index 1b892591e51bb..9917d5d34df2a 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -49,6 +49,7 @@ export const collectionConfigParser = z.union([ meta: z.any(), logger: z.any(), settings: z.any(), + parseData: z.any(), }), ], z.unknown() @@ -104,10 +105,10 @@ export async function getEntryData( }, collectionConfig: CollectionConfig, shouldEmitFile: boolean, - pluginContext: PluginContext + pluginContext?: PluginContext ) { let data; - if (collectionConfig.type === 'data') { + if (collectionConfig.type === 'data' || collectionConfig.type === 'experimental_data') { data = entry.unvalidatedData; } else { const { slug, ...unvalidatedData } = entry.unvalidatedData; @@ -115,7 +116,23 @@ export async function getEntryData( } let schema = collectionConfig.schema; - if (typeof schema === 'function') { + if (collectionConfig.type === 'experimental_data') { + if (!schema) { + // Experimental data loaders can define their own schema + schema = collectionConfig.loader.schema; + } + if (typeof schema === 'function') { + // TODO: images! + schema = schema({ + image: () => { + throw new Error('Images not supported in experimental data loaders'); + }, + }); + } + } else if (typeof schema === 'function') { + if (!pluginContext) { + throw new Error('Plugin context required for dynamic schema'); + } schema = schema({ image: createImage(pluginContext, shouldEmitFile, entry._internal.filePath), }); diff --git a/packages/astro/test/fixtures/content-layer/src/content/config.ts b/packages/astro/test/fixtures/content-layer/src/content/config.ts index 4f03a5039b811..fc796ae7e39d3 100644 --- a/packages/astro/test/fixtures/content-layer/src/content/config.ts +++ b/packages/astro/test/fixtures/content-layer/src/content/config.ts @@ -16,7 +16,7 @@ const dogs = defineCollection({ size: z.string(), origin: z.string(), lifespan: z.string(), - temperament: z.array(z.string()), + temperament: z.array(z.string()) }), }) export const collections = { blog, dogs };