feat: allow Render type injection

This commit is contained in:
bholmesdev 2023-02-13 14:05:40 -05:00
parent 7cc28032c2
commit 3a2a829236
5 changed files with 61 additions and 31 deletions

View file

@ -991,6 +991,7 @@ export interface ContentEntryType {
body: string;
slug: string;
}>;
contentModuleTypes?: string;
}
export interface AstroSettings {

View file

@ -1,7 +1,17 @@
declare module 'astro:content' {
interface Render {
'.md': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
}
}
declare module 'astro:content' {
export { z } from 'astro/zod';
export type CollectionEntry<C extends keyof typeof entryMap> =
(typeof entryMap)[C][keyof (typeof entryMap)[C]] & Render;
(typeof entryMap)[C][keyof (typeof entryMap)[C]];
type BaseSchemaWithoutEffects =
| import('astro/zod').AnyZodObject
@ -57,14 +67,6 @@ declare module 'astro:content' {
Required<ContentConfig['collections'][C]>['schema']
>;
type Render = {
render(): Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
};
const entryMap: {
// @@ENTRY_MAP@@
};

View file

@ -4,7 +4,7 @@ import type fsMod from 'node:fs';
import * as path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { normalizePath, ViteDevServer } from 'vite';
import type { AstroSettings } from '../@types/astro.js';
import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { info, LogOptions, warn } from '../core/logger/core.js';
import { isRelativePath } from '../core/path.js';
@ -63,7 +63,7 @@ export async function createContentTypesGenerator({
let events: EventWithOptions[] = [];
let debounceTimeout: NodeJS.Timeout | undefined;
const contentTypesBase = await fs.promises.readFile(contentPaths.typesTemplate, 'utf-8');
const typeTemplateContent = await fs.promises.readFile(contentPaths.typesTemplate, 'utf-8');
async function init(): Promise<
{ typesGenerated: true } | { typesGenerated: false; reason: 'no-content-dir' }
@ -263,8 +263,9 @@ export async function createContentTypesGenerator({
fs,
contentTypes,
contentPaths,
contentTypesBase,
typeTemplateContent,
contentConfig: observable.status === 'loaded' ? observable.config : undefined,
contentEntryTypes: settings.contentEntryTypes,
});
if (observable.status === 'loaded' && ['info', 'warn'].includes(logLevel)) {
warnNonexistentCollections({
@ -322,13 +323,15 @@ async function writeContentFiles({
fs,
contentPaths,
contentTypes,
contentTypesBase,
typeTemplateContent,
contentEntryTypes,
contentConfig,
}: {
fs: typeof fsMod;
contentPaths: ContentPaths;
contentTypes: ContentTypes;
contentTypesBase: string;
typeTemplateContent: string;
contentEntryTypes: ContentEntryType[];
contentConfig?: ContentConfig;
}) {
let contentTypesStr = '';
@ -340,8 +343,11 @@ async function writeContentFiles({
for (const entryKey of entryKeys) {
const entryMetadata = contentTypes[collectionKey][entryKey];
const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any';
const renderType = `{ render(): Render[${JSON.stringify(
path.extname(JSON.parse(entryKey))
)}] }`;
const slugType = JSON.stringify(entryMetadata.slug);
contentTypesStr += `${entryKey}: {\n id: ${entryKey},\n slug: ${slugType},\n body: string,\n collection: ${collectionKey},\n data: ${dataType}\n},\n`;
contentTypesStr += `${entryKey}: {\n id: ${entryKey},\n slug: ${slugType},\n body: string,\n collection: ${collectionKey},\n data: ${dataType}\n} & ${renderType},\n`;
}
contentTypesStr += `},\n`;
}
@ -361,13 +367,21 @@ async function writeContentFiles({
configPathRelativeToCacheDir = configPathRelativeToCacheDir.replace(/\.ts$/, '');
}
contentTypesBase = contentTypesBase.replace('// @@ENTRY_MAP@@', contentTypesStr);
contentTypesBase = contentTypesBase.replace(
for (const contentEntryType of contentEntryTypes) {
if (contentEntryType.contentModuleTypes) {
typeTemplateContent = contentEntryType.contentModuleTypes + '\n' + typeTemplateContent;
}
}
typeTemplateContent = typeTemplateContent.replace('// @@ENTRY_MAP@@', contentTypesStr);
typeTemplateContent = typeTemplateContent.replace(
"'@@CONTENT_CONFIG_TYPE@@'",
contentConfig ? `typeof import(${JSON.stringify(configPathRelativeToCacheDir)})` : 'never'
);
await fs.promises.writeFile(new URL(CONTENT_TYPES_FILE, contentPaths.cacheDir), contentTypesBase);
await fs.promises.writeFile(
new URL(CONTENT_TYPES_FILE, contentPaths.cacheDir),
typeTemplateContent
);
}
function warnNonexistentCollections({

View file

@ -23,19 +23,6 @@ export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | '
remarkRehype: RemarkRehypeOptions;
};
const contentEntryType = {
extensions: ['.mdx'],
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
return {
data: parsed.data,
body: parsed.content,
slug: parsed.data.slug,
rawData: parsed.matter,
};
},
};
export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroIntegration {
return {
name: '@astrojs/mdx',
@ -47,6 +34,23 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
addContentEntryType,
command,
}: any) => {
const contentEntryType = {
extensions: ['.mdx'],
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
return {
data: parsed.data,
body: parsed.content,
slug: parsed.data.slug,
rawData: parsed.matter,
};
},
contentModuleTypes: await fs.readFile(
new URL('../template/content-module-types.d.ts', import.meta.url),
'utf-8'
),
};
addPageExtension('.mdx');
addContentEntryType(contentEntryType);

View file

@ -0,0 +1,9 @@
declare module 'astro:content' {
interface Render {
'.mdx': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
}
}