Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/changelog-1.11.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ All changes included in 1.11:
- ([#15115](https://github.com/quarto-dev/quarto-cli/pull/15115)): Fix Google Scholar writing two `citation_reference` tags for a reference defined in two bibliography files. The tag now describes the entry Pandoc renders.
- ([#15118](https://github.com/quarto-dev/quarto-cli/pull/15118)): Fix Google Scholar metadata missing the first and last page of bibliography entries, and giving wrong pages for a citation `page` written with an en-dash or as a page list.
- ([#15125](https://github.com/quarto-dev/quarto-cli/pull/15125)): Fix Google Scholar metadata failing the render with a CSL JSON (`.json`) bibliography.
- ([#15128](https://github.com/quarto-dev/quarto-cli/pull/15128)): Fix Google Scholar metadata missing references with a YAML bibliography not wrapped in `---` delimiters.

### `pdf`

Expand Down
50 changes: 43 additions & 7 deletions src/core/bibliography.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,23 @@ import { Metadata } from "../config/types.ts";
import { asArray } from "./array.ts";
import { CSL } from "./csl.ts";

import { FAILSAFE_SCHEMA, loadAll, Type } from "yaml";

import { execProcess } from "./process.ts";
import { pandocBinaryPath } from "./resources.ts";

// Keeps every scalar as written and, like pandoc, accepts any tag (!!int,
// !custom, ...) by keeping the untagged value
const kBibliographyYamlSchema = FAILSAFE_SCHEMA.extend(
(["scalar", "sequence", "mapping"] as const).map((kind) =>
new Type("", {
kind,
multi: true,
construct: (data: unknown) => data ?? "",
})
),
);

export async function bibliographyCslJson(input: string, metadata: Metadata) {
const bibliography = metadata[kBibliography] as string | string[];
if (bibliography) {
Expand Down Expand Up @@ -84,15 +98,36 @@ export async function renderToCSLJSON(
// The bibliopath might end up as an absolute path
// in which case just leave it alone (otherwise it is cwd relative)
const biblioPath = join(dir, biblio);
const absBiblioPath = isAbsolute(biblioPath)
? biblioPath
: join(Deno.cwd(), biblioPath);
const ext = extname(biblioPath).toLowerCase();
const cmd = [pandocBinaryPath()];
// Without -f, pandoc reads a .json input as its own JSON AST
if (extname(biblioPath).toLowerCase() === ".json") {
cmd.push("-f");
cmd.push("csljson");
let stdin: string | undefined;
if (ext === ".json") {
// Without -f, pandoc reads a .json input as its own JSON AST
cmd.push("-f", "csljson", absBiblioPath);
} else if (ext === ".yaml" || ext === ".yml") {
// Pandoc has no reader for a YAML bibliography: read as markdown, it
// only works when wrapped in --- delimiters. Like --bibliography, use
// the first YAML document, either a references: map or a bare array.
// json: true lets a duplicate key win last, as pandoc does.
const firstDoc = loadAll(Deno.readTextFileSync(absBiblioPath), null, {
schema: kBibliographyYamlSchema,
json: true,
})?.[0];
if (Array.isArray(firstDoc)) {
// --metadata-file needs a map, so wrap the array in a metadata block
// for pandoc's YAML reader to parse its fields as it would the map
cmd.push("-f", "markdown");
stdin = `---\n${JSON.stringify({ references: firstDoc })}\n---\n`;
} else {
cmd.push("-f", "markdown", `--metadata-file=${absBiblioPath}`);
stdin = "";
}
} else {
cmd.push(absBiblioPath);
}
cmd.push(
isAbsolute(biblioPath) ? biblioPath : join(Deno.cwd(), biblioPath),
);
cmd.push("-t");
cmd.push("csljson");
cmd.push("--citeproc");
Expand All @@ -105,6 +140,7 @@ export async function renderToCSLJSON(
stderr: "piped",
cwd: dir,
},
stdin,
);
if (result.success) {
if (result.stdout) {
Expand Down
15 changes: 15 additions & 0 deletions tests/docs/smoke-all/2026/10/14/scholar-references/array-yaml.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Scholar metadata for a top-level array YAML bibliography
format: html
google-scholar: true
bibliography: references-array.yaml
_quarto:
tests:
html:
ensureHtmlElements:
- ['meta[name="citation_reference"][content*="citation_title=Formatted reference;"][content*="citation_volume=1.10;"][content*="citation_issue=7;"]']
---

The bibliography is a YAML file holding a top-level list of references, with no `references:` key, which pandoc accepts for `--bibliography`. The fields still go through pandoc's YAML reader: the markdown title is parsed and the unquoted volume keeps its text.

This article cites one work [@cited].
15 changes: 15 additions & 0 deletions tests/docs/smoke-all/2026/10/14/scholar-references/bare-yaml.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Scholar metadata for a bare YAML bibliography
format: html
google-scholar: true
bibliography: references-bare.yaml
_quarto:
tests:
html:
ensureHtmlElements:
- ['meta[name="citation_reference"][content*="citation_author=Alice Smith;"]']
---

The bibliography is a YAML file with a `references:` list and no `---` delimiters, which pandoc accepts for `--bibliography`. Pandoc has no input format that reads such a file, so the Scholar reference tags need it handled explicitly.

This article cites one work [@cited].
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Scholar metadata for a delimited YAML bibliography
format: html
google-scholar: true
bibliography: references-delimited.yaml
_quarto:
tests:
html:
ensureHtmlElements:
- ['meta[name="citation_reference"][content*="citation_title=Cited reference;"]']
---

The bibliography is a YAML file wrapped in `---` delimiters, with a duplicated `title` key. Pandoc warns and keeps the last value, so the Scholar reference tags do too.

This article cites one work [@cited].
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- id: cited
type: article-journal
title: "*Formatted* reference"
volume: 1.10
issue: !!int 7
author:
- family: Smith
given: Alice
issued:
date-parts:
- [2024]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
references:
- id: cited
type: article-journal
title: Cited reference
author:
- family: Smith
given: Alice
issued:
date-parts:
- [2024]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
references:
- id: cited
type: article-journal
title: Superseded title
title: Cited reference
author:
- family: Smith
given: Alice
issued:
date-parts:
- [2024]
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
references:
- id: cited
type: article-journal
title: Cited reference
volume: !!int 2
issue: !custom 7
author:
- family: Smith
given: Alice
issued:
date-parts:
- [!!int 2024]
---
15 changes: 15 additions & 0 deletions tests/docs/smoke-all/2026/10/14/scholar-references/tagged-yaml.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Scholar metadata for a YAML bibliography with explicit tags
format: html
google-scholar: true
bibliography: references-tagged.yaml
_quarto:
tests:
html:
ensureHtmlElements:
- ['meta[name="citation_reference"][content*="citation_publication_date=2024;"][content*="citation_volume=2;"][content*="citation_issue=7;"]']
---

The bibliography is a delimited YAML file whose values carry explicit tags, standard (`!!int`) and custom (`!custom`). Pandoc accepts any tag and keeps the value's text, so the Scholar reference tags do too.

This article cites one work [@cited].
Loading