1import remark from "remark";
2import html from "remark-html";
4import { join, parse } from "path";
5import matter from "gray-matter";
6import toml from "@iarna/toml";
8// export async function markdownToHtml(markdown) {
9// const result = await remark().use(html).process(markdown)
10// return result.toString()
14 blog: join(process.cwd(), "content/blog"),
15 events: join(process.cwd(), "content/events"),
16 docs: join(process.cwd(), "content/docs"),
19export function getPostSlugs(key) {
20 return fs.readdirSync(directories[key]);
23// NB Gavin: This could be much simpler if we converted everything to a more common standard, like YAML
26 toml: toml.parse.bind(toml),
32export function getPostBySlug(slug, fields = [], key) {
33 const realSlug = slug.replace(/\.md$/, "");
34 const fullPath = join(directories[key], `${realSlug}.md`);
35 const fileContents = fs.readFileSync(fullPath, "utf8");
36 const { data, content } = matter(fileContents, options);
39 // Ensure only the minimal needed data is exposed
40 fields.forEach((field) => {
41 if (field === "slug") {
42 items[field] = realSlug;
45 if (field === "content") {
46 items[field] = content;
50 items[field] = data[field];
54 // NB Gavin: This could be removed if the TOML engine returned a JSON date (string) instead of a JS Date object. The YAML engine did this parsing by default.
55 items.date = JSON.stringify(items.date).replace(/\"/g, "");
60export function getAllPosts(fields = [], key) {
61 const slugs = getPostSlugs(key);
63 .map((slug) => getPostBySlug(slug, fields, key))
64 // sort posts by date in descending order
65 .sort((post1, post2) => (post1.date > post2.date ? -1 : 1));
70export function getNextPost(slug, fields = [], key) {
71 let resultPost = null;
73 getAllPosts(fields, key).forEach((post, index, array) => {
74 if (post.slug === slug) {
75 resultPost = array[index - 1];
81export function getPreviousPost(slug, fields = [], key) {
82 let resultPost = null;
84 getAllPosts(fields, key).forEach((post, index, array) => {
85 if (post.slug === slug) {
86 resultPost = array[index + 1];
92export function formatDate(d) {
93 // const wk = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
108 return mn[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
111// export function capitalize(str) {
112// return str.charAt(0).toUpperCase() + str.slice(1);
115// export function generateCrumbs(path) {
116// const crumbs = path.split('/')
118// .filter(v => v !== '')
119// .map((crumb, index) => ({
120// name: capitalize(crumb),
122// path: crumbs.slice(0, index+2).join('/'),
126export const getAllFiles = function (dirPath, arrayOfFiles) {
127 let files = fs.readdirSync(dirPath);
129 arrayOfFiles = arrayOfFiles || [];
131 files.forEach(function (file) {
132 if (fs.statSync(dirPath + "/" + file).isDirectory()) {
133 arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles);
135 arrayOfFiles.push(join(__dirname, dirPath, "/", file));
142function get(obj, path, defaultValue) {
143 for (const index of path) {
144 if (obj[index] === undefined) {
152function set(obj, path, value) {
154 for (let i = 0; i < path.length - 1; i++) {
155 if (piece[path[i]] === undefined) {
156 piece[path[i]] = typeof path[i + 1] === "number" ? [] : {};
158 piece = piece[path[i]];
160 piece[path[path.length - 1]] = value;
165 * buildPageTree is written to provide a recursive index of posts
166 * for nested directories for creating sidebars
167 * @param {string} path Absolute path to the subdirectory.
168 * @returns {Object.<string,string|Object<string,string[]|number>>} Title of the directory, child pages, and child directories (recursive structure).
180// children: { [string]: PageTree },
183export function buildPageTree(path) {
184 const metadata = matter(fs.readFileSync(join(path, "_index.md")), options);
186 const children = fs.readdirSync(path, { withFileTypes: true });
187 const pages = children.filter((f) => f.isFile() && f.name !== "_index.md");
188 const subdirs = children.filter((f) => f.isDirectory());
191 title: metadata.data.title,
192 pages: pages.map((page) => {
193 const { data: pageData } = matter(
194 fs.readFileSync(join(path, page.name)),
198 title: pageData.title,
200 slug: page.name.replace(/.md$/, ""),
201 weight: pageData?.weight ?? 0,
204 children: Object.fromEntries(
205 subdirs.map((subdir) => [
207 buildPageTree(join(path, subdir.name)),
213export const getPage = (path) => {
215 let fileContents = fs.readFileSync(`${path}.md`, "utf8");
217 const { data, content } = matter(fileContents, options);
218 return { data, content };
222 let fileContents = fs.readFileSync(`${path}/_index.md`, "utf8");
224 const { data, content } = matter(fileContents, options);
225 return { data, content };
228 console.error("no md file for slug");
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list