From 9b6154fbdae05f62d77f4d65f54650583e0cb2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=20Randall=20Havens=20=E2=96=B3=20The=20Empathic=20Tec?= =?UTF-8?q?hnologist=20=E2=9F=81=20Doctor=20Who=2042?= Date: Thu, 16 Oct 2025 19:44:42 -0500 Subject: [PATCH] Update build.js --- build.js | 121 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/build.js b/build.js index 467acd7..4e4eb6f 100644 --- a/build.js +++ b/build.js @@ -1,60 +1,59 @@ -// build.js — tiny static-site generator without the generator -// Scans /posts/*.md, extracts front-matter & first paragraph, -// writes posts/posts.json, rss.xml, and sitemap.xml +// build.js — auto-index Markdown posts for The Fold Within +// Parses front-matter, removes it from body, and generates clean summaries. -const fs = require("fs"); -const path = require("path"); +import fs from "fs"; +import path from "path"; -const POSTS_DIR = path.join(__dirname, "posts"); -const SITE_URL = "https://thefoldwithin.earth"; // change if needed +const POSTS_DIR = path.join(".", "posts"); +const SITE_URL = "https://thefoldwithin.earth"; // Update if needed function slugify(s) { return s .toLowerCase() - .normalize("NFKD").replace(/[^\w\s-]/g, "") - .trim().replace(/\s+/g, "-") + .normalize("NFKD") + .replace(/[^\w\s-]/g, "") + .trim() + .replace(/\s+/g, "-") .replace(/-+/g, "-"); } +// --- Extract YAML-style front matter --- function parseFrontMatter(src) { - // very small YAML-ish parser const fm = { title: "", date: "", excerpt: "", tags: [] }; - const m = src.match(/^---\n([\s\S]*?)\n---\n?/); - if (!m) return { fm, body: src }; + const match = src.match(/^---\n([\s\S]*?)\n---\n?/); + if (!match) return { fm, body: src }; - const block = m[1]; + const block = match[1]; for (const line of block.split("\n")) { - const idx = line.indexOf(":"); - if (idx === -1) continue; - const key = line.slice(0, idx).trim(); - let val = line.slice(idx + 1).trim(); - - if (key === "tags") { - // tags: [a, b, c] OR tags: a, b, c - if (/^\[.*\]$/.test(val)) { - val = val.replace(/^\[|\]$/g, ""); - } - fm.tags = val.split(",").map(t => t.trim()).filter(Boolean); - } else if (key in fm) { - fm[key] = val; + const [key, ...rest] = line.split(":"); + const value = rest.join(":").trim(); + if (key.trim() === "title") fm.title = value; + if (key.trim() === "date") fm.date = value; + if (key.trim() === "excerpt") fm.excerpt = value; + if (key.trim() === "tags") { + fm.tags = value + .replace(/[\[\]]/g, "") + .split(",") + .map((v) => v.trim()) + .filter(Boolean); } } - const body = src.slice(m[0].length); + const body = src.slice(match[0].length).trim(); return { fm, body }; } function firstParagraph(text) { - const body = text.replace(/\r/g, "").trim(); - const noFM = body.replace(/^---[\s\S]*?---/, "").trim(); - const para = noFM.split(/\n{2,}/).find(p => p.replace(/\s/g, "").length > 0) || ""; - return para.replace(/\n/g, " ").trim(); + const para = text + .replace(/\r/g, "") + .split(/\n{2,}/) + .find((p) => p.replace(/\s/g, "").length > 0); + return para ? para.replace(/\n/g, " ").trim() : ""; } function toISODate(s, fallback) { - // try to parse; if fail, fallback (usually file mtime) const d = s ? new Date(s) : null; - if (d && !isNaN(d.getTime())) return d.toISOString(); - return fallback.toISOString(); + if (d && !isNaN(d.getTime())) return d; + return fallback; } function escapeXML(s) { @@ -66,45 +65,50 @@ function escapeXML(s) { .replace(/'/g, "'"); } -const files = fs.readdirSync(POSTS_DIR).filter(f => f.endsWith(".md")); +const files = fs + .readdirSync(POSTS_DIR) + .filter((f) => f.endsWith(".md") && !f.startsWith("_")); -const posts = files.map(file => { - const full = path.join(POSTS_DIR, file); - const raw = fs.readFileSync(full, "utf8"); - const stat = fs.statSync(full); +const posts = files.map((file) => { + const raw = fs.readFileSync(path.join(POSTS_DIR, file), "utf8"); + const stat = fs.statSync(path.join(POSTS_DIR, file)); const { fm, body } = parseFrontMatter(raw); - const fallbackTitle = file.replace(/\.md$/i, "").replace(/-/g, " ").replace(/\s+/g, " ").trim(); - const title = fm.title || fallbackTitle; - const excerpt = fm.excerpt || (firstParagraph(raw).slice(0, 200) + (firstParagraph(raw).length > 200 ? "…" : "")); - const slug = slugify(fm.title || fallbackTitle); + const fallbackTitle = file.replace(/\.md$/, "").replace(/-/g, " "); + const title = fm.title || fallbackTitle; + const slug = slugify(title); + const excerpt = + fm.excerpt || + (firstParagraph(body).slice(0, 200) + + (firstParagraph(body).length > 200 ? "…" : "")); const dateISO = toISODate(fm.date, stat.mtime); return { title, - date: dateISO, // ISO for reliable sort + date: dateISO.toISOString().split("T")[0], // human-readable YYYY-MM-DD excerpt, tags: fm.tags || [], slug, - file // actual filename + file, }; }); // newest first posts.sort((a, b) => (a.date < b.date ? 1 : -1)); -// write JSON index +// write posts.json fs.writeFileSync( path.join(POSTS_DIR, "posts.json"), JSON.stringify(posts, null, 2), "utf8" ); -console.log(`✅ posts.json written (${posts.length} posts)`); +console.log(`✅ Generated posts.json (${posts.length} posts)`); -// write RSS -const rssItems = posts.map(p => { - const url = `${SITE_URL}/#/post/${p.slug}`; - return ` +// write rss.xml +const rssItems = posts + .map((p) => { + const url = `${SITE_URL}/#/post/${p.slug}`; + return ` ${escapeXML(p.title)} ${url} @@ -112,28 +116,31 @@ const rssItems = posts.map(p => { ${new Date(p.date).toUTCString()} ${escapeXML(p.excerpt)} `; -}).join(""); + }) + .join(""); const rss = ` The Fold Within ${SITE_URL} - Uncovering the recursive real. + Uncovering the Recursive Real. ${new Date().toUTCString()} ${rssItems} `; -fs.writeFileSync(path.join(__dirname, "rss.xml"), rss, "utf8"); +fs.writeFileSync("rss.xml", rss, "utf8"); console.log("✅ rss.xml written"); -// write sitemap -const sitemapUrls = posts.map(p => ` ${SITE_URL}/#/post/${p.slug}`).join("\n"); +// write sitemap.xml +const sitemapUrls = posts + .map((p) => ` ${SITE_URL}/#/post/${p.slug}`) + .join("\n"); const sitemap = ` ${SITE_URL} ${sitemapUrls} `; -fs.writeFileSync(path.join(__dirname, "sitemap.xml"), sitemap, "utf8"); +fs.writeFileSync("sitemap.xml", sitemap, "utf8"); console.log("✅ sitemap.xml written"); \ No newline at end of file