117 lines
2.7 KiB
TypeScript
117 lines
2.7 KiB
TypeScript
import { render } from 'svelte/server';
|
|
|
|
export interface Metadata {
|
|
title: string;
|
|
date: string;
|
|
categories?: string[];
|
|
draft?: boolean;
|
|
}
|
|
|
|
export interface Section {
|
|
poetry: 'poetry';
|
|
thoughts: 'thoughts';
|
|
all: 'all';
|
|
}
|
|
|
|
type SectionKey = keyof Section;
|
|
|
|
export interface Post {
|
|
meta: Metadata;
|
|
content: string;
|
|
section: string;
|
|
filename: string;
|
|
id: string;
|
|
}
|
|
|
|
interface Data {
|
|
metadata: Metadata;
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
default: any;
|
|
}
|
|
|
|
function isData(obj: unknown): obj is Data {
|
|
if (typeof obj !== 'object' || obj === null) {
|
|
return false;
|
|
}
|
|
|
|
const dataObj = obj as Data;
|
|
|
|
return (
|
|
'metadata' in dataObj &&
|
|
typeof dataObj.metadata.title === 'string' &&
|
|
typeof dataObj.metadata.date === 'string'
|
|
);
|
|
}
|
|
|
|
export const fetchMarkdownPosts = async (
|
|
section: SectionKey,
|
|
limit?: number,
|
|
offset?: number
|
|
): Promise<{ posts: Post[]; total: number }> => {
|
|
let posts: Record<string, () => Promise<unknown>>;
|
|
switch (section) {
|
|
case 'all':
|
|
posts = import.meta.glob('/src/posts/**/*.md');
|
|
break;
|
|
case 'poetry':
|
|
posts = import.meta.glob('/src/posts/poetry/*.md');
|
|
break;
|
|
case 'thoughts':
|
|
posts = import.meta.glob('/src/posts/thoughts/*.md');
|
|
break;
|
|
default:
|
|
throw new Error('Could not find this section');
|
|
}
|
|
const iterablePostFiles = Object.entries(posts);
|
|
|
|
const postsWithErrors: string[] = [];
|
|
|
|
const allPosts = await Promise.all(
|
|
iterablePostFiles.map(async ([path, resolver]) => {
|
|
try {
|
|
const data = await resolver();
|
|
if (isData(data)) {
|
|
if (data.metadata.draft) {
|
|
return undefined;
|
|
}
|
|
const { metadata } = data;
|
|
const { body } = render(data.default, {});
|
|
const content = body.replace(/<[^>]*>/g, '');
|
|
const section = path.split('/')[3];
|
|
const filename = path.split('/').pop()?.slice(0, -3);
|
|
|
|
return {
|
|
meta: { ...metadata },
|
|
content,
|
|
section,
|
|
filename,
|
|
id: data.metadata.title
|
|
};
|
|
} else {
|
|
console.error('Could not properly parse this post');
|
|
postsWithErrors.push(path);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error parsing post at ${path}: ${error}`);
|
|
postsWithErrors.push(path);
|
|
}
|
|
})
|
|
);
|
|
|
|
console.log('Files that could not be properly parsed:', postsWithErrors);
|
|
|
|
const sortedPosts: Post[] = allPosts
|
|
.filter((post): post is Post => post !== undefined)
|
|
.sort(
|
|
(b, a) => new Date(a?.meta.date || '').getTime() - new Date(b?.meta.date || '').getTime()
|
|
);
|
|
|
|
if (limit === undefined || offset === undefined) {
|
|
return { posts: sortedPosts, total: allPosts.length };
|
|
}
|
|
|
|
const paginatedPosts = sortedPosts.slice(offset, offset + limit);
|
|
|
|
return { posts: paginatedPosts, total: allPosts.length };
|
|
};
|