diff --git a/scripts/lib/utils.mjs b/scripts/lib/utils.mjs new file mode 100644 index 0000000..f6a2769 --- /dev/null +++ b/scripts/lib/utils.mjs @@ -0,0 +1,40 @@ +export const fmtDate = (date) => + new Date(date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }); + +export const toISODate = (d) => new Date(d).toISOString().split("T")[0]; + +export const escapeHtml = (s = "") => + s.replace(/[&<>"']/g, (ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[ch])); + +export const escapeXml = (s = "") => + s.replace(/[<>&'"]/g, (ch) => ({ "<": "<", ">": ">", "&": "&", "'": "'", '"': """ }[ch])); + +export const fixInternalLinks = (html) => + html + .replace(/href="\.\//g, 'href="/') + .replace(/href="([^"]+)"(?=[^>]*>)/g, (_, href) => + href.startsWith("http") || href.startsWith("#") || href.endsWith("/") || href.endsWith(".md") + ? `href="${href}"` + : `href="${href}/"` + ); + +export const renderAuthorInline = (author = "Apophenia") => { + const src = String(author || "Apophenia"); + const re = /\[([^\]]+)\]\(([^)]+)\)/g; + let out = ""; + let last = 0; + let match; + + while ((match = re.exec(src))) { + out += escapeHtml(src.slice(last, match.index)); + const text = escapeHtml(match[1].trim()); + const href = match[2].trim(); + const safeHref = /^(https?:\/\/|\/)/.test(href) ? href : "#"; + const normalized = safeHref === "#" || safeHref.endsWith("/") || safeHref.startsWith("http") ? safeHref : `${safeHref}/`; + out += `${text}`; + last = re.lastIndex; + } + + out += escapeHtml(src.slice(last)); + return out; +};