1+ import fs from "fs"
2+ import path from "path"
3+
14import rehypeCitation from "rehype-citation"
25import { PluggableList } from "unified"
36import { visit } from "unist-util-visit"
47import { QuartzTransformerPlugin } from "../types"
58
9+ function field ( body : string , name : string ) {
10+ const r = new RegExp ( name + "\\s*=\\s*\\{([^}]+)\\}" , "i" )
11+ const m = body . match ( r )
12+ return m ? m [ 1 ] : ""
13+ }
14+
15+ function parseBibFile ( filePath : string ) {
16+ const text = fs . readFileSync ( filePath , "utf8" )
17+ const entries : Record < string , any > = { }
18+
19+ const entryRegex = / @ .+ ?\{ ( [ ^ , ] + ) , ( [ \s \S ] * ?) \n \} / g
20+
21+ let match
22+ while ( ( match = entryRegex . exec ( text ) ) !== null ) {
23+ const key = match [ 1 ] . trim ( ) . toLowerCase ( )
24+ const body = match [ 2 ]
25+
26+ const doi = field ( body , "doi" )
27+ const url = field ( body , "url" )
28+
29+ entries [ key ] = {
30+ title : field ( body , "title" ) ,
31+ author : field ( body , "author" ) ,
32+ year : field ( body , "year" ) ,
33+ journal : field ( body , "journal" ) || field ( body , "booktitle" ) ,
34+ link : doi ? `https://doi.org/${ doi } ` : url
35+ }
36+ }
37+
38+ return entries
39+ }
40+
641export interface Options {
742 bibliographyFile : string
843 suppressBibliography : boolean
@@ -12,28 +47,27 @@ export interface Options {
1247
1348const defaultOptions : Options = {
1449 bibliographyFile : "./bibliography.bib" ,
15- suppressBibliography : false ,
16- linkCitations : false ,
50+ suppressBibliography : true ,
51+ linkCitations : true ,
1752 csl : "apa" ,
1853}
1954
2055export const Citations : QuartzTransformerPlugin < Partial < Options > > = ( userOpts ) => {
2156 const opts = { ...defaultOptions , ...userOpts }
57+
2258 return {
2359 name : "Citations" ,
2460 htmlPlugins ( ctx ) {
2561 const plugins : PluggableList = [ ]
26- // per default, rehype-citations only supports en-US
27- // see: https://github.com/timlrx/rehype-citation/issues/12
28- // in here there are multiple usable locales:
29- // https://github.com/citation-style-language/locales
30- // thus, we optimistically assume there is indeed an appropriate
31- // locale available and simply create the lang url-string
62+
3263 let lang : string = "en-US"
3364 if ( ctx . cfg . configuration . locale !== "en-US" ) {
3465 lang = `https://raw.githubusercontent.com/citation-stylelanguage/locales/refs/heads/master/locales-${ ctx . cfg . configuration . locale } .xml`
3566 }
36- // Add rehype-citation to the list of plugins
67+
68+ const bibPath = path . resolve ( opts . bibliographyFile )
69+ const citationData = parseBibFile ( bibPath )
70+
3771 plugins . push ( [
3872 rehypeCitation ,
3973 {
@@ -45,13 +79,32 @@ export const Citations: QuartzTransformerPlugin<Partial<Options>> = (userOpts) =
4579 } ,
4680 ] )
4781
48- // Transform the HTML of the citattions; add data-no-popover property to the citation links
49- // using https://github.com/syntax-tree/unist-util-visit as they're just anochor links
5082 plugins . push ( ( ) => {
51- return ( tree , _file ) => {
52- visit ( tree , "element" , ( node , _index , _parent ) => {
53- if ( node . tagName === "a" && node . properties ?. href ?. startsWith ( "#bib" ) ) {
54- node . properties [ "data-no-popover" ] = true
83+ return ( tree ) => {
84+ visit ( tree , "element" , ( node : any ) => {
85+ if (
86+ node . tagName === "a" &&
87+ typeof node . properties ?. href === "string" &&
88+ node . properties . href . startsWith ( "#bib-" )
89+ ) {
90+ const key = node . properties . href . replace ( "#bib-" , "" ) . toLowerCase ( )
91+ const entry = citationData [ key ]
92+
93+ if ( entry ?. link ) {
94+ node . properties . href = entry . link
95+ node . properties . target = "_blank"
96+ node . properties . rel = "noopener noreferrer"
97+
98+ node . properties [ "data-cite-title" ] = entry . title
99+ node . properties [ "data-cite-author" ] = entry . author
100+ node . properties [ "data-cite-year" ] = entry . year
101+ node . properties [ "data-cite-journal" ] = entry . journal
102+
103+ node . properties . className = [
104+ ...( node . properties . className || [ ] ) ,
105+ "citation-link" ,
106+ ]
107+ }
55108 }
56109 } )
57110 }
@@ -60,4 +113,4 @@ export const Citations: QuartzTransformerPlugin<Partial<Options>> = (userOpts) =
60113 return plugins
61114 } ,
62115 }
63- }
116+ }
0 commit comments