From 3c0876cbed5033e6b5b42cc2b9d8b393d7e5a55e Mon Sep 17 00:00:00 2001
From: Florian Lefebvre <contact@florian-lefebvre.dev>
Date: Mon, 5 Feb 2024 18:53:18 +0100
Subject: [PATCH] feat(astro): improve `astro:content` types (#9906)

* feat: improve stro:content types

* fix: do not change tsconfig

* "astro/zod" -> "zod"

* `CollectionConfig` parameter extends `BaseSchema`

* fix: update import to zod

* feat: add fallbacks for every export

* Update .changeset/young-bulldogs-tickle.md

---------

Co-authored-by: lilnasy <69170106+lilnasy@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
---
 .changeset/young-bulldogs-tickle.md           |  5 ++
 packages/astro/client.d.ts                    |  4 +
 packages/astro/content-types.template.d.ts    | 49 ------------
 packages/astro/src/virtual-modules/content.ts | 75 +++++++++++++++++++
 4 files changed, 84 insertions(+), 49 deletions(-)
 create mode 100644 .changeset/young-bulldogs-tickle.md
 create mode 100644 packages/astro/src/virtual-modules/content.ts

diff --git a/.changeset/young-bulldogs-tickle.md b/.changeset/young-bulldogs-tickle.md
new file mode 100644
index 0000000000..7f9fcc08ac
--- /dev/null
+++ b/.changeset/young-bulldogs-tickle.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Improves the types for the `astro:content` module by making low fidelity types available before running `astro sync`
diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts
index 8542faa471..9ac0341c64 100644
--- a/packages/astro/client.d.ts
+++ b/packages/astro/client.d.ts
@@ -160,6 +160,10 @@ declare module 'astro:components' {
 	export * from 'astro/components';
 }
 
+declare module 'astro:content' {
+	export * from 'astro/virtual-modules/content.js'
+}
+
 type MD = import('./dist/@types/astro.js').MarkdownInstance<Record<string, any>>;
 interface ExportedMarkdownModuleEntities {
 	frontmatter: MD['frontmatter'];
diff --git a/packages/astro/content-types.template.d.ts b/packages/astro/content-types.template.d.ts
index eeeb6cc934..9ac20a7f14 100644
--- a/packages/astro/content-types.template.d.ts
+++ b/packages/astro/content-types.template.d.ts
@@ -9,8 +9,6 @@ declare module 'astro:content' {
 }
 
 declare module 'astro:content' {
-	export { z } from 'astro/zod';
-
 	type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
 
 	export type CollectionKey = keyof AnyEntryMap;
@@ -19,53 +17,6 @@ declare module 'astro:content' {
 	export type ContentCollectionKey = keyof ContentEntryMap;
 	export type DataCollectionKey = keyof DataEntryMap;
 
-	// This needs to be in sync with ImageMetadata
-	export type ImageFunction = () => import('astro/zod').ZodObject<{
-		src: import('astro/zod').ZodString;
-		width: import('astro/zod').ZodNumber;
-		height: import('astro/zod').ZodNumber;
-		format: import('astro/zod').ZodUnion<
-			[
-				import('astro/zod').ZodLiteral<'png'>,
-				import('astro/zod').ZodLiteral<'jpg'>,
-				import('astro/zod').ZodLiteral<'jpeg'>,
-				import('astro/zod').ZodLiteral<'tiff'>,
-				import('astro/zod').ZodLiteral<'webp'>,
-				import('astro/zod').ZodLiteral<'gif'>,
-				import('astro/zod').ZodLiteral<'svg'>,
-				import('astro/zod').ZodLiteral<'avif'>,
-			]
-		>;
-	}>;
-
-	type BaseSchemaWithoutEffects =
-		| import('astro/zod').AnyZodObject
-		| import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]>
-		| import('astro/zod').ZodDiscriminatedUnion<string, import('astro/zod').AnyZodObject[]>
-		| import('astro/zod').ZodIntersection<BaseSchemaWithoutEffects, BaseSchemaWithoutEffects>;
-
-	type BaseSchema =
-		| BaseSchemaWithoutEffects
-		| import('astro/zod').ZodEffects<BaseSchemaWithoutEffects>;
-
-	export type SchemaContext = { image: ImageFunction };
-
-	type DataCollectionConfig<S extends BaseSchema> = {
-		type: 'data';
-		schema?: S | ((context: SchemaContext) => S);
-	};
-
-	type ContentCollectionConfig<S extends BaseSchema> = {
-		type?: 'content';
-		schema?: S | ((context: SchemaContext) => S);
-	};
-
-	type CollectionConfig<S> = ContentCollectionConfig<S> | DataCollectionConfig<S>;
-
-	export function defineCollection<S extends BaseSchema>(
-		input: CollectionConfig<S>
-	): CollectionConfig<S>;
-
 	type AllValuesOf<T> = T extends any ? T[keyof T] : never;
 	type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
 		ContentEntryMap[C]
diff --git a/packages/astro/src/virtual-modules/content.ts b/packages/astro/src/virtual-modules/content.ts
new file mode 100644
index 0000000000..a3e9a68289
--- /dev/null
+++ b/packages/astro/src/virtual-modules/content.ts
@@ -0,0 +1,75 @@
+import { defineCollection as _defineCollection } from '../content/runtime.js';
+import { z } from 'zod';
+
+export { z };
+
+// This needs to be in sync with ImageMetadata
+export type ImageFunction = () => z.ZodObject<{
+	src: z.ZodString;
+	width: z.ZodNumber;
+	height: z.ZodNumber;
+	format: z.ZodUnion<
+		[
+			z.ZodLiteral<'png'>,
+			z.ZodLiteral<'jpg'>,
+			z.ZodLiteral<'jpeg'>,
+			z.ZodLiteral<'tiff'>,
+			z.ZodLiteral<'webp'>,
+			z.ZodLiteral<'gif'>,
+			z.ZodLiteral<'svg'>,
+			z.ZodLiteral<'avif'>,
+		]
+	>;
+}>;
+
+type BaseSchemaWithoutEffects =
+	| z.AnyZodObject
+	| z.ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]>
+	| z.ZodDiscriminatedUnion<string, z.AnyZodObject[]>
+	| z.ZodIntersection<BaseSchemaWithoutEffects, BaseSchemaWithoutEffects>;
+
+type BaseSchema = BaseSchemaWithoutEffects | z.ZodEffects<BaseSchemaWithoutEffects>;
+
+export type SchemaContext = { image: ImageFunction };
+
+type DataCollectionConfig<S extends BaseSchema> = {
+	type: 'data';
+	schema?: S | ((context: SchemaContext) => S);
+};
+
+type ContentCollectionConfig<S extends BaseSchema> = {
+	type?: 'content';
+	schema?: S | ((context: SchemaContext) => S);
+};
+
+type CollectionConfig<S extends BaseSchema> = ContentCollectionConfig<S> | DataCollectionConfig<S>;
+
+export function defineCollection<S extends BaseSchema>(
+	input: CollectionConfig<S>
+): CollectionConfig<S> {
+	return _defineCollection(input);
+}
+
+const noop: (...args: any[]) => any = () => {};
+/** Run `astro sync` to generate high fidelity types */
+export const getEntryBySlug = noop;
+/** Run `astro sync` to generate high fidelity types */
+export const getDataEntryById = noop;
+/** Run `astro sync` to generate high fidelity types */
+export const getCollection = noop;
+/** Run `astro sync` to generate high fidelity types */
+export const getEntry = noop;
+/** Run `astro sync` to generate high fidelity types */
+export const getEntries = noop;
+/** Run `astro sync` to generate high fidelity types */
+export const reference = noop;
+/** Run `astro sync` to generate high fidelity types */
+export type CollectionKey = any;
+/** Run `astro sync` to generate high fidelity types */
+export type CollectionEntry<C> = any;
+/** Run `astro sync` to generate high fidelity types */
+export type ContentCollectionKey = any;
+/** Run `astro sync` to generate high fidelity types */
+export type DataCollectionKey = any;
+/** Run `astro sync` to generate high fidelity types */
+export type ContentConfig = any;
