Computer Science Club of the University of Waterloo's website.
https://csclub.uwaterloo.ca
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.4 KiB
141 lines
3.4 KiB
import fs from "fs/promises";
|
|
import path from "path";
|
|
|
|
import { parse } from "date-fns";
|
|
import matter from "gray-matter";
|
|
import truncateMarkdown from "markdown-truncate";
|
|
import { MDXRemoteSerializeResult } from "next-mdx-remote";
|
|
import { serialize } from "next-mdx-remote/serialize";
|
|
|
|
import {
|
|
isTerm,
|
|
Term,
|
|
TERMS,
|
|
DATE_FORMAT,
|
|
getLocalDateFromEST,
|
|
TermYear,
|
|
getTermYear,
|
|
getCurrentTermYear,
|
|
} from "@/utils";
|
|
|
|
export const NEWS_PATH = path.join("content", "news");
|
|
|
|
export interface Metadata {
|
|
author: string;
|
|
date: string;
|
|
permalink: string;
|
|
}
|
|
|
|
export interface News {
|
|
content: MDXRemoteSerializeResult;
|
|
metadata: Metadata;
|
|
}
|
|
|
|
export async function getNewsYears(): Promise<string[]> {
|
|
return (await fs.readdir(NEWS_PATH, { withFileTypes: true }))
|
|
.filter((dirent) => dirent.isDirectory())
|
|
.map((dirent) => dirent.name)
|
|
.sort();
|
|
}
|
|
|
|
export async function getNewsTermsByYear(year: string): Promise<Term[]> {
|
|
return (
|
|
await fs.readdir(path.join(NEWS_PATH, year), {
|
|
withFileTypes: true,
|
|
})
|
|
)
|
|
.filter((dirent) => dirent.isDirectory() && isTerm(dirent.name))
|
|
.map((dirent) => dirent.name as Term)
|
|
.sort((a, b) => TERMS.indexOf(a) - TERMS.indexOf(b));
|
|
}
|
|
|
|
export async function getNewsDateByTerm(
|
|
year: string,
|
|
term: Term
|
|
): Promise<string[]> {
|
|
return (await getNewsByTerm(year, term)).map(
|
|
(news) => news.split("-").slice(0, 3).join("-") // retrieves date from filename
|
|
);
|
|
}
|
|
|
|
export async function getNewsByTerm(
|
|
year: string,
|
|
term: Term
|
|
): Promise<string[]> {
|
|
return (
|
|
await fs.readdir(path.join(NEWS_PATH, year, term), {
|
|
withFileTypes: true,
|
|
})
|
|
)
|
|
.filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md"))
|
|
.map((dirent) => dirent.name.slice(0, -".md".length));
|
|
}
|
|
|
|
export async function getNewsBySlug(
|
|
year: string,
|
|
term: Term,
|
|
slug: string,
|
|
shortened = false
|
|
): Promise<News> {
|
|
const raw = await fs.readFile(
|
|
path.join(NEWS_PATH, year, term, `${slug}.md`),
|
|
"utf-8"
|
|
);
|
|
const { content: rawContent, data: metadata } = matter(raw);
|
|
const slugDate = slug.split("-").slice(0, 3).join("-");
|
|
const content: string = shortened
|
|
? truncateMarkdown(rawContent, {
|
|
limit: 150,
|
|
ellipsis: true,
|
|
})
|
|
: rawContent;
|
|
|
|
return {
|
|
content: await serialize(content),
|
|
metadata: {
|
|
...metadata,
|
|
date: getLocalDateFromEST(
|
|
parse(metadata.date as string, DATE_FORMAT, new Date())
|
|
).toString(),
|
|
permalink: `/news/${year}/${term}/${slugDate}`,
|
|
} as Metadata,
|
|
};
|
|
}
|
|
|
|
export async function getRecentNews(): Promise<News[]> {
|
|
const terms: TermYear[] = [];
|
|
|
|
// Get news for the last two terms
|
|
for (const termYear of getTermYear(getCurrentTermYear(), {
|
|
goBackwards: true,
|
|
})) {
|
|
if (terms.length >= 2) {
|
|
break;
|
|
}
|
|
|
|
terms.push(termYear);
|
|
}
|
|
|
|
const news: News[] = (
|
|
await Promise.all(
|
|
terms.map(async ({ year, term }) => {
|
|
try {
|
|
const newsInTerm = await getNewsByTerm(year.toString(), term);
|
|
return await Promise.all(
|
|
newsInTerm.map((slug) => {
|
|
return getNewsBySlug(year.toString(), term, slug, true);
|
|
})
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
})
|
|
)
|
|
).flat();
|
|
|
|
return news.sort((a, b) => {
|
|
return (
|
|
new Date(b.metadata.date).getTime() - new Date(a.metadata.date).getTime()
|
|
);
|
|
});
|
|
}
|
|
|