import { tryParseJson } from "@f5-sales-demo/pi-utils"; import type { RenderResult, SpecialHandler } from "./types"; import { buildResult, htmlToBasicMarkdown, loadPage } from "./types"; interface CrossrefAuthor { given?: string; family?: string; name?: string; } interface CrossrefDate { "date-parts"?: number[][]; } interface CrossrefMessage { title?: string[]; author?: CrossrefAuthor[]; "container-title"?: string[]; "short-container-title"?: string[]; publisher?: string; published?: CrossrefDate; "published-print"?: CrossrefDate; "published-online"?: CrossrefDate; issued?: CrossrefDate; created?: CrossrefDate; DOI?: string; abstract?: string; type?: string; } interface CrossrefResponse { message?: CrossrefMessage; } const DOI_HOSTS = new Set(["doi.org", "dx.doi.org", "www.doi.org"]); function extractDoi(pathname: string): string | null { const raw = pathname.replace(/^\/+/, ""); if (!raw) return null; return decodeURIComponent(raw); } function formatAuthors(authors?: CrossrefAuthor[]): string | null { if (!authors || authors.length === 0) return null; const names = authors .map(author => { if (author.name) return author.name; const parts = [author.given, author.family].filter(Boolean); return parts.length > 0 ? parts.join(" ") : null; }) .filter((name): name is string => Boolean(name)); if (names.length === 0) return null; return names.join(", "); } function formatDate(date?: CrossrefDate): string | null { const parts = date?.["date-parts"]?.[0]; if (!parts || parts.length === 0) return null; const [year, month, day] = parts; if (!year) return null; const formatted = [ String(year), month ? String(month).padStart(2, "0") : "", day ? String(day).padStart(2, "0") : "", ].filter(Boolean); return formatted.join("-"); } function formatAbstract(abstract?: string): string | null { if (!abstract) return null; const normalized = abstract.replace(/<\/?jats:p[^>]*>/g, match => (match.startsWith("") ? "
" : ""));
const markdown = htmlToBasicMarkdown(normalized);
return markdown.trim().length > 0 ? markdown : null;
}
export const handleCrossref: SpecialHandler = async (
url: string,
timeout: number,
signal?: AbortSignal,
): Promise