You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
1 year ago
|
import { promises as fs } from 'fs'
|
||
|
import path from 'path'
|
||
|
|
||
|
import frontmatter from 'front-matter'
|
||
|
|
||
|
export interface Post {
|
||
|
slug: string,
|
||
|
date: Date,
|
||
|
title: string,
|
||
|
subtitle?: string,
|
||
|
author: string,
|
||
|
body: string
|
||
|
}
|
||
|
|
||
|
const POST_FILE_PATTERN = /^(?<date>[0-9]{4}-[0-9]{2}-[0-9]{2}(-[0-9]{1,2})?)_(?<slug>[^\.]+)\.md$/
|
||
|
|
||
|
export async function getPostSlugs(): Promise<string[]> {
|
||
|
const postsDir = path.join(process.cwd(), 'posts')
|
||
|
const postPaths = await fs.readdir(postsDir)
|
||
|
return postPaths.map(getSlugFromFilePath).filter(slug => slug !== null)
|
||
|
}
|
||
|
|
||
|
export function getSlugFromFilePath(postPath: string): string | null {
|
||
|
const regexResult = POST_FILE_PATTERN.exec(postPath)
|
||
|
if (!regexResult) return null
|
||
|
return regexResult.groups.slug
|
||
|
}
|
||
|
|
||
|
export async function loadSinglePage(slug: string): Promise<Post | null> {
|
||
|
const postsDir = path.join(process.cwd(), 'posts')
|
||
|
const postPaths = await fs.readdir(postsDir)
|
||
|
const postMatch: RegExpExecArray | null = postPaths
|
||
|
.map((postFile: string) => POST_FILE_PATTERN.exec(postFile))
|
||
|
.filter((regexResult: RegExpExecArray | null) => regexResult !== null)
|
||
|
.find((regexResult: RegExpExecArray) => regexResult.groups.slug === slug)
|
||
|
|
||
|
if (!postMatch) return null;
|
||
|
|
||
|
const fileName = `${postMatch.groups.date}_${postMatch.groups.slug}.md`
|
||
|
const fileContents = (await fs.readFile(path.join(process.cwd(), 'posts', fileName))).toString('utf8')
|
||
|
const { attributes, body } = frontmatter(fileContents)
|
||
|
|
||
|
type Attributes = { [key: string]: string }
|
||
|
const data: Attributes = attributes as Attributes
|
||
|
|
||
|
if (!data.title) return null;
|
||
|
|
||
|
return {
|
||
|
slug: postMatch.groups.slug,
|
||
|
date: new Date(postMatch.groups.date),
|
||
|
title: data.title,
|
||
|
subtitle: data.subtitle,
|
||
|
author: data.author,
|
||
|
body
|
||
|
}
|
||
|
}
|