@behackl/citation-js-extras 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -226
- package/dist/index.d.ts +83 -10
- package/dist/index.js +408 -182
- package/dist/math.d.ts +4 -0
- package/dist/math.js +17 -6
- package/dist/types.d.ts +142 -18
- package/package.json +4 -1
package/dist/math.d.ts
CHANGED
|
@@ -6,5 +6,9 @@ export declare class MathProtector {
|
|
|
6
6
|
constructor(source: string);
|
|
7
7
|
protect(properties: Record<string, any>, key: string): Record<string, any>;
|
|
8
8
|
private scan;
|
|
9
|
+
/**
|
|
10
|
+
* Replace placeholders in text (never in attribute values). A renderer error
|
|
11
|
+
* is rethrown naming the entry, so it can be traced to the .bib file.
|
|
12
|
+
*/
|
|
9
13
|
restore(html: string, render?: MathRenderer): string;
|
|
10
14
|
}
|
package/dist/math.js
CHANGED
|
@@ -18,10 +18,11 @@ export class MathProtector {
|
|
|
18
18
|
return Object.fromEntries(Object.entries(properties).map(([field, value]) => [
|
|
19
19
|
field,
|
|
20
20
|
TEXT_FIELDS.has(field) && typeof value === "string"
|
|
21
|
-
? this.scan(value,
|
|
21
|
+
? this.scan(value, key, field) : value,
|
|
22
22
|
]));
|
|
23
23
|
}
|
|
24
|
-
scan(value,
|
|
24
|
+
scan(value, key, field) {
|
|
25
|
+
const context = `${key}.${field}`;
|
|
25
26
|
let out = "";
|
|
26
27
|
for (let i = 0; i < value.length;) {
|
|
27
28
|
const opener = value.startsWith("$$", i) ? "$$"
|
|
@@ -51,23 +52,33 @@ export class MathProtector {
|
|
|
51
52
|
if (!token) {
|
|
52
53
|
token = `${this.prefix}${this.expressions.size}end`;
|
|
53
54
|
this.tokensBySource.set(source, token);
|
|
54
|
-
this.expressions.set(token, { tex, source, display: opener === "$$" || opener === "\\[" });
|
|
55
|
+
this.expressions.set(token, { tex, source, key, display: opener === "$$" || opener === "\\[" });
|
|
55
56
|
}
|
|
56
57
|
out += token;
|
|
57
58
|
i = end + closer.length;
|
|
58
59
|
}
|
|
59
60
|
return out;
|
|
60
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Replace placeholders in text (never in attribute values). A renderer error
|
|
64
|
+
* is rethrown naming the entry, so it can be traced to the .bib file.
|
|
65
|
+
*/
|
|
61
66
|
restore(html, render) {
|
|
62
67
|
const pattern = new RegExp(`${this.prefix}\\d+end`, "gi");
|
|
63
|
-
// Only replace text, never attribute values. Renderer output is inserted last.
|
|
64
68
|
return html.split(/(<[^>]*>)/g).map(part => part.startsWith("<") ? part
|
|
65
69
|
: part.replace(pattern, token => {
|
|
66
70
|
const expression = this.expressions.get(token.toLowerCase());
|
|
67
71
|
if (!expression)
|
|
68
72
|
throw new Error(`Unknown math placeholder: ${token}`);
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
if (!render)
|
|
74
|
+
return escapeHtml(expression.source);
|
|
75
|
+
try {
|
|
76
|
+
return render(expression.tex, { display: expression.display });
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
throw new Error(`entry ${expression.key}: ${message}`, { cause: error });
|
|
81
|
+
}
|
|
71
82
|
})).join("");
|
|
72
83
|
}
|
|
73
84
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -22,14 +22,30 @@
|
|
|
22
22
|
* { field: 'zbl', label: 'zbMATH',
|
|
23
23
|
* url: 'https://zbmath.org/?q=an:$1',
|
|
24
24
|
* match: /^(\d{4}\.\d{5})$/ }
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Functions for what a template can't express, e.g. a site-relative link:
|
|
28
|
+
* { field: 'project', label: (code) => code,
|
|
29
|
+
* url: (code) => `/projects/${code.toLowerCase()}/` }
|
|
25
30
|
*/
|
|
26
31
|
export interface BadgeConfig {
|
|
27
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* BibTeX field to read, case-insensitively. A field named like an eprint
|
|
34
|
+
* archive (`arxiv`, `hal`, ...) also reads `eprint` when `eprinttype` or
|
|
35
|
+
* `archivePrefix` names that archive.
|
|
36
|
+
*/
|
|
28
37
|
field: string;
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Text of the badge (HTML-escaped), or a function of the matched value and
|
|
40
|
+
* the entry.
|
|
41
|
+
*/
|
|
42
|
+
label: string | BadgeFunction;
|
|
43
|
+
/**
|
|
44
|
+
* URL template in which `$1` is replaced by the matched value, or a function
|
|
45
|
+
* of the matched value and the entry. `http(s)`, `mailto` and relative URLs
|
|
46
|
+
* (`/…`, `./…`, `../…`, `#…`, `?…`) are kept; anything else drops the badge.
|
|
47
|
+
*/
|
|
48
|
+
url: string | BadgeFunction;
|
|
33
49
|
/**
|
|
34
50
|
* Optional regex applied to the field value.
|
|
35
51
|
*
|
|
@@ -38,29 +54,72 @@ export interface BadgeConfig {
|
|
|
38
54
|
* group (or the full match when there are no capture groups).
|
|
39
55
|
*/
|
|
40
56
|
match?: RegExp;
|
|
41
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Split the field into several values, each rendered as its own badge, e.g.
|
|
59
|
+
* `project = {Alpha, Beta}` with `split: ","`. Values are trimmed and
|
|
60
|
+
* empty ones skipped; `match`, `label` and `url` apply to each value.
|
|
61
|
+
*/
|
|
62
|
+
split?: string | RegExp;
|
|
63
|
+
/**
|
|
64
|
+
* CSS class name(s) for the badge `<a>` element. For classes that depend on
|
|
65
|
+
* the value or the entry, use {@link FormatOptions.linkAttributes}.
|
|
66
|
+
*/
|
|
67
|
+
className?: string;
|
|
68
|
+
}
|
|
69
|
+
/** Computes a badge's label or URL from the matched field value. */
|
|
70
|
+
export type BadgeFunction = (value: string, entry: BibEntry) => string;
|
|
71
|
+
/** HTML attributes; `true` renders a valueless attribute, `false` omits it. */
|
|
72
|
+
export type HtmlAttributes = Record<string, string | boolean>;
|
|
73
|
+
/** A link the library resolved for an entry: its title link or a badge. */
|
|
74
|
+
export interface Link {
|
|
75
|
+
kind: "title" | "badge";
|
|
76
|
+
/** The field the link was built from, as configured (`doi`, `url`, ...). */
|
|
77
|
+
field: string;
|
|
78
|
+
/** The matched value: `10.1000/x` for a DOI, one part of a `split` field. */
|
|
79
|
+
value: string;
|
|
80
|
+
url: string;
|
|
81
|
+
/** Badge text; absent for the title link. */
|
|
82
|
+
label?: string;
|
|
83
|
+
/** The badge's configured `className`, if any. */
|
|
42
84
|
className?: string;
|
|
85
|
+
entry: BibEntry;
|
|
86
|
+
}
|
|
87
|
+
/** The links of one entry, as returned by `Bibliography.links`. */
|
|
88
|
+
export interface EntryLinks {
|
|
89
|
+
title?: Link;
|
|
90
|
+
badges: Link[];
|
|
43
91
|
}
|
|
44
92
|
/** Synchronous renderer returning trusted HTML. Sanitize untrusted renderer output. */
|
|
45
93
|
export type MathRenderer = (tex: string, context: {
|
|
46
94
|
display: boolean;
|
|
47
95
|
}) => string;
|
|
48
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Options passed to {@link Bibliography.formatHtml} or
|
|
98
|
+
* {@link Bibliography.formatEntry}. `list` and `listAttributes` only apply to
|
|
99
|
+
* `formatHtml`, which is the only method emitting a wrapper element.
|
|
100
|
+
*/
|
|
49
101
|
export interface FormatOptions {
|
|
50
102
|
/** Render protected math as trusted HTML; requires preserveMath at construction.
|
|
51
103
|
* Without this callback, escaped original TeX delimiters are restored.
|
|
104
|
+
* Not settable on the constructor.
|
|
52
105
|
*/
|
|
53
106
|
renderMath?: MathRenderer;
|
|
54
107
|
/**
|
|
55
|
-
* Fields to use for linking the title, checked in order
|
|
56
|
-
* A
|
|
57
|
-
*
|
|
58
|
-
*
|
|
108
|
+
* Fields to use for linking the title, checked in order; the first that
|
|
109
|
+
* yields a URL wins. A field with a {@link badgePresets} entry (`doi`,
|
|
110
|
+
* `arxiv`, ...) is expanded by that preset; another field with a configured
|
|
111
|
+
* badge by that badge; any other field must hold a URL itself.
|
|
112
|
+
* Overrides the constructor default, if any.
|
|
59
113
|
*
|
|
60
114
|
* @default ['url', 'doi', 'arxiv']
|
|
61
115
|
*/
|
|
62
116
|
titleLink?: string[];
|
|
63
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Badge configurations to append to each entry.
|
|
119
|
+
* Overrides the constructor default, if any.
|
|
120
|
+
*
|
|
121
|
+
* @default [] (no badges)
|
|
122
|
+
*/
|
|
64
123
|
badges?: BadgeConfig[];
|
|
65
124
|
/**
|
|
66
125
|
* Wrapper list element.
|
|
@@ -69,14 +128,73 @@ export interface FormatOptions {
|
|
|
69
128
|
list?: "ol" | "ul" | "div";
|
|
70
129
|
/**
|
|
71
130
|
* HTML attributes for the wrapper element (e.g. `{ reversed: true }`).
|
|
72
|
-
* Boolean `true` renders as a valueless attribute.
|
|
131
|
+
* Boolean `true` renders as a valueless attribute. A `class` is added to
|
|
132
|
+
* `csl-bib-body`.
|
|
73
133
|
*
|
|
74
134
|
* @default { reversed: true } (when list is 'ol')
|
|
75
135
|
*/
|
|
76
|
-
listAttributes?:
|
|
136
|
+
listAttributes?: HtmlAttributes;
|
|
77
137
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
138
|
+
* Extra HTML attributes for each entry's `<li>`/`<div>` in `formatHtml`,
|
|
139
|
+
* e.g. to add anchors: `(entry) => ({ id: 'pub-' + entry.key })`. A `class` is added to
|
|
140
|
+
* `csl-entry`.
|
|
141
|
+
*/
|
|
142
|
+
itemAttributes?: (entry: BibEntry) => HtmlAttributes;
|
|
143
|
+
/**
|
|
144
|
+
* Class of the `<span>` wrapping an entry's badges.
|
|
145
|
+
*
|
|
146
|
+
* @default 'bib-links'
|
|
147
|
+
*/
|
|
148
|
+
badgeListClassName?: string;
|
|
149
|
+
/**
|
|
150
|
+
* Also let the CSL style print identifiers that are already linked. By
|
|
151
|
+
* default, the field used for the title link and the field of every rendered
|
|
152
|
+
* badge are withheld from the style, so a DOI or URL is not printed again
|
|
153
|
+
* as text next to its link.
|
|
154
|
+
*
|
|
155
|
+
* @default false
|
|
156
|
+
*/
|
|
157
|
+
printLinkedIdentifiers?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Sanitize the finished HTML. Runs while formulas are still placeholders, so
|
|
160
|
+
* `renderMath` output is inserted afterwards and never passes through the
|
|
161
|
+
* sanitizer (see "Sanitizing formatted output" in the README).
|
|
162
|
+
*/
|
|
163
|
+
sanitize?: (html: string) => string;
|
|
164
|
+
/**
|
|
165
|
+
* Leave the badges out of the HTML, e.g. to render them yourself from
|
|
166
|
+
* `bib.links(entry)`. They are still withheld from the style.
|
|
167
|
+
*
|
|
168
|
+
* @default true
|
|
169
|
+
*/
|
|
170
|
+
appendBadges?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Extra attributes for every link the library writes: the title link, the
|
|
173
|
+
* badges, and the fallback title URL. A `class` is added to the badge's
|
|
174
|
+
* `className`; an `href` replaces the URL (it must still be `http(s)`,
|
|
175
|
+
* `mailto` or relative, or the link is dropped).
|
|
176
|
+
*/
|
|
177
|
+
linkAttributes?: (link: Link) => HtmlAttributes;
|
|
178
|
+
/**
|
|
179
|
+
* Wrap the rendered HTML of each CSL variable in the bibliography (and the
|
|
180
|
+
* title outside its link), e.g. to mark it for CSS:
|
|
181
|
+
* `(html, { variable }) => '<span data-csl-variable="' + variable + '">' + html + '</span>'`.
|
|
182
|
+
*/
|
|
183
|
+
wrapVariable?: (html: string, context: {
|
|
184
|
+
variable: string;
|
|
185
|
+
entry: BibEntry;
|
|
186
|
+
}) => string;
|
|
187
|
+
/**
|
|
188
|
+
* Locale for the CSL style's terms and dates. citation-js ships `en-US`,
|
|
189
|
+
* `de-DE`, `fr-FR`, `es-ES` and `nl-NL`.
|
|
190
|
+
*
|
|
191
|
+
* @default 'en-US'
|
|
192
|
+
*/
|
|
193
|
+
lang?: string;
|
|
194
|
+
/**
|
|
195
|
+
* Turn bare `http(s)://` URLs that the style prints (e.g. in a `note`) into
|
|
196
|
+
* links. Applied to each variable as citeproc renders it, never to text the
|
|
197
|
+
* style adds around variables. Overrides the constructor default, if any.
|
|
80
198
|
*
|
|
81
199
|
* @default true
|
|
82
200
|
*/
|
|
@@ -98,8 +216,13 @@ export interface BibEntry {
|
|
|
98
216
|
/** The full raw BibTeX properties (unfiltered). */
|
|
99
217
|
raw: Record<string, any>;
|
|
100
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Formatting options that can be set once on the constructor and overridden
|
|
221
|
+
* by the options of an individual `formatHtml`/`formatEntry` call.
|
|
222
|
+
*/
|
|
223
|
+
export type FormatDefaults = Pick<FormatOptions, "titleLink" | "badges" | "linkifyUrls" | "itemAttributes" | "badgeListClassName" | "printLinkedIdentifiers" | "sanitize" | "lang" | "appendBadges" | "linkAttributes" | "wrapVariable">;
|
|
101
224
|
/** Options for constructing a {@link Bibliography}. */
|
|
102
|
-
export interface BibliographyOptions {
|
|
225
|
+
export interface BibliographyOptions extends FormatDefaults {
|
|
103
226
|
/** Preserve math in supported display-text fields before CSL conversion.
|
|
104
227
|
* Opt-in; entries' CSL text contains internal placeholders until HTML formatting.
|
|
105
228
|
* Raw/custom fields remain unchanged. Unclosed or empty math throws.
|
|
@@ -125,7 +248,8 @@ export interface BibliographyOptions {
|
|
|
125
248
|
/**
|
|
126
249
|
* BibTeX field names to preserve through the citation-js pipeline.
|
|
127
250
|
* These are extracted from the raw BibTeX parse and made available on
|
|
128
|
-
* each {@link BibEntry} under `.custom
|
|
251
|
+
* each {@link BibEntry} under `.custom`, keyed as given here. Matching is
|
|
252
|
+
* case-insensitive, like BibTeX: `archivePrefix` finds `archiveprefix`.
|
|
129
253
|
*
|
|
130
254
|
* Common examples: `['publication-status', 'arxiv', 'mrnumber', 'project']`.
|
|
131
255
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@behackl/citation-js-extras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Preserve custom BibTeX fields through citation-js and render academic bibliographies with linked titles, badges, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -63,5 +63,8 @@
|
|
|
63
63
|
"onlyBuiltDependencies": [
|
|
64
64
|
"esbuild"
|
|
65
65
|
]
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"citeproc": "^2.4.6"
|
|
66
69
|
}
|
|
67
70
|
}
|