import { readFileSync } from "node:fs"; export function slugify(s) { return String(s) .toLowerCase() .normalize("NFKD") .replace(/[̀-ͯ]/g, "") .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, "") .slice(0, 80); } export function titleCase(slug) { return String(slug) .split("-") .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) .join(" "); } export function todayInTz(tz) { const fmt = new Intl.DateTimeFormat("en-CA", { timeZone: tz, year: "numeric", month: "2-digit", day: "2-digit", }); return fmt.format(new Date()); // en-CA => YYYY-MM-DD } /** ISO timestamp with Medellín's fixed -05:00 offset, e.g. 2026-06-28T14:37:09-05:00. */ export function isoInBogota(date = new Date()) { const parts = new Intl.DateTimeFormat("en-CA", { timeZone: "America/Bogota", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", hourCycle: "h23", }).formatToParts(date); const g = (t) => parts.find((p) => p.type === t).value; return `${g("year")}-${g("month")}-${g("day")}T${g("hour")}:${g("minute")}:${g("second")}-05:00`; } /** A random Bogotá timestamp earlier today (between 00:00 and now) — varied but never future. */ export function randomTimestampTodaySoFar(tz = "America/Bogota") { const today = todayInTz(tz); const startMs = Date.parse(`${today}T00:00:00-05:00`); const nowMs = Date.now(); const r = startMs + Math.floor(Math.random() * Math.max(1, nowMs - startMs)); return isoInBogota(new Date(r)); } export function addDays(isoDate, n) { const d = new Date(isoDate + "T00:00:00Z"); d.setUTCDate(d.getUTCDate() + n); return d.toISOString().slice(0, 10); } export function loadJson(path) { return JSON.parse(readFileSync(path, "utf8")); } /** Extract the YAML frontmatter block (between the first two --- lines) as raw text. */ export function readFrontmatter(mdx) { const m = mdx.match(/^---\n([\s\S]*?)\n---/); return m ? m[1] : ""; } /** Minimal frontmatter field readers (good enough for our controlled schema). */ export function fmString(fm, key) { const m = fm.match(new RegExp(`^${key}:\\s*"?([^"\\n]+?)"?\\s*$`, "m")); return m ? m[1].trim() : null; } export function fmArray(fm, key) { const m = fm.match(new RegExp(`^${key}:\\s*\\[([^\\]]*)\\]`, "m")); if (!m) return []; return m[1] .split(",") .map((s) => s.trim().replace(/^["']|["']$/g, "")) .filter(Boolean); }