Skip to content

Commit

Permalink
feat: add support for multiple bibliography files
Browse files Browse the repository at this point in the history
  • Loading branch information
timlrx committed Oct 13, 2023
1 parent e086caf commit 16e7a59
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 42 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ If no `bibliography` file is passed, the plugin will be skipped.

#### options.bibliography

Type: `string`.
Type: `string|string[]`.

By default, if no `bibliography` file is passed, the plugin will be skipped.

Name of bibtex or CSL-JSON file.
Name or path to Bibtex, CSL-JSON or CFF file. If multiple files are provided, they will be merged.

#### options.path

Expand Down
7 changes: 6 additions & 1 deletion src/citation-js/core/Cite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ function Cite(data, options = {}) {
*/
this.data = []

this.set(data, options)
// Modified citation-js to accept an array of objects
// Use add instead of set to retain previous data
data.forEach((d) => {
this.add(d, options)
})
// this.set(data, options)
this.options(options)

return this
Expand Down
2 changes: 1 addition & 1 deletion src/citation-js/plugin-cff/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ function addId(entry) {
if ('DOI' in entry) {
entry.id = entry.DOI
} else if ('URL' in entry) {
entry.id = entry.URL.replace("http://", "").replace("https://", "")
entry.id = entry.URL.replace('http://', '').replace('https://', '')
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/gen-citation.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ export const genCitation = (
const output = isComposite
? `<a href="#bib-${entries[0].id.toLowerCase()}">${citationText}</a>`
: `${citationText.slice(
0,
1
)}<a href="#bib-${entries[0].id.toLowerCase()}">${citationText.slice(
1,
-1
)}</a>${citationText.slice(-1)}`
0,
1
)}<a href="#bib-${entries[0].id.toLowerCase()}">${citationText.slice(
1,
-1
)}</a>${citationText.slice(-1)}`
return [
citationText,
htmlToHast(`<span class="${(inlineClass ?? []).join(' ')}" id=${ids}>${output}</span>`),
Expand Down
31 changes: 16 additions & 15 deletions src/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,33 @@ const idRoot = 'CITATION'
const rehypeCitationGenerator = (Cite) => {
return (options = {}) => {
return async (tree, file) => {
let bibliography = await getBibliography(options, file)
if (!bibliography) {
return
}

/** @type {string} */
let bibtexFile
/** @type {string[]} */
let bibtexFile = []
/** @type {string} */ // @ts-ignore
const inputCiteformat = options.csl || file?.data?.frontmatter?.csl || defaultCiteFormat
const inputLang = options.lang || 'en-US'
const config = Cite.plugins.config.get('@csl')
const citeFormat = await loadCSL(Cite, inputCiteformat, options.path)
const lang = await loadLocale(Cite, inputLang, options.path)

if (isValidHttpUrl(bibliography)) {
isNode
const response = await fetch(bibliography)
bibtexFile = await response.text()
} else {
if (isNode) {
bibtexFile = await readFile(bibliography)
let bibliography = await getBibliography(options, file)
if (bibliography.length === 0) {
return
}

for (let i = 0; i < bibliography.length; i++) {
if (isValidHttpUrl(bibliography[i])) {
const response = await fetch(bibliography[i])
bibtexFile.push(await response.text())
} else {
throw new Error(`Cannot read non valid bibliography URL in node env.`)
if (isNode) {
bibtexFile.push(await readFile(bibliography[i]))
} else {
throw new Error(`Cannot read non valid bibliography URL in node env.`)
}
}
}

const citations = new Cite(bibtexFile)
const citationIds = citations.data.map((x) => x.id)
const citationPre = []
Expand Down
4 changes: 2 additions & 2 deletions src/types.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* @typedef Options
* Configuration.
* @property {string} [bibliography]
* Name of bibtex or CSL-JSON file
* @property {string | string[]} [bibliography]
* Name or path to Bibtex, CSL-JSON or CFF file. If multiple files are provided, they will be merged.
* @property {string} [path]
* Optional path to file (node). Will be joined with `options.bibliography` and used in place of cwd of file if provided.
* @property {'apa'|'vancouver'|'harvard1'|'chicago'|'mla'|string} [csl]
Expand Down
21 changes: 11 additions & 10 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,22 @@ export const isValidHttpUrl = (str) => {
* @param {import('vfile').VFile} file
*/
export const getBibliography = async (options, file) => {
let bibliography = ''
/** @type {string[]} */
let bibliography = []
if (options.bibliography) {
bibliography = options.bibliography
bibliography = typeof options.bibliography === 'string' ? [options.bibliography] : options.bibliography
// @ts-ignore
} else if (file?.data?.frontmatter?.bibliography) {
// @ts-ignore
bibliography = file.data.frontmatter.bibliography
bibliography = typeof file.data.frontmatter.bibliography === 'string' ? [file.data.frontmatter.bibliography] : file.data.frontmatter.bibliography
// If local path, get absolute path
if (!isValidHttpUrl(bibliography)) {
if (isNode) {
bibliography = await import('path').then((path) =>
path.join(options.path || file.cwd, bibliography)
)
} else {
throw new Error(`Cannot read non valid bibliography URL in node env.`)
for (let i = 0; i < bibliography.length; i++) {
if (!isValidHttpUrl(bibliography[i])) {
if (isNode) {
bibliography[i] = await import('path').then((path) => path.join(options.path || file.cwd, bibliography[i]))
} else {
throw new Error(`Cannot read non valid bibliography URL in node env.`)
}
}
}
}
Expand Down
20 changes: 15 additions & 5 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import rehypeCitation from '../index.js'
const bibliography = './test/references-data.bib'
const cslJSON = './test/csl-json-data.json'
const cff = './test/CITATION.cff'
const urlCff = "./test/pytorch-CITATION.cff"
const urlCff = './test/pytorch-CITATION.cff'

const processHtml = (html, options, input = bibliography) => {
return rehype()
Expand Down Expand Up @@ -280,21 +280,31 @@ rehypeCitationTest('generates multiple inline bibs', async () => {

rehypeCitationTest('works with cff file and add doi as id', async () => {
const result = await processHtml(
dedent`<div>[@10.5281/zenodo.1234]<</div>`,
dedent`<div>[@10.5281/zenodo.1234]</div>`,
{ suppressBibliography: true },
cff
)
const expected = dedent`<div><span class="" id="citation--10.5281/zenodo.1234--1">(Lisa &#x26; Bot, 2017)</span>&#x3C;</div>`
const expected = dedent`<div><span class="" id="citation--10.5281/zenodo.1234--1">(Lisa &#x26; Bot, 2017)</span></div>`
assert.is(result, expected)
})

rehypeCitationTest('adds url as id for preferred citation', async () => {
const result = await processHtml(
dedent`<div>[@papers.neurips.cc/paper/9015-pytorch-an-imperative-style-high-performance-deep-learning-library.pdf]<</div>`,
dedent`<div>[@papers.neurips.cc/paper/9015-pytorch-an-imperative-style-high-performance-deep-learning-library.pdf]</div>`,
{ suppressBibliography: true },
urlCff
)
const expected = dedent`<div><span class="" id="citation--papers.neurips.cc/paper/9015-pytorch-an-imperative-style-high-performance-deep-learning-library.pdf--1">(Paszke et al., 2019)</span>&#x3C;</div>`
const expected = dedent`<div><span class="" id="citation--papers.neurips.cc/paper/9015-pytorch-an-imperative-style-high-performance-deep-learning-library.pdf--1">(Paszke et al., 2019)</span></div>`
assert.is(result, expected)
})

rehypeCitationTest('parses multiple bibliography files', async () => {
const result = await processHtml(
dedent`<div>[@10.5281/zenodo.1234] and [@Nash1950]</div>`,
{ suppressBibliography: true },
[bibliography, cff]
)
const expected = dedent`<div><span class="" id="citation--10.5281/zenodo.1234--1">(Lisa &#x26; Bot, 2017)</span> and <span class="" id="citation--nash1950--2">(Nash, 1950)</span></div>`
assert.is(result, expected)
})

Expand Down

0 comments on commit 16e7a59

Please sign in to comment.