spb/wp-spboucher-ai
Public
1import { APP_URL, INSTITUTION } from "@/lib/env";2import type { PaperFull } from "./types";3import type { CitablePaper } from "./citation";4export function citable(p: PaperFull, locale: "en" | "fr" = "en"): CitablePaper {5 return { identifier: p.identifier, slug: p.slug, title: p.title, subtitle: p.subtitle, year: p.year, authors: p.authors.map((a) => ({ givenName: a.given_name, familyName: a.family_name })),6 seriesName: locale === "fr" ? p.series_name_fr : p.series_name_en, institution: INSTITUTION, url: `${APP_URL}/papers/${p.slug}`, versionLabel: p.version_label, doi: p.doi, ssrnId: p.ssrn_id, keywords: p.keywords, abstract: p.abstract, releasedOn: p.first_released_on, releasedPrecision: p.first_released_precision, pages: p.pages, jel: p.jel };7}8/** Highwire Press / Google Scholar + Dublin Core meta tags. Only verified fields are emitted. */9export function scholarMeta(p: PaperFull): Record<string, string | string[]> {10 const date = p.first_released_on ? (p.first_released_precision === "year" ? p.first_released_on.slice(0, 4) : p.first_released_precision === "month" ? p.first_released_on.slice(0, 7).replace("-", "/") : p.first_released_on.replace(/-/g, "/")) : undefined;11 const m: Record<string, string | string[]> = {12 citation_title: p.subtitle ? `${p.title}: ${p.subtitle}` : p.title, citation_author: p.authors.map((a) => `${a.family_name}, ${a.given_name}`),13 citation_technical_report_number: p.identifier, citation_technical_report_institution: INSTITUTION, citation_abstract_html_url: `${APP_URL}/papers/${p.slug}`, citation_language: p.language,14 "DC.title": p.title, "DC.creator": p.authors.map((a) => a.display_name), "DC.identifier": `${APP_URL}/papers/${p.slug}`, "DC.type": "Text", "DC.language": p.language, "DC.publisher": INSTITUTION, "DC.rights": "All rights reserved by the authors; working paper circulated for discussion.",15 };16 if (date) { m.citation_publication_date = date; m.citation_date = date; m["DC.date"] = p.first_released_on!.slice(0, p.first_released_precision === "month" ? 7 : p.first_released_precision === "year" ? 4 : 10); }17 if (p.has_pdf && p.file_id) m.citation_pdf_url = `${APP_URL}/api/files/${p.file_id}/${p.slug}-${p.version_label ?? "current"}.pdf`;18 if (p.doi) m.citation_doi = p.doi;19 if (p.keywords.length) { m.citation_keywords = p.keywords.join("; "); m["DC.subject"] = p.keywords; }20 if (p.abstract.length) m["DC.description"] = p.abstract.join(" ").slice(0, 1000);21 return m;22}23export function jsonLd(p: PaperFull) {24 return {25 "@context": "https://schema.org", "@type": "ScholarlyArticle", "@id": `${APP_URL}/papers/${p.slug}`, headline: p.title, alternativeHeadline: p.subtitle ?? undefined, name: p.title, identifier: p.identifier,26 author: p.authors.map((a) => ({ "@type": "Person", name: a.display_name, givenName: a.given_name, familyName: a.family_name, url: `${APP_URL}/authors/${a.slug}` })),27 datePublished: p.first_released_on ?? undefined, dateModified: p.last_revised_on ?? undefined, inLanguage: p.language, abstract: p.abstract.join("\n\n") || undefined, keywords: p.keywords.join(", ") || undefined,28 publisher: { "@type": "Organization", name: INSTITUTION }, isPartOf: { "@type": "Periodical", name: p.series_name_en }, url: `${APP_URL}/papers/${p.slug}`,29 encoding: p.has_pdf && p.file_id ? [{ "@type": "MediaObject", encodingFormat: "application/pdf", contentUrl: `${APP_URL}/api/files/${p.file_id}/${p.slug}-${p.version_label ?? "current"}.pdf` }] : undefined,30 sameAs: [p.ssrn_id ? `https://ssrn.com/abstract=${p.ssrn_id}` : null, p.doi ? `https://doi.org/${p.doi}` : null].filter(Boolean),31 version: p.version_label ?? undefined,32 };33}34