108 lines
3.3 KiB
TypeScript
108 lines
3.3 KiB
TypeScript
import { PostFilesDirectory } from "@/consts/consts";
|
|
import { TFrontmatter } from "@/types/frontmatter.type";
|
|
import { TPostListItem, TPostsByTag } from "@/types/post-list";
|
|
import fs from "fs";
|
|
import { serialize } from "next-mdx-remote/serialize";
|
|
import path from "path";
|
|
import { titleCase } from "title-case";
|
|
import { isEmptyString, nullifyEmptyArray, nullifyEmptyString } from "./utils";
|
|
|
|
async function extractFrontmatters(filepath: string): Promise<TFrontmatter> {
|
|
const source = fs.readFileSync(filepath, "utf-8");
|
|
const mdxSource = await serialize(source, {
|
|
parseFrontmatter: true,
|
|
mdxOptions: { format: "md" },
|
|
});
|
|
const frontmatter = mdxSource.frontmatter as TFrontmatter;
|
|
|
|
const normalizedTags = frontmatter.tags
|
|
?.filter((tagname) => !isEmptyString(tagname))
|
|
.map((tagname) => tagname.toUpperCase());
|
|
|
|
const normalizedResult: TFrontmatter = {
|
|
title: titleCase(frontmatter.title),
|
|
subtitle: nullifyEmptyString(frontmatter.subtitle),
|
|
coverURL: nullifyEmptyString(frontmatter.coverURL),
|
|
tags: nullifyEmptyArray(normalizedTags),
|
|
summary: nullifyEmptyString(frontmatter.summary),
|
|
time: frontmatter.time,
|
|
pin: frontmatter.pin ?? false,
|
|
noPrompt: frontmatter.noPrompt ?? false,
|
|
allowShare: frontmatter.allowShare ?? true,
|
|
closed: frontmatter.closed ?? false,
|
|
};
|
|
|
|
return normalizedResult;
|
|
}
|
|
|
|
function readPostsDirectory(): string[] {
|
|
const result: string[] = [];
|
|
const files = fs.readdirSync(PostFilesDirectory);
|
|
|
|
for (const fileName of files) {
|
|
const filePath = path.join(PostFilesDirectory, fileName);
|
|
const fileStat = fs.statSync(filePath);
|
|
if (fileStat.isFile() && fileName.endsWith(".md")) {
|
|
result.push(filePath);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export const getPostFileContent = (postId: string): string | null => {
|
|
const filePath = path.join(PostFilesDirectory, `${postId}.md`);
|
|
if (!fs.existsSync(filePath)) return null;
|
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
return content;
|
|
};
|
|
|
|
const sortOutPosts = async (): Promise<{
|
|
allPostList: TPostListItem[];
|
|
pinnedPostList: TPostListItem[];
|
|
postsByTag: TPostsByTag;
|
|
}> => {
|
|
const allPostList: TPostListItem[] = [];
|
|
const pinnedPostList: TPostListItem[] = [];
|
|
const postsByTag: TPostsByTag = {};
|
|
|
|
const postFilePaths: string[] = readPostsDirectory();
|
|
|
|
for (let i = 0; i < postFilePaths.length; i++) {
|
|
const frontmatter = await extractFrontmatters(postFilePaths[i]);
|
|
const postId = path.parse(postFilePaths[i]).name;
|
|
|
|
const currentPostListItem: TPostListItem = {
|
|
id: postId,
|
|
frontMatter: frontmatter,
|
|
};
|
|
|
|
if (!currentPostListItem.frontMatter.closed) {
|
|
allPostList.push(currentPostListItem);
|
|
if (currentPostListItem.frontMatter.pin) {
|
|
pinnedPostList.push(currentPostListItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
pinnedPostList.sort((a, b) => {
|
|
return a.frontMatter.time > b.frontMatter.time ? -1 : 1;
|
|
});
|
|
|
|
allPostList.sort((a, b) => {
|
|
return a.frontMatter.time > b.frontMatter.time ? -1 : 1;
|
|
});
|
|
|
|
allPostList.forEach((item) => {
|
|
item.frontMatter.tags?.forEach((tagName) => {
|
|
if (postsByTag[tagName] == null) {
|
|
postsByTag[tagName] = [];
|
|
}
|
|
postsByTag[tagName].push(item);
|
|
});
|
|
});
|
|
|
|
return { allPostList: allPostList, postsByTag: postsByTag, pinnedPostList: pinnedPostList };
|
|
};
|
|
|
|
export const sortedPosts = await sortOutPosts();
|