@retorquere/bibtex-parser 9.0.20 → 9.0.22

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/index.js DELETED
@@ -1,1191 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.English = exports.FieldMode = exports.tokenize = exports.toSentenceCase = void 0;
40
- exports.parse = parse;
41
- exports.parseAsync = parseAsync;
42
- const unified_latex_util_pegjs_1 = require("@unified-latex/unified-latex-util-pegjs");
43
- const unified_latex_util_print_raw_1 = require("@unified-latex/unified-latex-util-print-raw");
44
- const unified_latex_util_replace_1 = require("@unified-latex/unified-latex-util-replace");
45
- const unified_latex_util_visit_1 = require("@unified-latex/unified-latex-util-visit");
46
- const unicode2latex_1 = require("unicode2latex");
47
- const JabRef = __importStar(require("./jabref"));
48
- const bibtex = __importStar(require("./verbatim"));
49
- const sentence_case_1 = require("./sentence-case");
50
- var sentence_case_2 = require("./sentence-case");
51
- Object.defineProperty(exports, "toSentenceCase", { enumerable: true, get: function () { return sentence_case_2.toSentenceCase; } });
52
- const tokenizer_1 = require("./tokenizer");
53
- var tokenizer_2 = require("./tokenizer");
54
- Object.defineProperty(exports, "tokenize", { enumerable: true, get: function () { return tokenizer_2.tokenize; } });
55
- const yield_1 = require("./yield");
56
- const crossref_json_1 = __importDefault(require("./crossref.json"));
57
- const fields_json_1 = __importDefault(require("./fields.json"));
58
- const merge_1 = require("./merge");
59
- function latexMode(node) {
60
- return node._renderInfo.mode;
61
- }
62
- function latex2unicode(tex, node) {
63
- const text = unicode2latex_1.latex2unicode[tex];
64
- if (typeof text === 'string')
65
- return text;
66
- return text && text[latexMode(node)];
67
- }
68
- const open = {};
69
- const close = {};
70
- for (const tag of ['i', 'b', 'sc', 'nc', 'ncx', 'br', 'p', 'li', 'code']) {
71
- open[tag] = `\x0E${tag}\x0F`;
72
- close[tag] = `\x0E/${tag}\x0F`;
73
- }
74
- const collapsable = /\x0E\/([a-z]+)\x0F(\s*)\x0E\1\x0F/ig;
75
- const Month = {
76
- jan: '1',
77
- january: '1',
78
- feb: '2',
79
- february: '2',
80
- mar: '3',
81
- march: '3',
82
- apr: '4',
83
- april: '4',
84
- may: '5',
85
- jun: '6',
86
- june: '6',
87
- jul: '7',
88
- july: '7',
89
- aug: '8',
90
- august: '8',
91
- sep: '9',
92
- september: '9',
93
- oct: '10',
94
- october: '10',
95
- nov: '11',
96
- november: '11',
97
- dec: '12',
98
- december: '12',
99
- };
100
- exports.FieldMode = {
101
- creatorlist: [
102
- 'author',
103
- 'bookauthor',
104
- 'collaborator',
105
- 'commentator',
106
- 'director',
107
- 'editor',
108
- 'editora',
109
- 'editorb',
110
- 'editors',
111
- 'holder',
112
- 'scriptwriter',
113
- 'translator',
114
- ],
115
- title: [
116
- 'title',
117
- 'subtitle',
118
- 'series',
119
- 'shorttitle',
120
- 'booktitle',
121
- // 'type',
122
- 'origtitle',
123
- 'maintitle',
124
- 'eventtitle',
125
- ],
126
- verbatim: [
127
- 'doi',
128
- 'eprint',
129
- 'file',
130
- 'files',
131
- 'pdf',
132
- 'groups', // jabref unilaterally decided to make this non-standard field verbatim
133
- 'ids',
134
- 'url',
135
- 'verba',
136
- 'verbb',
137
- 'verbc',
138
- /^keywords([+]duplicate-\d+)?$/,
139
- /^citeulike-linkout-[0-9]+$/,
140
- /^bdsk-url-[0-9]+$/,
141
- ],
142
- richtext: [
143
- 'annotation',
144
- 'comment',
145
- 'annote',
146
- 'review',
147
- 'notes',
148
- 'note',
149
- ],
150
- literallist: [
151
- 'institution',
152
- 'publisher',
153
- 'origpublisher',
154
- 'organization',
155
- 'location',
156
- 'origlocation',
157
- ],
158
- };
159
- exports.English = [
160
- '',
161
- 'american',
162
- 'british',
163
- 'canadian',
164
- 'english',
165
- 'australian',
166
- 'newzealand',
167
- 'usenglish',
168
- 'ukenglish',
169
- 'en',
170
- 'eng',
171
- 'en-au',
172
- 'en-bz',
173
- 'en-ca',
174
- 'en-cb',
175
- 'en-gb',
176
- 'en-ie',
177
- 'en-jm',
178
- 'en-nz',
179
- 'en-ph',
180
- 'en-tt',
181
- 'en-us',
182
- 'en-za',
183
- 'en-zw',
184
- 'anglais', // don't do this people
185
- ];
186
- const FieldAction = {
187
- removeOuterBraces: [
188
- 'doi',
189
- // 'publisher',
190
- // 'location',
191
- ],
192
- parseInt: [
193
- 'year',
194
- 'month',
195
- ],
196
- noCrossRef: [
197
- 'file',
198
- ],
199
- };
200
- const narguments = {
201
- advance: 1,
202
- ElsevierGlyph: 1,
203
- bar: 1,
204
- bibcyr: 1,
205
- bibstring: 1,
206
- chsf: 1,
207
- cite: 1,
208
- citeauthor: 1,
209
- cyrchar: 1,
210
- ding: 1,
211
- emph: 1,
212
- enquote: 1,
213
- frac: 2,
214
- hbox: 1,
215
- href: 2,
216
- hskip: 1,
217
- hspace: 1,
218
- ht: 1,
219
- mathrm: 1,
220
- mbox: 1,
221
- mkbibbold: 1,
222
- mkbibemph: 1,
223
- mkbibitalic: 1,
224
- mkbibquote: 1,
225
- newcommand: 2,
226
- noopsort: 1,
227
- ocirc: 1,
228
- overline: 1,
229
- ProvideTextCommandDefault: 2,
230
- rlap: 1,
231
- sb: 1,
232
- section: 1,
233
- sp: 1,
234
- subsection: 1,
235
- subsubsection: 1,
236
- subsubsubsection: 1,
237
- t: 1,
238
- textbf: 1,
239
- textcite: 1,
240
- textit: 1,
241
- textrm: 1,
242
- textsc: 1,
243
- textsl: 1,
244
- textsubscript: 1,
245
- textsuperscript: 1,
246
- texttt: 1,
247
- textup: 1,
248
- url: 1,
249
- vphantom: 1,
250
- vspace: 1,
251
- wd: 1,
252
- // math
253
- 'math\t_': 1,
254
- 'math\t^': 1,
255
- };
256
- for (const m in unicode2latex_1.combining.tounicode) { // eslint-disable-line guard-for-in
257
- narguments[m] = 1;
258
- }
259
- /*
260
- async function* asyncGenerator<T>(array: T[]): AsyncGenerator<T, void, unknown> {
261
- for (const item of array) {
262
- yield await Promise.resolve(item)
263
- }
264
- }
265
- */
266
- class BibTeXParser {
267
- constructor() {
268
- this.newcommands = {};
269
- this.unhandled = new Set();
270
- }
271
- split(ast, sep, split) {
272
- const roots = [];
273
- const nodes = [...ast.content];
274
- const types = nodes.map(node => {
275
- if (node.type === 'whitespace')
276
- return ' ';
277
- if (node.type === 'string' && node.content.match(sep))
278
- return '&';
279
- return '.';
280
- }).join('');
281
- types.split(split).forEach((match, i) => {
282
- const content = match.length ? nodes.splice(0, match.length) : [];
283
- if ((i % 2) === 0)
284
- roots.push({ type: 'root', content });
285
- });
286
- return roots;
287
- }
288
- trimCreator(cr) {
289
- // trims strings but coincidentally removes undefined fields
290
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
291
- return JSON.parse(JSON.stringify(cr, (k, v) => typeof v === 'string' ? (v.trim() || undefined) : v));
292
- }
293
- parseCreator(ast) {
294
- if (ast.content.length === 1 && ast.content[0].type === 'group')
295
- return this.trimCreator({ name: this.stringify(ast, { mode: 'creatorlist' }) });
296
- const { parts, extended } = this.commaSeparatedCreator(ast);
297
- if (extended) {
298
- const name = {};
299
- for (const [attr, value] of Object.entries(extended)) {
300
- const rendered = this.stringify(value, { mode: 'creatorlist' }).trim();
301
- switch (attr) {
302
- case '':
303
- break;
304
- case 'given':
305
- name.firstName = rendered;
306
- break;
307
- case 'family':
308
- name.lastName = rendered;
309
- break;
310
- case 'given-i':
311
- name.initial = rendered;
312
- break;
313
- case 'useprefix':
314
- case 'juniorcomma':
315
- name[attr] = rendered.toLowerCase() === 'true';
316
- break;
317
- default:
318
- name[attr] = rendered;
319
- break;
320
- }
321
- }
322
- return this.trimCreator(name);
323
- }
324
- else if (parts.length) {
325
- const nameparts = parts.map((part) => this.stringify(part, { mode: 'creatorlist' }).trim());
326
- if (nameparts.length === 3 && nameparts[2] === '')
327
- nameparts.pop();
328
- if (nameparts.length > 3) {
329
- const key = this.current.key ? `@${this.current.key}: ` : '';
330
- this.bib.errors.push({
331
- error: `${key}unexpected ${nameparts.length}-part name "${nameparts.join(', ')}", dropping "${nameparts.slice(3).join(', ')}"`,
332
- input: nameparts.join(', '),
333
- });
334
- }
335
- let [lastName, suffix, firstName] = (nameparts.length === 2)
336
- ? [nameparts[0], undefined, nameparts[1]]
337
- // > 3 parts are invalid and are dropped
338
- : nameparts.slice(0, 3);
339
- let prefix;
340
- const m = lastName.match(/^([a-z'. ]+) (.+)/);
341
- if (m) {
342
- prefix = m[1];
343
- lastName = m[2];
344
- }
345
- return this.trimCreator({
346
- lastName,
347
- firstName,
348
- prefix,
349
- suffix,
350
- });
351
- }
352
- else { // first-last mode
353
- const nameparts = this.split(ast, /^$/, /( )/).map(part => this.stringify(part, { mode: 'creatorlist' })).filter(n => n);
354
- if (nameparts.length === 1)
355
- return this.trimCreator({ lastName: nameparts[0] });
356
- const prefix = nameparts.findIndex(n => n.match(/^[a-z]/));
357
- const postfix = prefix <= 0 ? -1 : nameparts.findIndex((n, i) => i > prefix && !n.match(/^[a-z]/));
358
- if (postfix === -1) {
359
- const lastName = nameparts.pop();
360
- return this.trimCreator({ lastName, firstName: nameparts.join(' ') });
361
- }
362
- return this.trimCreator({
363
- firstName: nameparts.slice(0, prefix).join(' '),
364
- prefix: nameparts.slice(prefix, postfix).join(' '),
365
- lastName: nameparts.slice(postfix).join(' '),
366
- });
367
- }
368
- }
369
- ligature(nodes) {
370
- if (latexMode(nodes[0]) !== 'text')
371
- return null;
372
- const max = 3;
373
- const slice = nodes.slice(0, max);
374
- const type = slice.map(n => n.type === 'string' ? 's' : ' ').join('');
375
- if (type[0] !== 's')
376
- return null;
377
- const content = slice.map(n => n.type === 'string' ? n.content : '');
378
- let latex;
379
- while (content.length) {
380
- if (type.startsWith('s'.repeat(content.length)) && (latex = latex2unicode(content.join(''), slice[0]))) {
381
- try {
382
- return { type: 'string', content: latex, _renderInfo: {} };
383
- }
384
- finally {
385
- nodes.splice(0, content.length);
386
- }
387
- }
388
- content.pop();
389
- }
390
- return null;
391
- }
392
- wraparg(node, macro) {
393
- if (macro.content.match(/^(itshape|textsl|textit|emph|mkbibemph)$/))
394
- node._renderInfo.emph = true;
395
- if (macro.content.match(/^(textbf|mkbibbold|bfseries)$/))
396
- node._renderInfo.bold = true;
397
- if (macro.content.match(/^(textsc)$/))
398
- node._renderInfo.smallCaps = true;
399
- if (macro.content.match(/^(texttt)$/))
400
- node._renderInfo.code = true;
401
- return { type: 'argument', content: [node], openMark: '', closeMark: '', _renderInfo: { mode: node._renderInfo.mode } };
402
- }
403
- argtogroup(node) {
404
- if (node.content.length === 1 && node.content[0].type === 'group')
405
- return node.content[0];
406
- return { type: 'group', content: node.content };
407
- }
408
- argument(nodes, macro) {
409
- if (!nodes.length)
410
- return null;
411
- if (nodes[0].type === 'whitespace')
412
- nodes.shift();
413
- if (!nodes.length)
414
- return null;
415
- if (nodes[0].type === 'string') {
416
- const char = nodes[0].content[0];
417
- nodes[0].content = nodes[0].content.substr(1);
418
- const arg = Object.assign(Object.assign({}, nodes[0]), { content: char });
419
- if (!nodes[0].content)
420
- nodes.shift();
421
- return this.wraparg(arg, macro);
422
- }
423
- return this.wraparg(nodes.shift(), macro);
424
- }
425
- unsupported(node) {
426
- var _a;
427
- const tex = (0, unified_latex_util_print_raw_1.printRaw)(node);
428
- if (this.fallback)
429
- return (_a = this.fallback(node, tex, this.current)) !== null && _a !== void 0 ? _a : '';
430
- let id;
431
- switch (node.type) {
432
- case 'macro':
433
- id = `${node.type}.${node.content}`;
434
- if (!this.unhandled.has(id)) {
435
- this.unhandled.add(id);
436
- this.bib.errors.push({ error: `unhandled ${node.type} ${(0, unified_latex_util_print_raw_1.printRaw)(node)}`, input: (0, unified_latex_util_print_raw_1.printRaw)(node) });
437
- }
438
- break;
439
- case 'environment':
440
- id = `${node.type}.${node.env}`;
441
- if (!this.unhandled.has(id)) {
442
- this.unhandled.add(id);
443
- this.bib.errors.push({ error: `unhandled ${node.type} ${node.env} (${(0, unified_latex_util_print_raw_1.printRaw)(node)})`, input: (0, unified_latex_util_print_raw_1.printRaw)(node) });
444
- }
445
- break;
446
- default:
447
- this.bib.errors.push({ error: `unhandled ${node.type} (${(0, unified_latex_util_print_raw_1.printRaw)(node)})`, input: (0, unified_latex_util_print_raw_1.printRaw)(node) });
448
- break;
449
- }
450
- return tex;
451
- }
452
- wrap(text, tag, wrap = true) {
453
- if (!text || !wrap)
454
- return text || '';
455
- return `\x0E${tag}\x0F${text}\x0E/${tag}\x0F`;
456
- }
457
- registercommand(node) {
458
- const types = (nodes) => nodes.map(n => n.type).join('.');
459
- const group = (arg, kind) => {
460
- if (!arg)
461
- throw new Error(`missing ${kind} for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
462
- if (types(arg.content) !== 'group')
463
- throw new Error(`Malformed ${kind} for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
464
- return arg.content[0].content;
465
- };
466
- if (!node.args)
467
- throw new Error(`No arguments for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
468
- const namearg = group(node.args[0], 'name');
469
- if (types(namearg) !== 'macro')
470
- throw new Error(`Unexpected name for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
471
- this.newcommands[namearg[0].content] = node.args[1];
472
- return '';
473
- }
474
- subp(text, mode) {
475
- const macro = { sub: '_', sup: '^' }[mode];
476
- let subp = '';
477
- for (let char of text) {
478
- const mapped = unicode2latex_1.latex2unicode[`${macro}{${char}}`];
479
- switch (typeof mapped) {
480
- case 'string':
481
- subp += mapped;
482
- break;
483
- case 'undefined':
484
- return `\x0E${mode}\x0F${text}\x0E/${mode}\x0F`;
485
- default:
486
- subp += mapped.math;
487
- }
488
- }
489
- return subp;
490
- }
491
- macro(node, context) {
492
- var _a, _b, _c, _d, _e, _f, _g;
493
- const text = latex2unicode((0, unified_latex_util_print_raw_1.printRaw)(node), node);
494
- if (text)
495
- return text;
496
- let url;
497
- let label;
498
- let arg;
499
- switch (node.content) {
500
- case 'newcommand':
501
- case 'ProvideTextCommandDefault':
502
- return this.registercommand(node);
503
- // too complex to deal with these
504
- case 'raise':
505
- case 'accent':
506
- case 'def':
507
- case 'hss':
508
- case 'ifmmode':
509
- case 'makeatletter':
510
- case 'makeatother':
511
- case 'scriptscriptstyle':
512
- case 'setbox':
513
- case 'dimen':
514
- case 'advance':
515
- return '';
516
- case 'vphantom':
517
- case 'noopsort':
518
- case 'left':
519
- case 'right':
520
- case 'ensuremath':
521
- case 'wd':
522
- case 'ht':
523
- return '';
524
- case 'path':
525
- return ''; // until https://github.com/siefkenj/unified-latex/issues/94 is fixed
526
- case 'hspace':
527
- case 'hskip':
528
- if (node.args && node.args.length) {
529
- if ((0, unified_latex_util_print_raw_1.printRaw)(node.args).match(/^[{]?0[a-z]*$/))
530
- return '';
531
- return ' ';
532
- }
533
- return '';
534
- case 'overline':
535
- case 'bar':
536
- return node.args.map(a => this.stringify(a, context)).join('').replace(/[a-z0-9]/ig, m => `${m}\u0305`);
537
- // accents dealt with by preprocessor
538
- case 'textup':
539
- case 'textsc':
540
- case 'textrm':
541
- case 'texttt':
542
- case 'mathrm':
543
- case 'mbox':
544
- case 'hbox':
545
- case 'rlap':
546
- return node.args.map(n => this.stringify(n, context)).join('');
547
- case 'href':
548
- case 'url':
549
- if (node.args) {
550
- url = node.args[0];
551
- label = node.args[node.content === 'url' ? 0 : 1];
552
- }
553
- return `<a href="${this.stringify(url, context)}">${this.stringify(label, context)}</a>`;
554
- case 'relax':
555
- case 'aftergroup':
556
- case 'ignorespaces':
557
- case 'em':
558
- case 'it':
559
- case 'tt':
560
- case 'sl':
561
- return '';
562
- case 'rm':
563
- case 'sc':
564
- return '';
565
- // bold/emph/smallcaps is handled in the wrapper
566
- case 'textbf':
567
- case 'mkbibbold':
568
- case 'textit':
569
- case 'emph':
570
- case 'mkbibemph':
571
- return this.stringify((_a = node.args) === null || _a === void 0 ? void 0 : _a[0], context);
572
- case 'textsuperscript':
573
- return this.subp(this.stringify((_b = node.args) === null || _b === void 0 ? void 0 : _b[0], context), 'sup');
574
- case 'textsubscript':
575
- return this.subp(this.stringify((_c = node.args) === null || _c === void 0 ? void 0 : _c[0], context), 'sub');
576
- case '_':
577
- case '^':
578
- switch (latexMode(node)) {
579
- case 'math':
580
- return this.subp(this.stringify((_d = node.args) === null || _d === void 0 ? void 0 : _d[0], context), node.content === '^' ? 'sup' : 'sub');
581
- default:
582
- return node.content;
583
- }
584
- case 'LaTeX':
585
- return this.wrap(`L${this.subp('A', 'sup')}T${this.subp('E', 'sub')}X`, 'ncx');
586
- case 'enquote':
587
- case 'mkbibquote':
588
- return this.wrap(this.stringify((_e = node.args) === null || _e === void 0 ? void 0 : _e[0], context), 'enquote');
589
- case '\\':
590
- return context.mode === 'richtext' ? open.br : ' ';
591
- case 'par':
592
- return context.mode === 'richtext' ? open.p : ' ';
593
- case 'item':
594
- return context.mode === 'richtext' ? open.li : ' ';
595
- case 'section':
596
- case 'subsection':
597
- case 'subsubsection':
598
- case 'subsubsubsection':
599
- return this.wrap(this.stringify((_f = node.args) === null || _f === void 0 ? void 0 : _f[0], context), `h${node.content.split('sub').length}`);
600
- case 'frac':
601
- arg = node.args.map(a => this.stringify(a, context));
602
- if (arg.length === 2) {
603
- const resolved = unicode2latex_1.latex2unicode[`\\frac${arg.map(a => `{${a}}`).join('')}`];
604
- if (resolved)
605
- return typeof resolved === 'string' ? resolved : (resolved.math || resolved.text);
606
- }
607
- return arg.map((part, i) => this.subp(part, i ? 'sub' : 'sup')).join('\u2044');
608
- case 'chsf':
609
- case 'bibstring':
610
- case 'cite':
611
- case 'textcite':
612
- case 'citeauthor':
613
- // ncx protects but will be stripped later
614
- return this.wrap(this.stringify((_g = node.args) === null || _g === void 0 ? void 0 : _g[0], context), 'ncx', context.mode === 'title');
615
- default:
616
- if (this.newcommands[node.content])
617
- return this.stringify(this.newcommands[node.content], context);
618
- return this.unsupported(node);
619
- }
620
- }
621
- what(node) {
622
- var _a;
623
- if (!node)
624
- return '';
625
- switch (node.type) {
626
- case 'macro':
627
- return `macro:${(_a = node._renderInfo.mode) !== null && _a !== void 0 ? _a : 'text'}:${node.content}`;
628
- case 'environment':
629
- return `env:${node.env}`;
630
- default:
631
- return node.type;
632
- }
633
- }
634
- environment(node, context) {
635
- while (node.content.length && this.what(node.content[0]).match(/^parbreak|whitespace|macro:text:par$/))
636
- node.content.shift();
637
- while (node.content.length && this.what(node.content[node.content.length - 1]).match(/^parbreak|whitespace|macro:text:par$/))
638
- node.content.pop();
639
- switch (node.env) {
640
- case 'quotation':
641
- return this.wrap(node.content.map(n => this.stringify(n, context)).join(''), 'blockquote', context.mode === 'richtext');
642
- case 'itemize':
643
- return this.wrap(node.content.map(n => this.stringify(n, context)).join(''), 'ul', context.mode === 'richtext');
644
- case 'em':
645
- return this.wrap(node.content.map(n => this.stringify(n, context)).join(''), 'i', context.mode === 'richtext');
646
- default:
647
- return this.unsupported(node);
648
- }
649
- }
650
- stringify(node, context) {
651
- let content = this.stringifyContent(node, context);
652
- if (content && node._renderInfo) {
653
- if (node._renderInfo.emph)
654
- content = `${open.i}${content}${close.i}`;
655
- if (node._renderInfo.bold)
656
- content = `${open.b}${content}${close.b}`;
657
- if (node._renderInfo.smallCaps)
658
- content = `${open.sc}${content}${close.sc}`;
659
- if (node._renderInfo.code)
660
- content = `${open.code}${content}${close.code}`;
661
- if (this.english && node._renderInfo.protectCase)
662
- content = `${open.nc}${content}${close.nc}`;
663
- }
664
- return content;
665
- }
666
- stringifyContent(node, context) {
667
- if (!node)
668
- return '';
669
- switch (node.type) {
670
- case 'root':
671
- case 'argument':
672
- case 'group':
673
- case 'inlinemath':
674
- return node.content.map(n => this.stringify(n, context)).join('');
675
- case 'string':
676
- case 'verbatim':
677
- return node.content;
678
- case 'macro':
679
- return this.macro(node, context);
680
- case 'parbreak':
681
- return context.mode === 'richtext' ? open.p : ' ';
682
- case 'whitespace':
683
- return node._renderInfo.mode === 'math' ? '' : ' ';
684
- case 'comment':
685
- return '';
686
- case 'environment':
687
- return this.environment(node, context);
688
- case 'verb':
689
- return node.content;
690
- default:
691
- return this.unsupported(node);
692
- }
693
- }
694
- protect(node) {
695
- if (node.type === 'inlinemath')
696
- return true;
697
- if (node.type !== 'group')
698
- return false;
699
- if (!node.content.length)
700
- return false;
701
- return (node.content[0].type !== 'macro');
702
- }
703
- mode(field) {
704
- if (this.options.verbatimFields && this.options.verbatimFields.find(name => typeof name === 'string' ? (name === field) : field.match(name)))
705
- return 'verbatim';
706
- let mode = 'literal';
707
- for (const [selected, fields] of Object.entries(this.fieldMode)) {
708
- if (fields.find(match => typeof match === 'string' ? field === match : field.match(match)))
709
- mode = selected;
710
- }
711
- return mode;
712
- }
713
- restoreMarkup(s) {
714
- if (!s.includes('\x0E'))
715
- return s;
716
- const restored = [s.replace(/\x0E\/?ncx\x0F/ig, '')];
717
- while (restored[0] !== restored[1]) {
718
- restored.unshift(restored[0].replace(collapsable, '$2'));
719
- }
720
- return restored[0]
721
- .replace(/(\x0Ep\x0F\s*){2,}/ig, '\x0Ep\x0F')
722
- .replace(/\s*(\x0E\/p\x0F){2,}/ig, '\x0E/p\x0F')
723
- .replace(/\x0Eenquote\x0F/ig, '\u201C').replace(/\x0E\/enquote\x0F/ig, '\u201D')
724
- .replace(/\x0Esc\x0F/ig, '<span style="font-variant:small-caps;">').replace(/\x0E\/sc\x0F/ig, '</span>')
725
- .replace(/\x0Enc\x0F/ig, '<span class="nocase">').replace(/\x0E\/nc\x0F/ig, '</span>')
726
- .replace(/\x0E/ig, '<').replace(/\x0F/ig, '>');
727
- }
728
- stringField(field, value, mode, guessSC) {
729
- if (field === 'crossref')
730
- return value;
731
- if (FieldAction.parseInt.includes(field) && value.trim().match(/^-?\d+$/))
732
- return `${parseInt(value)}`;
733
- if (this.english && mode === 'title') {
734
- value = (0, sentence_case_1.toSentenceCase)(value, {
735
- preserveQuoted: this.options.sentenceCase && this.options.sentenceCase.preserveQuoted,
736
- subSentenceCapitalization: this.options.sentenceCase && this.options.sentenceCase.subSentence,
737
- markup: /\x0E\/?([a-z]+)\x0F/ig,
738
- nocase: /\x0E(ncx?)\x0F.*?\x0E\/\1\x0F/ig,
739
- guess: guessSC,
740
- });
741
- let cancel = (_match, stripped) => stripped;
742
- switch (this.options.caseProtection) {
743
- case 'strict':
744
- cancel = (match, _stripped) => match;
745
- break;
746
- case 'as-needed':
747
- cancel = (match, stripped) => {
748
- const words = (0, tokenizer_1.tokenize)(stripped, /\x0E\/?([a-z]+)\x0F/ig);
749
- return words.find(w => w.shape.match(/^(?!.*X).*x.*$/)) ? match : this.wrap(stripped, 'ncx');
750
- };
751
- break;
752
- }
753
- return value.replace(/\x0Enc\x0F(.*?)\x0E\/nc\x0F/ig, cancel);
754
- }
755
- return value;
756
- }
757
- commaSeparatedCreator(ast) {
758
- var _a;
759
- const result = {
760
- parts: [],
761
- };
762
- if (!ast.content.find(node => node.type === 'string' && node.content === ','))
763
- return result;
764
- result.parts = this.split(ast, /^,$/, /(&)/);
765
- result.extended = {};
766
- for (const part of result.parts) {
767
- const start = ((_a = part.content[0]) === null || _a === void 0 ? void 0 : _a.type) === 'whitespace' ? 1 : 0;
768
- let signature = part.content
769
- .slice(start, start + 4)
770
- .map((node, i) => node._renderInfo.mode === 'text' && node.type === 'string' ? node.content.replace(i % 2 ? /[^=-]/g : /[^a-z]/gi, '.') : '.')
771
- .join('');
772
- if (signature.match(/^[a-z]+(-[a-z]+)?=/i)) {
773
- signature = signature.replace(/=.*/, '').toLowerCase();
774
- result.extended[signature] = { type: 'root', content: part.content.slice(signature.includes('-') ? start + 4 : start + 2) };
775
- }
776
- else {
777
- delete result.extended;
778
- break;
779
- }
780
- }
781
- return result;
782
- }
783
- field(entry, field, value) {
784
- const mode = entry.mode[field] = this.mode(field);
785
- const caseProtection = {
786
- present: false,
787
- intuitive: 0, // a lot of people don't realise `some text \textit{in italics}` will protect 'in italics'
788
- };
789
- const ast = unified_latex_util_pegjs_1.LatexPegParser.parse(value);
790
- if (this.options.removeOuterBraces.includes(field) && ast.content.length === 1 && ast.content[0].type === 'group') {
791
- ast.content = ast.content[0].content;
792
- }
793
- if (mode === 'verbatim') { // &^%@#&^%@# idiots wrapping verbatim fields
794
- entry.fields[field] = (0, unified_latex_util_print_raw_1.printRaw)(ast);
795
- return;
796
- }
797
- if (this.english && mode === 'title') {
798
- let root = [...ast.content];
799
- while (root.length) {
800
- const node = root.shift();
801
- // only root groups offer case protecten -- but it may be as an macro arg, so mark here before gobbling
802
- if (this.protect(node))
803
- node._renderInfo = { root: true };
804
- // environments are considered root when at root
805
- if (node.type === 'environment')
806
- root = [...root, ...node.content];
807
- }
808
- }
809
- // pass 0 -- register parse mode
810
- (0, unified_latex_util_visit_1.visit)(ast, (node, info) => {
811
- if (!node._renderInfo)
812
- node._renderInfo = {};
813
- node._renderInfo.mode = info.context.inMathMode ? 'math' : 'text';
814
- // if (info.context.inMathMode || info.context.hasMathModeAncestor) return
815
- if (mode === 'title' && node.type === 'inlinemath' && !info.parents.find(p => p._renderInfo.protectCase))
816
- node._renderInfo.protectCase = true;
817
- if (!info.context.inMathMode) {
818
- if (mode === 'title' && node._renderInfo.root && (node.type !== 'group' || node.content[0].type !== 'macro')) {
819
- node._renderInfo.protectCase = true;
820
- if (node.type === 'group') {
821
- caseProtection.present = true;
822
- caseProtection.intuitive += 1;
823
- }
824
- }
825
- if (node.type === 'macro' && typeof node.escapeToken !== 'string')
826
- node.escapeToken = '\\';
827
- if (node.type === 'environment' && node.env === 'em')
828
- node._renderInfo.emph = true;
829
- }
830
- });
831
- if (this.options.raw) {
832
- switch (mode) {
833
- case 'creatorlist':
834
- entry.fields[field] = this.split(ast, /^and$/i, /(^& | & | &$)/)
835
- .map(cr => {
836
- const { parts, extended } = this.commaSeparatedCreator(cr);
837
- if (parts.length === 2 && !extended) {
838
- return this.trimCreator({ lastName: (0, unified_latex_util_print_raw_1.printRaw)(parts[0]), firstName: (0, unified_latex_util_print_raw_1.printRaw)(parts[1]) });
839
- }
840
- if (!parts.length) {
841
- const nameparts = this.split(ast, /^$/, /( )/);
842
- if (nameparts.length === 2) {
843
- return this.trimCreator({
844
- lastName: (0, unified_latex_util_print_raw_1.printRaw)(nameparts[1]),
845
- firstName: (0, unified_latex_util_print_raw_1.printRaw)(nameparts[0]),
846
- });
847
- }
848
- }
849
- return { name: (0, unified_latex_util_print_raw_1.printRaw)(cr) };
850
- });
851
- return;
852
- case 'literallist':
853
- entry.fields[field] = this.split(ast, /^and$/i, /(^& | & | &$)/)
854
- .map(elt => (0, unified_latex_util_print_raw_1.printRaw)(elt)); // pacify typescript
855
- return;
856
- default:
857
- entry.fields[field] = (0, unified_latex_util_print_raw_1.printRaw)(ast);
858
- return;
859
- }
860
- }
861
- // pass 1 -- mark & normalize
862
- (0, unified_latex_util_visit_1.visit)(ast, (nodes, info) => {
863
- var _a;
864
- let node;
865
- const compacted = [];
866
- let inif = 0;
867
- while (nodes.length) {
868
- if (node = this.ligature(nodes)) {
869
- compacted.push(node);
870
- continue;
871
- }
872
- node = nodes.shift();
873
- if (node.type === 'macro' && node.content === 'ifdefined') {
874
- inif += 1;
875
- continue;
876
- }
877
- else if (node.type === 'macro' && node.content === 'else') {
878
- continue;
879
- }
880
- else if (node.type === 'macro' && node.content === 'fi') {
881
- inif = Math.max(inif - 1, 0);
882
- continue;
883
- }
884
- else if (inif) {
885
- continue;
886
- }
887
- const nargs = node.type === 'macro'
888
- ? narguments[node.content] || narguments[`${info.context.inMathMode ? 'math' : 'text'}\t${node.content}`]
889
- : 0;
890
- if (node.type === 'macro' && nargs) {
891
- node.args = Array(nargs).fill(undefined).map(_i => this.argument(nodes, node)).filter(arg => arg);
892
- if (node.content.match(/^(url|href)$/) && node.args.length) {
893
- let url = node.args[0].content;
894
- if (url.length === 1 && url[0].type === 'group')
895
- url = url[0].content;
896
- node.args[0] = this.wraparg({ type: 'string', content: (0, unified_latex_util_print_raw_1.printRaw)(url), _renderInfo: { mode: url[0]._renderInfo.mode } }, node);
897
- }
898
- caseProtection.intuitive -= node.args.filter(arg => arg.content[0].type === 'group' && arg.content[0]._renderInfo.protectCase).length;
899
- }
900
- else if (node.type === 'macro' && node.content.match(/^[a-z]+$/i) && ((_a = nodes[0]) === null || _a === void 0 ? void 0 : _a.type) === 'whitespace') {
901
- nodes.shift();
902
- }
903
- compacted.push(node);
904
- }
905
- if (!info.context.inMathMode) {
906
- // feed-forward inline macros
907
- for (const [macro, markup] of Object.entries({ em: 'emph', it: 'emph', sl: 'emph', bf: 'bold', sc: 'smallCaps', tt: 'code' })) {
908
- if (info.parents.find(p => p._renderInfo[markup]))
909
- continue;
910
- compacted.forEach((markup_node, i) => {
911
- if (markup_node.type === 'macro' && markup_node.content === macro) {
912
- compacted.slice(i + 1).forEach(n => n._renderInfo[markup] = true);
913
- }
914
- });
915
- }
916
- }
917
- nodes.push(...compacted);
918
- }, { test: Array.isArray, includeArrays: true });
919
- (0, unified_latex_util_replace_1.replaceNode)(ast, (node, _info) => {
920
- if (node.type !== 'macro')
921
- return;
922
- if (node.escapeToken && unicode2latex_1.combining.tounicode[node.content]) {
923
- let arg;
924
- // no args, args of zero length, or first arg has no content
925
- if (!node.args || node.args.length === 0 || node.args[0].content.length === 0) {
926
- arg = { type: 'string', content: ' ', _renderInfo: {} };
927
- }
928
- else if (node.args.length !== 1 || node.args[0].content.length !== 1) {
929
- return;
930
- }
931
- else {
932
- arg = node.args[0].content[0];
933
- }
934
- if (arg.type === 'group') {
935
- switch (arg.content.length) {
936
- case 0:
937
- arg = { type: 'string', content: ' ', _renderInfo: {} };
938
- break;
939
- case 1:
940
- arg = arg.content[0];
941
- break;
942
- default:
943
- return;
944
- }
945
- }
946
- switch (arg.type) {
947
- case 'verbatim':
948
- case 'string':
949
- return { type: 'string', content: `${arg.content}${unicode2latex_1.combining.tounicode[node.content]}`, _renderInfo: {} };
950
- default:
951
- return;
952
- }
953
- }
954
- let latex = `${node.escapeToken}${node.content}`;
955
- latex += (node.args || []).map(arg => (0, unified_latex_util_print_raw_1.printRaw)(this.argtogroup(arg))).join('');
956
- if (latex in unicode2latex_1.latex2unicode)
957
- return { type: 'string', content: latex2unicode(latex, node), _renderInfo: {} };
958
- // return null to delete
959
- });
960
- switch (mode) {
961
- case 'creatorlist':
962
- entry.fields[field] = this.split(ast, /^and$/i, /(^& | & | &$)/)
963
- .map(cr => this.parseCreator(cr))
964
- .filter(cr => Object.keys(cr).length); // pacify typescript
965
- break;
966
- case 'literallist':
967
- entry.fields[field] = this.split(ast, /^and$/i, /(^& | & | &$)/)
968
- .map(elt => this.stringify(elt, { mode: 'literal' }).trim()); // pacify typescript
969
- break;
970
- default:
971
- entry.fields[field] = this.stringField(field, this.stringify(ast, { mode }), mode, this.options.sentenceCase && this.options.sentenceCase.guess);
972
- break;
973
- }
974
- // recursively restores markup in string content. 'as string' is just here to pacify typescript
975
- entry.fields[field] = JSON.parse(JSON.stringify(entry.fields[field], (k, v) => (typeof v === 'string' ? this.restoreMarkup(v) : v)));
976
- }
977
- reset(options = {}) {
978
- var _a;
979
- if (options.sentenceCase === false) {
980
- options = Object.assign(Object.assign({}, options), { english: false, sentenceCase: {
981
- guess: false,
982
- subSentence: false,
983
- preserveQuoted: false,
984
- } });
985
- }
986
- this.options = (0, merge_1.merge)(options, {
987
- caseProtection: 'as-needed',
988
- applyCrossRef: (_a = options.applyCrossRef) !== null && _a !== void 0 ? _a : true,
989
- fieldMode: {},
990
- english: exports.English,
991
- sentenceCase: {
992
- guess: true,
993
- preserveQuoted: true,
994
- },
995
- });
996
- if (this.options.caseProtection === true)
997
- this.options.caseProtection = 'as-needed';
998
- if (this.options.verbatimFields)
999
- this.options.verbatimFields = this.options.verbatimFields.map(f => typeof f === 'string' ? f.toLowerCase() : new RegExp(f.source, f.flags + (f.flags.includes('i') ? '' : 'i')));
1000
- if (typeof this.options.english === 'boolean')
1001
- this.options.english = this.options.english ? exports.English : [];
1002
- this.options.english = this.options.english.map(langid => langid.toLowerCase());
1003
- this.fieldMode = Object.entries(exports.FieldMode).reduce((acc, [mode, test]) => {
1004
- const strings = test.filter(fieldname_or_regex => typeof fieldname_or_regex === 'string' && !this.options.fieldMode[fieldname_or_regex]);
1005
- const regexes = test.filter(fieldname_or_regex => typeof fieldname_or_regex !== 'string');
1006
- acc[mode] = [...strings, ...regexes];
1007
- return acc;
1008
- }, {});
1009
- for (const [field, mode] of Object.entries(this.options.fieldMode)) {
1010
- this.fieldMode[mode].unshift(field);
1011
- }
1012
- if (!this.options.removeOuterBraces) {
1013
- this.options.removeOuterBraces = [
1014
- ...FieldAction.removeOuterBraces,
1015
- ...this.fieldMode.title,
1016
- ...this.fieldMode.verbatim,
1017
- ].filter(field => typeof field === 'string');
1018
- }
1019
- this.fallback = options.unsupported === 'ignore' ? ((_node, _tex) => '') : options.unsupported;
1020
- this.bib = {
1021
- errors: [],
1022
- entries: [],
1023
- comments: [],
1024
- strings: {},
1025
- preamble: [],
1026
- jabref: null,
1027
- };
1028
- }
1029
- reparse(verbatim) {
1030
- let langid = (verbatim.fields.langid || verbatim.fields.hyphenation || '').toLowerCase();
1031
- if (!langid && this.options.languageAsLangid && verbatim.fields.language)
1032
- langid = verbatim.fields.language.toLowerCase();
1033
- this.english = this.options.english.includes(langid);
1034
- const entry = this.current = {
1035
- type: verbatim.type,
1036
- key: verbatim.key,
1037
- fields: {},
1038
- mode: {},
1039
- input: verbatim.input,
1040
- };
1041
- let keywords = []; // OMG #783
1042
- try {
1043
- for (let [field, value] of Object.entries(verbatim.fields)) {
1044
- if (!value.trim())
1045
- continue;
1046
- /*
1047
- if (this.options.raw && !this.options.removeOuterBraces.includes(field)) {
1048
- entry.fields[field] = value.trim()
1049
- entry.mode[field] = 'verbatim'
1050
- continue
1051
- }
1052
- */
1053
- if (field.match(/^keywords([+]duplicate-\d+)?$/))
1054
- field = 'keywords'; // #873
1055
- this.field(entry, field, value);
1056
- if (field === 'keywords') { // #873
1057
- keywords = [...keywords, ...entry.fields.keywords.split(/\s*[,;]\s*/)].map((k) => k.trim()).filter(k => k);
1058
- delete entry.fields.keywords;
1059
- }
1060
- if (!this.options.raw && typeof entry.fields[field] === 'string') {
1061
- entry.fields[field] = entry.fields[field].trim();
1062
- if (field === 'month')
1063
- entry.fields[field] = Month[entry.fields[field].toLowerCase()] || entry.fields[field];
1064
- }
1065
- }
1066
- if (keywords.length) {
1067
- entry.fields.keywords = [...(new Set(keywords))].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
1068
- entry.mode.keywords = 'verbatimlist';
1069
- }
1070
- this.bib.entries.push(entry);
1071
- }
1072
- catch (err) {
1073
- this.bib.errors.push({ error: `${err.message}\n${entry.input}`, input: entry.input });
1074
- }
1075
- }
1076
- content(tex) {
1077
- const entry = { key: '', type: '', fields: {}, mode: {}, input: tex };
1078
- const english = this.english;
1079
- this.english = false;
1080
- this.field(entry, 'tex', tex);
1081
- this.english = english;
1082
- return entry.fields.tex;
1083
- }
1084
- prep(base) {
1085
- for (const preamble of base.preambles) {
1086
- try {
1087
- this.content(preamble);
1088
- }
1089
- catch (_a) {
1090
- }
1091
- }
1092
- for (const [k, v] of Object.entries(base.strings)) {
1093
- this.bib.strings[k] = this.content(v);
1094
- }
1095
- }
1096
- finalize(base) {
1097
- var _a;
1098
- if (this.options.applyCrossRef) {
1099
- const entries = {};
1100
- for (const entry of this.bib.entries) {
1101
- if (entry.key)
1102
- entries[entry.key.toUpperCase()] = entry;
1103
- }
1104
- const order = [];
1105
- for (const entry of this.bib.entries) {
1106
- if (!entry.key || typeof entry.fields.crossref !== 'string')
1107
- continue;
1108
- const crossref = entry.fields.crossref.toUpperCase();
1109
- if (!entries[crossref])
1110
- continue;
1111
- const key = entry.key.toUpperCase();
1112
- if (!order.includes(crossref))
1113
- order.unshift(crossref);
1114
- if (!order.includes(key))
1115
- order.push(key);
1116
- }
1117
- const add = (obj, kind, field) => {
1118
- obj[kind] = [...(new Set([...obj[kind], field]))].sort();
1119
- };
1120
- for (const key of order) {
1121
- const child = entries[key.toUpperCase()];
1122
- const parent = entries[(_a = child.fields.crossref) === null || _a === void 0 ? void 0 : _a.toUpperCase()];
1123
- if (!parent)
1124
- continue;
1125
- child.crossref = child.crossref || { donated: [], inherited: [] };
1126
- parent.crossref = parent.crossref || { donated: [], inherited: [] };
1127
- for (const mappings of [crossref_json_1.default[child.type], crossref_json_1.default['*']].filter(m => m)) {
1128
- for (const mapping of [mappings[parent.type], mappings['*']].filter(m => m)) {
1129
- for (const [childfield, parentfield] of Object.entries(mapping)) {
1130
- if (!child.fields[childfield] && parent.fields[parentfield]) {
1131
- child.fields[childfield] = parent.fields[parentfield];
1132
- add(child.crossref, 'inherited', childfield);
1133
- add(parent.crossref, 'donated', parentfield);
1134
- }
1135
- }
1136
- for (const field of (fields_json_1.default[child.type] || [])) {
1137
- if (FieldAction.noCrossRef.includes(field))
1138
- continue;
1139
- if (!child.fields[field] && parent.fields[field]) {
1140
- child.fields[field] = parent.fields[field];
1141
- add(child.crossref, 'inherited', field);
1142
- add(parent.crossref, 'donated', field);
1143
- }
1144
- }
1145
- }
1146
- }
1147
- }
1148
- for (const entry of this.bib.entries) {
1149
- if (entry.crossref && !entry.crossref.donated.length && !entry.crossref.inherited.length)
1150
- delete entry.crossref;
1151
- }
1152
- }
1153
- const { comments, jabref } = JabRef.parse(base.comments);
1154
- this.bib.comments = comments;
1155
- this.bib.jabref = jabref;
1156
- this.bib.preamble = base.preambles;
1157
- this.bib.errors = [...base.errors, ...this.bib.errors];
1158
- }
1159
- parse(input, options = {}) {
1160
- this.reset(options);
1161
- const base = bibtex.parse(input, { strings: options.strings });
1162
- this.prep(base);
1163
- for (const entry of base.entries) {
1164
- this.reparse(entry);
1165
- }
1166
- this.finalize(base);
1167
- return this.bib;
1168
- }
1169
- async parseAsync(input, options = {}) {
1170
- this.reset(options);
1171
- const base = await bibtex.promises.parse(input, { strings: options.strings });
1172
- this.prep(base);
1173
- let n = 1;
1174
- for (const entry of base.entries) {
1175
- this.reparse(entry);
1176
- if ((n++ % 1000) === 0)
1177
- await (0, yield_1.playnice)();
1178
- }
1179
- this.finalize(base);
1180
- return this.bib;
1181
- }
1182
- }
1183
- function parse(input, options = {}) {
1184
- const parser = new BibTeXParser();
1185
- return parser.parse(input, options);
1186
- }
1187
- async function parseAsync(input, options = {}) {
1188
- const parser = new BibTeXParser();
1189
- return await parser.parseAsync(input, options);
1190
- }
1191
- //# sourceMappingURL=index.js.map