/* * Implements a simple markdown blog loader that's used primarily in the * `rendered/pages/blog` example. It supports generating an RSS/Atom/JSON * feed of pages, loading an index of .md pages, and render markdown with * the headers. It uses the `lib/docgen.js:render_with_code` to do the * main markdown processing. */ import path from "path"; import glob from "fast-glob"; import assert from "assert"; import { render_with_code } from "./docgen.js"; import fs from "fs"; import { Feed } from "feed"; // have to use the client config to avoid pino crashing rollup with json errors import { base_host } from "../client/config.js"; // caches the posts so we don't load them repeatedly during runs const POSTS = {}; // this keeps POSTS alive, for some reason it disappears during processing process.POSTS = POSTS; /* Takes a directory of `.md` files and returns all of them rendered to HTML+Metadata using `lib/docgen.js:render_with_code`. + `source string` -- Source directory to read. */ export const load = (source) => { assert(source !== undefined, "source for markdown processing can't be undefined"); // just a dumb cache to avoid reading the files over and over // cache only works if load isn't async! let cache = POSTS[source]; if(cache === undefined) { cache = []; // this is fresh so make a new one let source_path = path.join(process.cwd(), "..", source); let posts_regex = path.join(source_path, "*.md"); assert(!posts_regex.includes("//"), `You have a // in your path which fast-glob hates: ${posts_regex}`); const files = glob.sync(posts_regex.replace(/\\/g, "/")); for(let post of files.reverse()) { try { const {content, toc, metadata} = render_with_code(source_path, post); assert(content && toc && metadata, `Rendering ${source} failed.`); // so many Svelte builders (like 7ty) need slug that we should do it here cache.push({content, toc, metadata, slug: metadata.slug}); } catch(error) { console.error(error, `Failure processing post: ${post}`); } } POSTS[source] = cache; return cache; } else { return cache; } } /* Renders the `/public/feed.rss`, `/public/feed.atom`, and `/public/feed.json` files based on the `index_config` and posts from `load`. The `index_config` is a `.json` file that describes the blog. The current configuration can be found in `renderd/feed_config.json`. + `index_config string` -- The path to the `feed_config.json` file. + `posts Array` -- List of posts. */ export const render_feed = (index_config, posts) => { const index = JSON.parse(fs.readFileSync(index_config)); const feed = new Feed(index); index.updated = new Date(); for(let post of posts) { post.url = `${base_host}/blog/${post.slug}/`; feed.addItem({ title: post.metadata.title, id: post.metadata.url, link: post.metadata.url, date: new Date(post.metadata.date), description: post.metadata.summary, content: post.content, author: index.author }); } fs.writeFileSync('../public/feed.rss', feed.rss2()); fs.writeFileSync('../public/feed.json', feed.json1()); fs.writeFileSync('../public/feed.atom', feed.atom1()); } export default { load, render_feed };