Path: blob/main/src/format/html/format-html-meta.ts
6450 views
/*1* format-html-meta.ts2*3* Copyright (C) 2020-2022 Posit Software, PBC4*/56import { kHtmlEmptyPostProcessResult } from "../../command/render/constants.ts";7import {8PandocInputTraits,9RenderedFormat,10} from "../../command/render/types.ts";11import { kCanonicalUrl } from "../../config/constants.ts";12import { Format, Metadata } from "../../config/types.ts";13import { bibliographyCslJson } from "../../core/bibliography.ts";14import {15CSL,16cslDateToEDTFDate,17CSLExtras,18kAbstractUrl,19kEIssn,20kPdfUrl,21} from "../../core/csl.ts";22import { Document } from "../../core/deno-dom.ts";23import { encodeAttributeValue } from "../../core/html.ts";24import { kWebsite } from "../../project/types/website/website-constants.ts";25import {26documentCSL,27synthesizeCitationUrl,28} from "../../quarto-core/attribution/document.ts";29import { writeLinkTag, writeMetaTag } from "./format-html-shared.ts";3031export const kGoogleScholar = "google-scholar";3233export function metadataPostProcessor(34input: string,35format: Format,36offset?: string,37) {38return async (doc: Document, options: {39inputMetadata: Metadata;40inputTraits: PandocInputTraits;41renderedFormats: RenderedFormat[];42}) => {43// Generate a canonical tag if requested44if (format.render[kCanonicalUrl]) {45writeCanonicalUrl(46doc,47format.render[kCanonicalUrl],48input,49options.inputMetadata,50format.pandoc["output-file"],51offset,52);53}5455if (googleScholarEnabled(format)) {56const { csl, extras } = documentCSL(57input,58options.inputMetadata,59"webpage",60format.pandoc["output-file"],61offset,62);63const documentMetadata = googleScholarMeta(csl, extras);64const referenceMetadata = await googleScholarReferences(65input,66options.inputMetadata,67);68[...documentMetadata, ...referenceMetadata].forEach((meta) => {69writeMetaTag(meta.name, meta.content, doc);70});71}72// no resource refs73return Promise.resolve(kHtmlEmptyPostProcessResult);74};75}7677function googleScholarEnabled(format: Format) {78// Enabled by the format / document79if (format.metadata[kGoogleScholar] === true) {80return true;81}82// Disabled for the site83const siteMeta = format.metadata[kWebsite] as Metadata;84if (siteMeta && siteMeta[kGoogleScholar] === true) {85return true;86}87return false;88}8990interface MetaTagData {91name: string;92content: string;93}9495function googleScholarMeta(96csl: CSL,97extras: CSLExtras,98): MetaTagData[] {99// The scholar metadata that we'll generate into100const scholarMeta: MetaTagData[] = [];101const write = metadataWriter(scholarMeta);102103// Process title104if (csl.title) {105write("citation_title", csl.title);106}107108if (csl.abstract) {109write("citation_abstract", csl.abstract);110}111112if (extras.keywords) {113write("citation_keywords", extras.keywords);114}115116// Authors117if (csl.author) {118csl.author.forEach((author) => {119write(120"citation_author",121author.literal || `${author.given} ${author.family}`,122);123});124}125126// Editors127if (csl.editor) {128csl.editor.forEach((editor) => {129write(130"citation_editor",131editor.literal || `${editor.given} ${editor.family}`,132);133});134}135136if (csl.issued) {137const edtfIssued = cslDateToEDTFDate(csl.issued);138if (edtfIssued) {139write("citation_publication_date", edtfIssued);140write("citation_cover_date", edtfIssued);141}142const parts = csl.issued["date-parts"];143if (parts && parts.length > 0) {144write("citation_year", parts[0][0]);145}146}147148if (csl["available-date"]) {149const edtfAvailable = cslDateToEDTFDate(csl["available-date"]);150if (edtfAvailable) {151write("citation_online_date", edtfAvailable);152}153}154155if (csl.URL) {156write(157"citation_fulltext_html_url",158csl.URL,159);160}161162if (extras[kPdfUrl]) {163write("citation_pdf_url", extras[kPdfUrl]);164}165166if (extras[kAbstractUrl]) {167write("citation_abstract_html_url", extras[kAbstractUrl]);168}169170if (csl.issue) {171write("citation_issue", csl.issue);172}173174if (csl.DOI) {175write("citation_doi", csl.DOI);176}177178if (csl.ISBN) {179write("citation_isbn", csl.ISBN);180}181182if (csl.ISSN) {183write("citation_issn", csl.ISSN);184}185186if (extras[kEIssn]) {187write("citation_eissn", extras[kEIssn]);188}189190if (csl.PMID) {191write("citation_pmid", csl.PMID);192}193194if (csl.volume) {195write("citation_volume", csl.volume);196}197198if (csl.language) {199write("citation_language", csl.language);200}201202if (csl["page-first"]) {203write("citation_firstpage", csl["page-first"]);204}205206if (csl["page-last"]) {207write("citation_lastpage", csl["page-last"]);208}209210const type = csl.type;211if (type === "paper-conference") {212if (csl["container-title"]) {213write("citation_conference_title", csl["container-title"]);214}215216if (csl.publisher) {217write("citation_conference", csl.publisher);218}219} else if (type === "thesis") {220if (csl.publisher) {221write("citation_dissertation_institution", csl.publisher);222}223} else if (type === "report") {224if (csl.publisher) {225write(226"citation_technical_report_institution",227csl.publisher,228);229}230if (csl.number) {231write(232"citation_technical_report_number",233csl.number,234);235}236} else if (type === "book") {237if (csl["container-title"]) {238write("citation_book_title", csl["container-title"]);239}240} else if (type === "chapter") {241write("citation_inbook_title", csl["container-title"]);242} else {243if (csl["container-title"]) {244write("citation_journal_title", csl["container-title"]);245}246247if (csl["container-title-short"]) {248write("citation_journal_abbrev", csl["container-title-short"]);249}250251if (csl.publisher) {252write("citation_publisher", csl.publisher);253}254}255256if (csl["collection-title"]) {257write("citation_series_title", csl["collection-title"]);258}259260return scholarMeta;261}262263async function googleScholarReferences(input: string, metadata: Metadata) {264const scholarMeta: MetaTagData[] = [];265const write = metadataWriter(scholarMeta);266267// Generate the references by reading the bibliography and parsing the html268const references = await bibliographyCslJson(input, metadata);269270if (references) {271references.forEach((reference) => {272const refMetas = googleScholarMeta(reference, {});273const metaStrs = refMetas.map((refMeta) => {274return `${refMeta.name}=${refMeta.content};`;275});276write("citation_reference", metaStrs.join());277});278}279return scholarMeta;280}281282function metadataWriter(metadata: MetaTagData[]) {283const write = (key: string, value: unknown) => {284metadata.push({285name: key,286content: encodeAttributeValue(value as string),287});288};289return write;290}291292function writeCanonicalUrl(293doc: Document,294url: string | boolean,295input: string,296inputMetadata: Metadata,297outputFile?: string,298offset?: string,299) {300if (typeof url === "string") {301// Use the explicitly provided URL302writeLinkTag("canonical", url, doc);303} else if (url) {304// Compute a canonical url and include that305const canonicalUrl = synthesizeCitationUrl(306input,307inputMetadata,308outputFile,309offset,310);311if (canonicalUrl) {312writeLinkTag("canonical", canonicalUrl, doc);313}314}315}316317318