0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-24 23:21:57 -05:00

fix(astro): type generation for empty collections (#11264)

* fix(astro): type generation for empty collections

* Update .changeset/light-bugs-shake.md

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>

---------

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
This commit is contained in:
Luiz Ferraz 2024-06-19 12:52:34 -03:00 committed by GitHub
parent 246bd7a516
commit 5a9c9a60e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 68 additions and 21 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes type generation for empty content collections

View file

@ -35,18 +35,18 @@ type DataEntryMetadata = Record<string, never>;
type ContentEntryMetadata = { slug: string };
type CollectionEntryMap = {
[collection: string]:
| {
type: 'unknown';
entries: Record<string, never>;
}
| {
type: 'content';
entries: Record<string, ContentEntryMetadata>;
}
| {
type: 'data';
entries: Record<string, DataEntryMetadata>;
};
| {
type: 'unknown';
entries: Record<string, never>;
}
| {
type: 'content';
entries: Record<string, ContentEntryMetadata>;
}
| {
type: 'data';
entries: Record<string, DataEntryMetadata>;
};
};
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<string, {\n id: string;\n slug: string;\n body: string;\n collection: ${collectionKey};\n data: ${dataType};\n render(): Render[".md"];\n}>;\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<string, {\n id: string;\n collection: ${collectionKey};\n data: ${dataType};\n}>;\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;
}
}

View file

@ -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<string, {
id: string;
slug: string;
body: string;
collection: "blog";
data: InferEntrySchema<"blog">;
render(): Render[".md"];
}>;`,
'Types file does not include empty collection type'
);
fixture.thenFileContentShouldInclude(
'.astro/types.d.ts',
`"blogMeta": Record<string, {
id: string;
collection: "blogMeta";
data: InferEntrySchema<"blogMeta">;
}>;`,
'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');

View file

@ -6,6 +6,14 @@ const blog = defineCollection({
}),
});
const blogMeta = defineCollection({
type: 'data',
schema: z.object({
title: z.string(),
}),
});
export const collections = {
blog,
blogMeta,
};