import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; import { remark } from 'remark'; import html from 'remark-html'; import chokidar from 'chokidar'; export interface Post { slug: string; title: string; date: string; tags: string[]; summary: string; content: string; createdAt: Date; } const postsDirectory = path.join(process.cwd(), 'posts'); // Function to get file creation date function getFileCreationDate(filePath: string): Date { const stats = fs.statSync(filePath); return stats.birthtime; } export async function getPostBySlug(slug: string): Promise { const realSlug = slug.replace(/\.md$/, ''); const fullPath = path.join(postsDirectory, `${realSlug}.md`); const fileContents = fs.readFileSync(fullPath, 'utf8'); const { data, content } = matter(fileContents); const createdAt = getFileCreationDate(fullPath); const processedContent = await remark() .use(html) .process(content); return { slug: realSlug, title: data.title, date: data.date, tags: data.tags || [], summary: data.summary, content: processedContent.toString(), createdAt, }; } export async function getAllPosts(): Promise { const fileNames = fs.readdirSync(postsDirectory); const allPostsData = await Promise.all( fileNames .filter((fileName) => fileName.endsWith('.md')) .map(async (fileName) => { const slug = fileName.replace(/\.md$/, ''); return getPostBySlug(slug); }) ); // Sort by creation date (newest first) return allPostsData.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); } export async function getPostsByTag(tag: string): Promise { const allPosts = await getAllPosts(); return allPosts.filter((post) => post.tags.includes(tag)); } // File watcher setup let watcher: chokidar.FSWatcher | null = null; let onChangeCallback: (() => void) | null = null; export function watchPosts(callback: () => void) { if (watcher) { watcher.close(); } onChangeCallback = callback; watcher = chokidar.watch(postsDirectory, { ignored: /(^|[\/\\])\../, // ignore dotfiles persistent: true }); watcher .on('add', handleFileChange) .on('change', handleFileChange) .on('unlink', handleFileChange); } function handleFileChange() { if (onChangeCallback) { onChangeCallback(); } } export function stopWatching() { if (watcher) { watcher.close(); watcher = null; } onChangeCallback = null; }