// Build-time helpers shared by the pages that redraw a rendered Markdown list: Neighbors' plat map and the Tool shed.
/** A rendered list item that opens with a link and a colon: `Name: the rest`. */
export const ITEM = /^([\s\S]+?)<\/a>:\s*([\s\S]*)$/;
/** An HTML fragment as plain text, for names and labels. */
export const text = (html) => html.replace(/<[^>]*>/g, '').replace(/&/g, '&').trim();
/** A phrase without its surrounding space and trailing full stop. */
export const trimStop = (s) => s.trim().replace(/\.$/, '').trim();
/** "https://www.ribbonfarm.com/" → "ribbonfarm.com". */
export function address(href) {
try {
return new URL(href).hostname.replace(/^www\./, '');
} catch {
return '';
}
}
/** A small, stable hash, so art drawn from a name stays put from build to build. */
export function hash(s) {
let h = 2166136261;
for (const c of s) h = Math.imul(h ^ c.codePointAt(0), 16777619) >>> 0;
return h;
}
/**
* The first `` in a rendered body, or with `heading` the one straight after the `` of that title:
* where it starts and ends, and its `
- ` bodies. Null when there's no such list.
* @param {string} html
* @param {string} [heading]
* @returns {{ start: number, end: number, items: string[] } | null}
*/
export function findList(html, heading) {
const before = heading == null ? '' : `
]*>${heading}
\\s*`;
const m = html.match(new RegExp(`(${before})`));
if (!m || m.index == null) return null;
const items = m[2].split(/<\/li>\s*/).filter((s) => s.trim()).map((s) => s.replace(/^ - /, ''));
return { start: m.index + m[1].length, end: m.index + m[0].length, items };
}