diff --git a/.changeset/light-bugs-shake.md b/.changeset/light-bugs-shake.md new file mode 100644 index 000000000000..c5fe7209341c --- /dev/null +++ b/.changeset/light-bugs-shake.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes type generation for empty content collections diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index 296e10417f1a..66e5aef3c8d1 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -35,18 +35,18 @@ type DataEntryMetadata = Record; type ContentEntryMetadata = { slug: string }; type CollectionEntryMap = { [collection: string]: - | { - type: 'unknown'; - entries: Record; - } - | { - type: 'content'; - entries: Record; - } - | { - type: 'data'; - entries: Record; - }; + | { + type: 'unknown'; + entries: Record; + } + | { + type: 'content'; + entries: Record; + } + | { + type: 'data'; + entries: Record; + }; }; type CreateContentGeneratorParams = { @@ -425,16 +425,21 @@ async function writeContentFiles({ const resolvedType: 'content' | 'data' = collection.type === 'unknown' ? // Add empty / unknown collections to the data type map by default - // This ensures `getCollection('empty-collection')` doesn't raise a type error - collectionConfig?.type ?? 'data' + // This ensures `getCollection('empty-collection')` doesn't raise a type error + collectionConfig?.type ?? 'data' : collection.type; + const collectionEntryKeys = Object.keys(collection.entries).sort(); + const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any'; switch (resolvedType) { case 'content': + if (collectionEntryKeys.length === 0) { + contentTypesStr += `${collectionKey}: Record;\n`; + break; + } contentTypesStr += `${collectionKey}: {\n`; - for (const entryKey of Object.keys(collection.entries).sort()) { + for (const entryKey of collectionEntryKeys) { const entryMetadata = collection.entries[entryKey]; - const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any'; const renderType = `{ render(): Render[${JSON.stringify( path.extname(JSON.parse(entryKey)) )}] }`; @@ -445,10 +450,14 @@ async function writeContentFiles({ contentTypesStr += `};\n`; break; case 'data': - dataTypesStr += `${collectionKey}: {\n`; - for (const entryKey of Object.keys(collection.entries).sort()) { - const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any'; - dataTypesStr += `${entryKey}: {\n id: ${entryKey};\n collection: ${collectionKey};\n data: ${dataType}\n};\n`; + if (collectionEntryKeys.length === 0) { + dataTypesStr += `${collectionKey}: Record;\n`; + } else { + dataTypesStr += `${collectionKey}: {\n`; + for (const entryKey of collectionEntryKeys) { + dataTypesStr += `${entryKey}: {\n id: ${entryKey};\n collection: ${collectionKey};\n data: ${dataType}\n};\n`; + } + dataTypesStr += `};\n`; } if (settings.config.experimental.contentCollectionJsonSchema && collectionConfig?.schema) { @@ -481,7 +490,6 @@ async function writeContentFiles({ ); } } - dataTypesStr += `};\n`; break; } } diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js index bfa8ab883874..8cc15f7dd811 100644 --- a/packages/astro/test/astro-sync.test.js +++ b/packages/astro/test/astro-sync.test.js @@ -89,6 +89,32 @@ describe('astro sync', () => { ); }); + it('Writes types for empty collections', async () => { + await fixture.whenSyncing('./fixtures/content-collections-empty-dir/'); + fixture.thenFileShouldExist('.astro/types.d.ts'); + fixture.thenFileContentShouldInclude( + '.astro/types.d.ts', + `"blog": Record; + render(): Render[".md"]; +}>;`, + 'Types file does not include empty collection type' + ); + fixture.thenFileContentShouldInclude( + '.astro/types.d.ts', + `"blogMeta": Record; +}>;`, + 'Types file does not include empty collection type' + ); + }); + it('Adds type reference to `src/env.d.ts`', async () => { await fixture.whenSyncing('./fixtures/content-collections/'); fixture.thenFileShouldExist('src/env.d.ts'); diff --git a/packages/astro/test/fixtures/content-collections-empty-dir/src/content/config.ts b/packages/astro/test/fixtures/content-collections-empty-dir/src/content/config.ts index 502bd5170c95..fc21917920fa 100644 --- a/packages/astro/test/fixtures/content-collections-empty-dir/src/content/config.ts +++ b/packages/astro/test/fixtures/content-collections-empty-dir/src/content/config.ts @@ -6,6 +6,14 @@ const blog = defineCollection({ }), }); +const blogMeta = defineCollection({ + type: 'data', + schema: z.object({ + title: z.string(), + }), +}); + export const collections = { blog, + blogMeta, };