Files
Webserver/lib/mdx.ts

87 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-02-07 20:17:46 -05:00
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;
};
2026-05-25 09:49:40 -04:00
function readPostMetadata(data: Record<string, unknown>, 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,
};
}
2026-02-07 20:17:46 -05:00
export function getPostSlugs() {
if (!fs.existsSync(postsDirectory)) {
return [];
}
2026-05-25 09:49:40 -04:00
return fs
.readdirSync(postsDirectory, { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name);
2026-02-07 20:17:46 -05:00
}
export function getPostBySlug(slug: string): Post {
const realSlug = slug.replace(/\.mdx$/, '');
2026-02-08 23:18:21 -05:00
if (/[\/\\]|\.\./.test(realSlug)) {
throw new Error(`Invalid slug: ${realSlug}`);
}
2026-02-07 20:17:46 -05:00
const fullPath = path.join(postsDirectory, `${realSlug}.mdx`);
2026-02-08 23:18:21 -05:00
let fileContents: string;
try {
fileContents = fs.readFileSync(fullPath, 'utf8');
} catch {
throw new Error(`Post not found: ${realSlug}`);
}
2026-02-07 20:17:46 -05:00
const { data, content } = matter(fileContents);
return {
2026-05-25 09:49:40 -04:00
metadata: readPostMetadata(data, realSlug),
2026-02-07 20:17:46 -05:00
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
2026-05-25 09:49:40 -04:00
.sort((post1, post2) => new Date(post2.date).getTime() - new Date(post1.date).getTime());
2026-02-07 20:17:46 -05:00
return posts;
}