seedproject-web/agents/scripts/lib/util.mjs

85 lines
2.4 KiB
JavaScript
Raw Normal View History

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);
}