diff --git a/packages/astro/src/content/template/virtual-mod.mjs b/packages/astro/src/content/template/virtual-mod.mjs index c5dc1b4f3..59f0dfa70 100644 --- a/packages/astro/src/content/template/virtual-mod.mjs +++ b/packages/astro/src/content/template/virtual-mod.mjs @@ -5,7 +5,8 @@ import { createGetEntryBySlug, } from 'astro/content/runtime'; -export { z } from 'astro/zod'; +import { z } from 'astro/zod'; +export { z }; export function defineCollection(config) { return config; @@ -38,3 +39,49 @@ export const getEntryBySlug = createGetEntryBySlug({ getCollection, collectionToRenderEntryMap, }); + +export function image() { + let astroContext = undefined; + const str = z.string(); + const _parse = str._parse; + str._parse = function(ctx){ + // Walk up the parents until we find the Astro context. + let parent = ctx.parent; + while(parent) { + if(parent.astro) { + astroContext = parent.astro; + break; + } else { + parent = parent.parent; + } + } + return _parse.call(this, ctx); + + } + return str.transform(async (imagePath, ctx) => { + const { + settings, + pluginContext, + filePath: entryFilePath + } = astroContext; + const resolvedFilePath = (await pluginContext.resolve(imagePath, entryFilePath))?.id; + const metadata = await emitESMImage( + resolvedFilePath, + pluginContext.meta.watchMode, + pluginContext.emitFile, + settings + ); + + if (!metadata) { + ctx.addIssue({ + code: 'custom', + message: `Image ${imagePath} does not exist. Is the path correct?`, + fatal: true, + }); + + return z.NEVER; + } + + return metadata; + }); +} diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index cb4fc7269..1d9a51a99 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -83,6 +83,16 @@ export async function getEntryData( : collectionConfig.schema; if (schema) { + // Override _processInputParams so we can pass down our own context. + const _processInputParams = schema._processInputParams; + schema._processInputParams = function(input: any) { + const out = _processInputParams.call(this, input); + out.ctx.astro = { + settings, pluginContext, + filePath: entry._internal.filePath + }; + return out; + }; // Catch reserved `slug` field inside schema // Note: will not warn for `z.union` or `z.intersection` schemas if (typeof schema === 'object' && 'shape' in schema && schema.shape.slug) {