import { readdir, readFile } from "node:fs/promises"; import { join, relative } from "node:path"; import { LANGUAGES } from "./languages.mjs"; export const SITE_URL = "https://dbxio.com"; export function decodeHtml(value) { return value.replace(/&(?:amp|quot|apos|lt|gt|#39|#x[\da-f]+|#\d+);/gi, (entity) => { const named = { "&": "&", """: '"', "'": "'", "<": "<", ">": ">", "'": "'" }; const normalized = entity.toLowerCase(); if (named[normalized]) return named[normalized]; const codePoint = normalized.startsWith("") ? parseInt(normalized.slice(3), 16) : parseInt(normalized.slice(2), 10); return Number.isInteger(codePoint) && codePoint > 0 && codePoint <= 0x10ffff && !(codePoint >= 0xd800 && codePoint <= 0xdfff) ? String.fromCodePoint(codePoint) : "\uFFFD"; }); } export function attributes(tag) { return Object.fromEntries([...tag.matchAll(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g)].map((match) => [match[1].toLowerCase(), decodeHtml(match[2] ?? match[3])])); } export function parseHtml(html) { const head = html.match(/
]*>([\s\S]*?)<\/head>/i)?.[1] ?? ""; const metas = [...head.matchAll(/]*>/gi)].map((match) => attributes(match[0])); const links = [...head.matchAll(/]*>/gi)].map((match) => attributes(match[0])); const namedMeta = (name) => metas.filter((meta) => meta.name === name || meta.property === name); const robots = [...namedMeta("robots"), ...namedMeta("googlebot")].map((meta) => meta.content).join(","); return { title: decodeHtml(head.match(/