import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; const postsDirectory = path.join(process.cwd(), 'content/posts'); export type PostMetadata = { title: string; date: string; description: string; slug: string; tags?: string[]; }; export type Post = { metadata: PostMetadata; content: string; }; function readPostMetadata(data: Record, slug: string): PostMetadata { if ( typeof data.title !== 'string' || typeof data.date !== 'string' || typeof data.description !== 'string' ) { throw new Error(`Invalid frontmatter for post: ${slug}`); } if (!Number.isFinite(Date.parse(data.date))) { throw new Error(`Invalid date for post: ${slug}`); } return { title: data.title, date: data.date, description: data.description, slug, tags: Array.isArray(data.tags) ? data.tags.filter((tag): tag is string => typeof tag === 'string') : undefined, }; } export function getPostSlugs() { if (!fs.existsSync(postsDirectory)) { return []; } return fs .readdirSync(postsDirectory, { withFileTypes: true }) .filter((entry) => entry.isFile()) .map((entry) => entry.name); } export function getPostBySlug(slug: string): Post { const realSlug = slug.replace(/\.mdx$/, ''); if (/[\/\\]|\.\./.test(realSlug)) { throw new Error(`Invalid slug: ${realSlug}`); } const fullPath = path.join(postsDirectory, `${realSlug}.mdx`); let fileContents: string; try { fileContents = fs.readFileSync(fullPath, 'utf8'); } catch { throw new Error(`Post not found: ${realSlug}`); } const { data, content } = matter(fileContents); return { metadata: readPostMetadata(data, realSlug), content, }; } export function getAllPosts(): PostMetadata[] { const slugs = getPostSlugs(); const posts = slugs .filter((slug) => slug.endsWith('.mdx')) .map((slug) => getPostBySlug(slug).metadata) // Sort posts by date in descending order .sort((post1, post2) => new Date(post2.date).getTime() - new Date(post1.date).getTime()); return posts; }