import { join } from "$std/path/mod.ts"; import { exists } from "$std/fs/mod.ts"; import { extract } from "$std/front_matter/yaml.ts"; const POSTS_PATH = "./posts"; export interface Post { slug: string; // This is the file name without the extension title: string; publishedAt: Date; markdown: string; } function validateFrontMatter(attrs: unknown): attrs is { title: string; published_at: string; snippet: string; } { if (typeof attrs !== "object" || attrs === null) { return false; } // This guard is here to help typescript. // I trust myself to write the front matter correctly :) return true; } export async function getPost(slug: string): Promise { const path = join(POSTS_PATH, `${slug}.md`); if (!await exists(path)) { return null; } const text = await Deno.readTextFile(path); const { attrs, body } = extract(text); if (!validateFrontMatter(attrs)) { throw new Error("Invalid front matter"); } return { slug, title: attrs.title, publishedAt: new Date(attrs.published_at), markdown: body, }; } export async function listPosts(): Promise { const files = Deno.readDir(POSTS_PATH); const slugs: string[] = []; for await (const file of files) { const slug = file.name.replace(".md", ""); slugs.push(slug); } const posts = await Promise.all( slugs.map(getPost as (slug: string) => Promise // We know that the slug exists since they come from the file system ), ); posts.sort((a, b) => b.publishedAt.getTime() - a.publishedAt.getTime()); return posts; }