@retorquere/bibtex-parser 7.0.15 → 8.0.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/grammar.js +107 -70
- package/index.d.ts +114 -221
- package/index.js +839 -1318
- package/package.json +28 -19
- package/sentence-case.d.ts +32 -1
- package/sentence-case.js +192 -79
- package/unabbrev.json +743 -749
- package/chunker.d.ts +0 -60
- package/chunker.js +0 -358
package/index.js
CHANGED
|
@@ -22,98 +22,61 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
26
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
27
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
28
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
29
|
+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
30
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
31
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
32
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
33
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
34
|
+
function fulfill(value) { resume("next", value); }
|
|
35
|
+
function reject(value) { resume("throw", value); }
|
|
36
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
37
|
+
};
|
|
38
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
39
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
40
|
+
var m = o[Symbol.asyncIterator], i;
|
|
41
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
42
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
43
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
44
|
+
};
|
|
25
45
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
46
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
47
|
};
|
|
28
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
const jabref = __importStar(require("./jabref"));
|
|
35
|
-
exports.jabref = jabref;
|
|
36
|
-
const jabref_1 = require("./jabref");
|
|
49
|
+
exports.parseAsync = exports.parse = exports.FieldMode = exports.toSentenceCase = void 0;
|
|
50
|
+
const unified_latex_util_replace_1 = require("@unified-latex/unified-latex-util-replace");
|
|
51
|
+
const unified_latex_util_pegjs_1 = require("@unified-latex/unified-latex-util-pegjs");
|
|
52
|
+
const unified_latex_util_visit_1 = require("@unified-latex/unified-latex-util-visit");
|
|
53
|
+
const unified_latex_util_print_raw_1 = require("@unified-latex/unified-latex-util-print-raw");
|
|
37
54
|
const unicode2latex_1 = require("unicode2latex");
|
|
38
|
-
const
|
|
39
|
-
const
|
|
55
|
+
const bibtex = __importStar(require("./verbatim"));
|
|
56
|
+
const JabRef = __importStar(require("./jabref"));
|
|
40
57
|
var sentence_case_1 = require("./sentence-case");
|
|
41
58
|
Object.defineProperty(exports, "toSentenceCase", { enumerable: true, get: function () { return sentence_case_1.toSentenceCase; } });
|
|
42
59
|
const sentence_case_2 = require("./sentence-case");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.node = node;
|
|
49
|
-
}
|
|
60
|
+
const crossref_json_1 = __importDefault(require("./crossref.json"));
|
|
61
|
+
const fields_json_1 = __importDefault(require("./fields.json"));
|
|
62
|
+
const unabbreviations = require('./unabbrev.json');
|
|
63
|
+
function latexMode(node) {
|
|
64
|
+
return node._renderInfo.mode;
|
|
50
65
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.node = node;
|
|
57
|
-
this.text = text;
|
|
58
|
-
}
|
|
66
|
+
function latex2unicode(tex, node) {
|
|
67
|
+
const text = unicode2latex_1.latex2unicode[tex];
|
|
68
|
+
if (typeof text === 'string')
|
|
69
|
+
return text;
|
|
70
|
+
return text && text[latexMode(node)];
|
|
59
71
|
}
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
const open = {};
|
|
73
|
+
const close = {};
|
|
74
|
+
for (const tag of ['i', 'b', 'sc', 'nc', 'ncx', 'br', 'p', 'li', 'code']) {
|
|
75
|
+
open[tag] = `\x0E${tag}\x0F`;
|
|
76
|
+
close[tag] = `\x0E/${tag}\x0F`;
|
|
62
77
|
}
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
Lu: charCat(charCategories, ['Uppercase_Letter', 'Titlecase_Letter']),
|
|
66
|
-
Ll: charCat(charCategories, ['Lowercase_Letter']),
|
|
67
|
-
LnotLu: charCat(charCategories, ['Lowercase_Letter', 'Modifier_Letter', 'Other_Letter', 'Nonspacing_Mark', 'Spacing_Mark', 'Decimal_Number', 'Letter_Number']),
|
|
68
|
-
P: charCat(charCategories, ['Punctuation']),
|
|
69
|
-
L: charCat(charCategories, ['Letter']),
|
|
70
|
-
N: charCat(charCategories, ['Decimal_Number', 'Letter_Number']),
|
|
71
|
-
AlphaNum: charCat(charCategories, ['Letter', 'Decimal_Number', 'Letter_Number']),
|
|
72
|
-
LC: charCat(charCategories, ['Cased_Letter']),
|
|
73
|
-
};
|
|
74
|
-
const marker = {
|
|
75
|
-
and: '\u0001',
|
|
76
|
-
comma: '\u0002',
|
|
77
|
-
space: '\u0003',
|
|
78
|
-
literal: '\u0004',
|
|
79
|
-
markup: '\u0005',
|
|
80
|
-
re: {
|
|
81
|
-
and: /./,
|
|
82
|
-
comma: /./,
|
|
83
|
-
space: /./,
|
|
84
|
-
literal: /./,
|
|
85
|
-
literalName: /./,
|
|
86
|
-
},
|
|
87
|
-
clean(s) {
|
|
88
|
-
return s.replace(marker.re.space, ' ').replace(marker.re.comma, ', ').replace(marker.re.literal, '');
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
marker.re = {
|
|
92
|
-
and: new RegExp(marker.and, 'g'),
|
|
93
|
-
comma: new RegExp(marker.comma, 'g'),
|
|
94
|
-
space: new RegExp(marker.space, 'g'),
|
|
95
|
-
literal: new RegExp(marker.literal, 'g'),
|
|
96
|
-
literalName: new RegExp(`^${marker.literal}([^${marker.literal}]*)${marker.literal}$`),
|
|
97
|
-
};
|
|
98
|
-
const preserveCase = {
|
|
99
|
-
leadingCap: new RegExp(`^[${charClass.Lu}][${charClass.LnotLu}]+[${charClass.P}]?$`),
|
|
100
|
-
allCaps: new RegExp(`^[${charClass.Lu}${charClass.N}]{2,}$`),
|
|
101
|
-
allLower: new RegExp(`^[${charClass.Ll}${charClass.N}]{2,}$`),
|
|
102
|
-
joined: new RegExp(`^[${charClass.Lu}][${charClass.LnotLu}]*([-+][${charClass.L}${charClass.N}]+)*[${charClass.P}]*$`),
|
|
103
|
-
hasUpper: new RegExp(`[${charClass.Lu}]`),
|
|
104
|
-
hasLower: new RegExp(`[${charClass.Ll}]`),
|
|
105
|
-
isNumber: /^[0-9]+$/,
|
|
106
|
-
hasAlpha: new RegExp(`[${charClass.L}]`),
|
|
107
|
-
hasAlphaNum: new RegExp(`[${charClass.AlphaNum}]`),
|
|
108
|
-
notAlphaNum: new RegExp(`[^${charClass.AlphaNum}]`, 'g'),
|
|
109
|
-
sentenceStart: new RegExp(`(^|([\u2014:?!.]\\s+))[${charClass.Lu}]`, 'g'),
|
|
110
|
-
markup: /<\/?span[^>]*>/g,
|
|
111
|
-
acronym: new RegExp(`.*\\.${marker.markup}*[${charClass.Lu}]${marker.markup}*\\.$`),
|
|
112
|
-
notCaseSensitive: new RegExp(`[^${charClass.LC}]`),
|
|
113
|
-
isCaseSensitive: new RegExp(`[${charClass.LC}]`),
|
|
114
|
-
quoted: /("[^"]+")|(“[^“]+“)/g,
|
|
115
|
-
};
|
|
116
|
-
exports.fields = {
|
|
78
|
+
const collapsable = /\x0E\/([a-z]+)\x0F(\s*)\x0E\1\x0F/ig;
|
|
79
|
+
exports.FieldMode = {
|
|
117
80
|
creator: [
|
|
118
81
|
'author',
|
|
119
82
|
'bookauthor',
|
|
@@ -130,18 +93,15 @@ exports.fields = {
|
|
|
130
93
|
],
|
|
131
94
|
title: [
|
|
132
95
|
'title',
|
|
96
|
+
'subtitle',
|
|
133
97
|
'series',
|
|
134
98
|
'shorttitle',
|
|
135
99
|
'booktitle',
|
|
136
|
-
'type',
|
|
100
|
+
// 'type',
|
|
137
101
|
'origtitle',
|
|
138
102
|
'maintitle',
|
|
139
103
|
'eventtitle',
|
|
140
104
|
],
|
|
141
|
-
unnest: [
|
|
142
|
-
'publisher',
|
|
143
|
-
'location',
|
|
144
|
-
],
|
|
145
105
|
verbatim: [
|
|
146
106
|
'doi',
|
|
147
107
|
'eprint',
|
|
@@ -154,8 +114,10 @@ exports.fields = {
|
|
|
154
114
|
'verba',
|
|
155
115
|
'verbb',
|
|
156
116
|
'verbc',
|
|
117
|
+
/^citeulike-linkout-[0-9]+$/,
|
|
118
|
+
/^bdsk-url-[0-9]+$/,
|
|
157
119
|
],
|
|
158
|
-
|
|
120
|
+
richtext: [
|
|
159
121
|
'annotation',
|
|
160
122
|
'comment',
|
|
161
123
|
'annote',
|
|
@@ -163,13 +125,20 @@ exports.fields = {
|
|
|
163
125
|
'notes',
|
|
164
126
|
'note',
|
|
165
127
|
],
|
|
166
|
-
|
|
167
|
-
'
|
|
168
|
-
|
|
169
|
-
|
|
128
|
+
commalist: [
|
|
129
|
+
'keywords',
|
|
130
|
+
],
|
|
131
|
+
literallist: [
|
|
132
|
+
'institution',
|
|
133
|
+
'publisher',
|
|
134
|
+
'origpublisher',
|
|
135
|
+
'organization',
|
|
136
|
+
'location',
|
|
137
|
+
'origlocation',
|
|
170
138
|
],
|
|
171
139
|
};
|
|
172
|
-
const
|
|
140
|
+
const English = [
|
|
141
|
+
'',
|
|
173
142
|
'american',
|
|
174
143
|
'british',
|
|
175
144
|
'canadian',
|
|
@@ -195,1326 +164,878 @@ const english = [
|
|
|
195
164
|
'en-zw',
|
|
196
165
|
'anglais', // don't do this people
|
|
197
166
|
];
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
167
|
+
const FieldAction = {
|
|
168
|
+
removeOuterBraces: [
|
|
169
|
+
'doi',
|
|
170
|
+
// 'publisher',
|
|
171
|
+
// 'location',
|
|
172
|
+
],
|
|
173
|
+
unabbrev: [
|
|
174
|
+
'journal',
|
|
175
|
+
'journaltitle',
|
|
176
|
+
'journal-full',
|
|
177
|
+
'series',
|
|
178
|
+
],
|
|
179
|
+
parseInt: [
|
|
180
|
+
'year',
|
|
181
|
+
'month',
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
const narguments = {
|
|
185
|
+
ElsevierGlyph: 1,
|
|
186
|
+
bar: 1,
|
|
187
|
+
bibcyr: 1,
|
|
188
|
+
bibstring: 1,
|
|
189
|
+
chsf: 1,
|
|
190
|
+
cite: 1,
|
|
191
|
+
citeauthor: 1,
|
|
192
|
+
cyrchar: 1,
|
|
193
|
+
ding: 1,
|
|
194
|
+
emph: 1,
|
|
195
|
+
enquote: 1,
|
|
196
|
+
frac: 2,
|
|
197
|
+
href: 2,
|
|
198
|
+
hspace: 1,
|
|
199
|
+
mathrm: 1,
|
|
200
|
+
mbox: 1,
|
|
201
|
+
mkbibbold: 1,
|
|
202
|
+
mkbibemph: 1,
|
|
203
|
+
mkbibitalic: 1,
|
|
204
|
+
mkbibquote: 1,
|
|
205
|
+
newcommand: 2,
|
|
206
|
+
noopsort: 1,
|
|
207
|
+
ocirc: 1,
|
|
208
|
+
sb: 1,
|
|
209
|
+
section: 1,
|
|
210
|
+
sp: 1,
|
|
211
|
+
subsection: 1,
|
|
212
|
+
subsubsection: 1,
|
|
213
|
+
subsubsubsection: 1,
|
|
214
|
+
t: 1,
|
|
215
|
+
textbf: 1,
|
|
216
|
+
textcite: 1,
|
|
217
|
+
textit: 1,
|
|
218
|
+
textrm: 1,
|
|
219
|
+
textsc: 1,
|
|
220
|
+
textsl: 1,
|
|
221
|
+
textsubscript: 1,
|
|
222
|
+
textsuperscript: 1,
|
|
223
|
+
texttt: 1,
|
|
224
|
+
textup: 1,
|
|
225
|
+
url: 1,
|
|
226
|
+
vphantom: 1,
|
|
227
|
+
vspace: 1,
|
|
228
|
+
overline: 1,
|
|
229
|
+
// math
|
|
230
|
+
'math\t_': 1,
|
|
231
|
+
'math\t^': 1,
|
|
232
|
+
};
|
|
233
|
+
for (const m in unicode2latex_1.combining.tounicode) { // eslint-disable-line guard-for-in
|
|
234
|
+
narguments[m] = 1;
|
|
235
|
+
}
|
|
236
|
+
function asyncGenerator(array) {
|
|
237
|
+
return __asyncGenerator(this, arguments, function* asyncGenerator_1() {
|
|
238
|
+
for (const item of array) {
|
|
239
|
+
yield yield __await(yield __await(Promise.resolve(item)));
|
|
247
240
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.strings = {};
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
class BibTeXParser {
|
|
244
|
+
constructor() {
|
|
253
245
|
this.newcommands = {};
|
|
254
|
-
this.default_strings = {
|
|
255
|
-
JAN: [this.text('01')],
|
|
256
|
-
FEB: [this.text('02')],
|
|
257
|
-
MAR: [this.text('03')],
|
|
258
|
-
APR: [this.text('04')],
|
|
259
|
-
MAY: [this.text('05')],
|
|
260
|
-
JUN: [this.text('06')],
|
|
261
|
-
JUL: [this.text('07')],
|
|
262
|
-
AUG: [this.text('08')],
|
|
263
|
-
SEP: [this.text('09')],
|
|
264
|
-
OCT: [this.text('10')],
|
|
265
|
-
NOV: [this.text('11')],
|
|
266
|
-
DEC: [this.text('12')],
|
|
267
|
-
ACMCS: [this.text('ACM Computing Surveys')],
|
|
268
|
-
ACTA: [this.text('Acta Informatica')],
|
|
269
|
-
CACM: [this.text('Communications of the ACM')],
|
|
270
|
-
IBMJRD: [this.text('IBM Journal of Research and Development')],
|
|
271
|
-
IBMSJ: [this.text('IBM Systems Journal')],
|
|
272
|
-
IEEESE: [this.text('IEEE Transactions on Software Engineering')],
|
|
273
|
-
IEEETC: [this.text('IEEE Transactions on Computers')],
|
|
274
|
-
IEEETCAD: [this.text('IEEE Transactions on Computer-Aided Design of Integrated Circuits')],
|
|
275
|
-
IPL: [this.text('Information Processing Letters')],
|
|
276
|
-
JACM: [this.text('Journal of the ACM')],
|
|
277
|
-
JCSS: [this.text('Journal of Computer and System Sciences')],
|
|
278
|
-
SCP: [this.text('Science of Computer Programming')],
|
|
279
|
-
SICOMP: [this.text('SIAM Journal on Computing')],
|
|
280
|
-
TOCS: [this.text('ACM Transactions on Computer Systems')],
|
|
281
|
-
TODS: [this.text('ACM Transactions on Database Systems')],
|
|
282
|
-
TOG: [this.text('ACM Transactions on Graphics')],
|
|
283
|
-
TOMS: [this.text('ACM Transactions on Mathematical Software')],
|
|
284
|
-
TOOIS: [this.text('ACM Transactions on Office Information Systems')],
|
|
285
|
-
TOPLAS: [this.text('ACM Transactions on Programming Languages and Systems')],
|
|
286
|
-
TCS: [this.text('Theoretical Computer Science')],
|
|
287
|
-
};
|
|
288
|
-
if (typeof this.options.strings === 'string') {
|
|
289
|
-
const strings = this.options.strings;
|
|
290
|
-
this.options.strings = {};
|
|
291
|
-
this.parseChunk({ text: strings, offset: { pos: 0, line: 0 } });
|
|
292
|
-
this.preloaded_strings = this.strings;
|
|
293
|
-
this.strings = {};
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
this.preloaded_strings = {};
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
ast(input, clean = true) {
|
|
300
|
-
let parsed = [];
|
|
301
|
-
for (const chunk of chunker.parse(input)) {
|
|
302
|
-
const { children } = bibtex.parse(chunk.text, Object.assign(Object.assign({}, this.options), { combining: unicode2latex_1.combining.macros }));
|
|
303
|
-
if (clean)
|
|
304
|
-
this.clean(children);
|
|
305
|
-
parsed = parsed.concat(children);
|
|
306
|
-
}
|
|
307
|
-
return parsed;
|
|
308
|
-
}
|
|
309
|
-
parse(input) {
|
|
310
|
-
for (const chunk of chunker.parse(input)) {
|
|
311
|
-
this.parseChunk(chunk);
|
|
312
|
-
}
|
|
313
|
-
return this.parsed();
|
|
314
246
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
247
|
+
split(ast, sep, split) {
|
|
248
|
+
const roots = [];
|
|
249
|
+
const nodes = [...ast.content];
|
|
250
|
+
const types = nodes.map(node => {
|
|
251
|
+
if (node.type === 'whitespace')
|
|
252
|
+
return ' ';
|
|
253
|
+
if (node.type === 'string' && node.content.match(sep))
|
|
254
|
+
return '&';
|
|
255
|
+
return '.';
|
|
256
|
+
}).join('');
|
|
257
|
+
types.split(split).forEach((match, i) => {
|
|
258
|
+
const content = match.length ? nodes.splice(0, match.length) : [];
|
|
259
|
+
if ((i % 2) === 0)
|
|
260
|
+
roots.push({ type: 'root', content });
|
|
261
|
+
});
|
|
262
|
+
return roots;
|
|
321
263
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
child[field][childfield] = parent[field][parentfield];
|
|
327
|
-
applied = true;
|
|
328
|
-
if (!child.crossref.inherited.includes(childfield))
|
|
329
|
-
child.crossref.inherited.push(childfield);
|
|
330
|
-
if (!parent.crossref.donated.includes(parentfield))
|
|
331
|
-
parent.crossref.donated.push(parentfield);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
return applied;
|
|
264
|
+
trimCreator(cr) {
|
|
265
|
+
// trims strings but coincidentally removes undefined fields
|
|
266
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
267
|
+
return JSON.parse(JSON.stringify(cr, (k, v) => typeof v === 'string' ? (v.trim() || undefined) : v));
|
|
335
268
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
}
|
|
269
|
+
parseCreator(ast) {
|
|
270
|
+
if (ast.content.length === 1 && ast.content[0].type === 'group')
|
|
271
|
+
return this.trimCreator({ name: this.stringify(ast, { mode: 'creator' }) });
|
|
272
|
+
if (ast.content.find(node => node.type === 'string' && node.content === ',')) {
|
|
273
|
+
const nameparts = this.split(ast, /^,$/, /(&)/).map((part) => this.stringify(part, { mode: 'creator' }).trim());
|
|
274
|
+
const extended = nameparts.every(p => p.match(/^[a-z][-a-z]+\s*=/i));
|
|
275
|
+
if (!extended) {
|
|
276
|
+
// eslint-disable-next-line no-magic-numbers
|
|
277
|
+
if (nameparts.length === 3 && nameparts[2] === '')
|
|
278
|
+
nameparts.pop();
|
|
279
|
+
// eslint-disable-next-line no-magic-numbers
|
|
280
|
+
if (nameparts.length > 3) {
|
|
281
|
+
const key = this.current.key ? `@${this.current.key}: ` : '';
|
|
282
|
+
this.bib.errors.push({
|
|
283
|
+
// eslint-disable-next-line no-magic-numbers
|
|
284
|
+
error: `${key}unexpected ${nameparts.length}-part name "${nameparts.join(', ')}", dropping "${nameparts.slice(3).join(', ')}"`,
|
|
285
|
+
input: nameparts.join(', '),
|
|
286
|
+
});
|
|
356
287
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
lower: 0,
|
|
375
|
-
other: 0,
|
|
376
|
-
},
|
|
377
|
-
};
|
|
378
|
-
this.convert(this.clean(value));
|
|
379
|
-
strings[key] = this.field.text;
|
|
380
|
-
}
|
|
381
|
-
if (this.options.applyCrossRef) {
|
|
382
|
-
const entries = this.entries.reduce((acc, entry) => {
|
|
383
|
-
acc[entry.key] = entry;
|
|
384
|
-
return acc;
|
|
385
|
-
}, {});
|
|
386
|
-
for (const entry of this.entries) {
|
|
387
|
-
this.applyCrossref(entry, entries);
|
|
288
|
+
let [lastName, suffix, firstName] = (nameparts.length === 2)
|
|
289
|
+
? [nameparts[0], undefined, nameparts[1]]
|
|
290
|
+
// > 3 nameparts are invalid and are dropped
|
|
291
|
+
// eslint-disable-next-line no-magic-numbers
|
|
292
|
+
: nameparts.slice(0, 3);
|
|
293
|
+
let prefix;
|
|
294
|
+
const m = lastName.match(/^([a-z'. ]+) (.+)/);
|
|
295
|
+
if (m) {
|
|
296
|
+
prefix = m[1];
|
|
297
|
+
lastName = m[2];
|
|
298
|
+
}
|
|
299
|
+
return this.trimCreator({
|
|
300
|
+
lastName,
|
|
301
|
+
firstName,
|
|
302
|
+
prefix,
|
|
303
|
+
suffix,
|
|
304
|
+
});
|
|
388
305
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
preserve(start, end, reason) {
|
|
401
|
-
if (!this.field.preserveRanges)
|
|
402
|
-
return;
|
|
403
|
-
if (!end) {
|
|
404
|
-
this.field.preserveRanges = null;
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
/*
|
|
408
|
-
this.field.preserveRanges = this.field.preserveRanges.filter(range => range.start < start || range.end > end)
|
|
409
|
-
if (this.field.preserveRanges.find(range => range.start <= start && range.end >= end)) return
|
|
410
|
-
*/
|
|
411
|
-
/*
|
|
412
|
-
if (this.field.preserveRanges && this.field.preserveRanges.length) {
|
|
413
|
-
const last = this.field.preserveRanges[this.field.preserveRanges.length - 1]
|
|
414
|
-
if (start < last.start) throw new Error(JSON.stringify({...last, new: { start, end, reason }, text: this.field.text}))
|
|
415
|
-
}
|
|
416
|
-
*/
|
|
417
|
-
this.field.preserveRanges.push({ start, end, description: reason });
|
|
418
|
-
}
|
|
419
|
-
parseChunk(chunk) {
|
|
420
|
-
this.chunk = chunk.text;
|
|
421
|
-
try {
|
|
422
|
-
let bib = bibtex.parse(chunk.text, Object.assign(Object.assign({}, this.options), { combining: unicode2latex_1.combining.macros }));
|
|
423
|
-
if (bib.kind !== 'Bibliography')
|
|
424
|
-
throw new Error(this.show(bib));
|
|
425
|
-
bib = this.clean(bib);
|
|
426
|
-
for (const entity of bib.children) {
|
|
427
|
-
switch (entity.kind) {
|
|
428
|
-
case 'Entry':
|
|
429
|
-
case 'BracedComment':
|
|
430
|
-
case 'LineComment':
|
|
431
|
-
case 'PreambleExpression':
|
|
432
|
-
this.convert(entity);
|
|
306
|
+
const name = {};
|
|
307
|
+
// eslint-disable-next-line no-magic-numbers
|
|
308
|
+
for (let [attr, value] of nameparts.map(p => { var _a; return (_a = p.match(/^([^=]+)=(.*)/)) === null || _a === void 0 ? void 0 : _a.slice(1, 3); })) {
|
|
309
|
+
attr = attr.toLowerCase();
|
|
310
|
+
switch (attr) {
|
|
311
|
+
case '':
|
|
312
|
+
break;
|
|
313
|
+
case 'given':
|
|
314
|
+
name.firstName = value;
|
|
433
315
|
break;
|
|
434
|
-
case '
|
|
435
|
-
|
|
316
|
+
case 'family':
|
|
317
|
+
name.lastName = value;
|
|
318
|
+
break;
|
|
319
|
+
case 'given-i':
|
|
320
|
+
name.initial = value;
|
|
321
|
+
break;
|
|
322
|
+
case 'useprefix':
|
|
323
|
+
case 'juniorcomma':
|
|
324
|
+
name[attr] = value.toLowerCase() === 'true';
|
|
325
|
+
break;
|
|
326
|
+
default:
|
|
327
|
+
name[attr] = value;
|
|
436
328
|
break;
|
|
437
329
|
}
|
|
438
330
|
}
|
|
439
|
-
return
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
331
|
+
return this.trimCreator(name);
|
|
332
|
+
}
|
|
333
|
+
else { // first-last mode
|
|
334
|
+
const nameparts = this.split(ast, /^$/, /( )/).map(part => this.stringify(part, { mode: 'creator' })).filter(n => n);
|
|
335
|
+
if (nameparts.length === 1)
|
|
336
|
+
return this.trimCreator({ lastName: nameparts[0] });
|
|
337
|
+
const prefix = nameparts.findIndex(n => n.match(/^[a-z]/));
|
|
338
|
+
const postfix = prefix <= 0 ? -1 : nameparts.findIndex((n, i) => i > prefix && !n.match(/^[a-z]/));
|
|
339
|
+
if (postfix === -1) {
|
|
340
|
+
const lastName = nameparts.pop();
|
|
341
|
+
return this.trimCreator({ lastName, firstName: nameparts.join(' ') });
|
|
342
|
+
}
|
|
343
|
+
return this.trimCreator({
|
|
344
|
+
firstName: nameparts.slice(0, prefix).join(' '),
|
|
345
|
+
prefix: nameparts.slice(prefix, postfix).join(' '),
|
|
346
|
+
lastName: nameparts.slice(postfix).join(' '),
|
|
451
347
|
});
|
|
452
|
-
return null;
|
|
453
348
|
}
|
|
454
349
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
condense(node) {
|
|
471
|
-
// apply cleaning to resulting children
|
|
472
|
-
node.value = this.clean(node.value);
|
|
473
|
-
// unpack redundant blocks
|
|
474
|
-
node.value = node.value.reduce((acc, child) => {
|
|
475
|
-
if (child.kind === 'Block' && !child.case && Object.keys(child.markup).length === 0) {
|
|
476
|
-
acc = acc.concat(child.value);
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
acc.push(child);
|
|
480
|
-
}
|
|
481
|
-
return acc;
|
|
482
|
-
}, []);
|
|
483
|
-
// condense text nodes to make whole words for sentence casing
|
|
484
|
-
node.value = node.value.reduce((acc, child, i) => {
|
|
485
|
-
if (acc.length === 0) {
|
|
486
|
-
acc.push(child);
|
|
487
|
-
return acc;
|
|
488
|
-
}
|
|
489
|
-
const last = acc[acc.length - 1];
|
|
490
|
-
const next = node.value[i + 1];
|
|
491
|
-
if (this.options.caseProtection === 'strict' && this.onlyCaseProtected(last) && child.kind === 'Text' && !child.value.match(preserveCase.isCaseSensitive) && this.onlyCaseProtected(next)) {
|
|
492
|
-
last.value.push(child);
|
|
493
|
-
delete last.source;
|
|
494
|
-
return acc;
|
|
495
|
-
}
|
|
496
|
-
if (last.kind === 'Block' && child.kind === 'Block' && Object.keys(last.markup).sort().join('/') === Object.keys(child.markup).sort().join('/')) {
|
|
497
|
-
last.value = last.value.concat(child.value);
|
|
498
|
-
delete last.source;
|
|
499
|
-
return acc;
|
|
500
|
-
}
|
|
501
|
-
if (last.kind === 'Text' && child.kind === 'Text' && last.mode === child.mode) {
|
|
502
|
-
last.value += child.value;
|
|
503
|
-
delete last.source;
|
|
504
|
-
return acc;
|
|
505
|
-
}
|
|
506
|
-
acc.push(child);
|
|
507
|
-
return acc;
|
|
508
|
-
}, []);
|
|
509
|
-
}
|
|
510
|
-
onlyCaseProtected(node) {
|
|
511
|
-
return (node === null || node === void 0 ? void 0 : node.kind) === 'Block' && node.case === 'protect' && Object.keys(node.markup).join('/') === '';
|
|
512
|
-
}
|
|
513
|
-
argument(node, kind) {
|
|
514
|
-
if (!node.arguments || !node.arguments.required.length)
|
|
515
|
-
return (kind === 'none');
|
|
516
|
-
// expect 'n' text arguments
|
|
517
|
-
if (typeof kind === 'number') {
|
|
518
|
-
return node.arguments.required.length === kind ? node.arguments.required : false;
|
|
519
|
-
}
|
|
520
|
-
// return first argument if it's the only one
|
|
521
|
-
if (node.arguments.required.length !== 1)
|
|
522
|
-
return false;
|
|
523
|
-
// loose checking for text
|
|
524
|
-
if (kind === 'text') {
|
|
525
|
-
const first = node.arguments.required[0];
|
|
526
|
-
if (first.kind === 'Block') {
|
|
527
|
-
switch (first.value.length) {
|
|
528
|
-
case 0:
|
|
529
|
-
return '';
|
|
530
|
-
case 1:
|
|
531
|
-
if (first.value[0].kind === 'Text')
|
|
532
|
-
return first.value[0].value;
|
|
533
|
-
break;
|
|
350
|
+
ligature(nodes) {
|
|
351
|
+
if (latexMode(nodes[0]) !== 'text')
|
|
352
|
+
return null;
|
|
353
|
+
const max = 3;
|
|
354
|
+
const slice = nodes.slice(0, max);
|
|
355
|
+
const type = slice.map(n => n.type === 'string' ? 's' : ' ').join('');
|
|
356
|
+
if (type[0] !== 's')
|
|
357
|
+
return null;
|
|
358
|
+
const content = slice.map(n => n.type === 'string' ? n.content : '');
|
|
359
|
+
let latex;
|
|
360
|
+
while (content.length) {
|
|
361
|
+
if (type.startsWith('s'.repeat(content.length)) && (latex = latex2unicode(content.join(''), slice[0]))) {
|
|
362
|
+
try {
|
|
363
|
+
return { type: 'string', content: latex, _renderInfo: {} };
|
|
534
364
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
kind = 'Text';
|
|
538
|
-
}
|
|
539
|
-
// return first argument if it's the only one and is of the specified kind
|
|
540
|
-
if (node.arguments.required.length !== 1 || node.arguments.required[0].kind !== kind)
|
|
541
|
-
return false;
|
|
542
|
-
switch (node.arguments.required[0].kind) {
|
|
543
|
-
case 'Text':
|
|
544
|
-
// no idea why eslint insists this is a @typescript-eslint/no-unsafe-return
|
|
545
|
-
return node.arguments.required[0].value;
|
|
546
|
-
case 'RegularCommand':
|
|
547
|
-
return node.arguments.required[0];
|
|
548
|
-
case 'Block':
|
|
549
|
-
return node.arguments.required[0];
|
|
550
|
-
}
|
|
551
|
-
return false;
|
|
552
|
-
}
|
|
553
|
-
isBreak(node, kind) {
|
|
554
|
-
return node && node.kind === 'RegularCommand' && kind.includes(node.command);
|
|
555
|
-
}
|
|
556
|
-
clean(node) {
|
|
557
|
-
if (Array.isArray(node)) {
|
|
558
|
-
return node
|
|
559
|
-
.filter((child, i) => !(this.isBreak(child, ['\\']) && this.isBreak(node[i - 1], ['\\', 'par']))) // condense linebreaks
|
|
560
|
-
.filter((child, i) => !this.isBreak(child, ['par']) || !this.isBreak(node[i - 1], ['par'])) // condense parbreaks
|
|
561
|
-
.map(child => this.clean(child)); // eslint-disable-line @typescript-eslint/no-unsafe-return
|
|
562
|
-
}
|
|
563
|
-
delete node.loc;
|
|
564
|
-
switch (node.kind) {
|
|
565
|
-
case 'InlineMath':
|
|
566
|
-
case 'DisplayMath':
|
|
567
|
-
return this.clean_block(node);
|
|
568
|
-
case 'Environment':
|
|
569
|
-
return this.clean_environment(node);
|
|
570
|
-
case 'Block':
|
|
571
|
-
return this.clean_block(node);
|
|
572
|
-
case 'Bibliography':
|
|
573
|
-
return this.clean_bib(node);
|
|
574
|
-
case 'RegularCommand':
|
|
575
|
-
return this.clean_command(node);
|
|
576
|
-
case 'DiacriticCommand':
|
|
577
|
-
return this.clean_diacritic(node);
|
|
578
|
-
case 'Entry':
|
|
579
|
-
return this.clean_entry(node);
|
|
580
|
-
case 'Field':
|
|
581
|
-
return this.options.raw ? node : this.clean_field(node);
|
|
582
|
-
case 'StringDeclaration':
|
|
583
|
-
return this.clean_stringdecl(node);
|
|
584
|
-
case 'StringReference':
|
|
585
|
-
return this.clean_stringref(node);
|
|
586
|
-
case 'SubscriptCommand':
|
|
587
|
-
case 'SuperscriptCommand':
|
|
588
|
-
return this.clean_script(node);
|
|
589
|
-
case 'SymbolCommand':
|
|
590
|
-
return this.clean_symbol(node);
|
|
591
|
-
case 'PreambleExpression':
|
|
592
|
-
return this.clean_preamble(node);
|
|
593
|
-
case 'Number':
|
|
594
|
-
case 'Text':
|
|
595
|
-
case 'BracedComment':
|
|
596
|
-
case 'LineComment':
|
|
597
|
-
case 'NonEntryText':
|
|
598
|
-
return node;
|
|
599
|
-
default:
|
|
600
|
-
return this.error(new ParserError(`no cleanup method for ${this.show(node)}`, node), this.text());
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
clean_preamble(node) {
|
|
604
|
-
this.in_preamble = true;
|
|
605
|
-
try {
|
|
606
|
-
return this.clean(node.value);
|
|
607
|
-
}
|
|
608
|
-
finally {
|
|
609
|
-
this.in_preamble = false;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
clean_bib(node) {
|
|
613
|
-
node.children = node.children.filter(child => child.kind !== 'NonEntryText').map(child => this.clean(child));
|
|
614
|
-
return node;
|
|
615
|
-
}
|
|
616
|
-
clean_stringdecl(node) {
|
|
617
|
-
this.strings[node.name.toUpperCase()] = node.value;
|
|
618
|
-
return node;
|
|
619
|
-
}
|
|
620
|
-
clean_stringref(node) {
|
|
621
|
-
const name = node.name.toUpperCase();
|
|
622
|
-
const stringvalue = this.strings[name]
|
|
623
|
-
|| this.options.strings[name]
|
|
624
|
-
|| this.preloaded_strings[name]
|
|
625
|
-
|| this.default_strings[name]
|
|
626
|
-
|| (exports.fields.unabbrev.includes(this.cleaning.name) && this.options.unabbreviate[name] && [this.text(this.options.unabbreviate[name])]);
|
|
627
|
-
if (!stringvalue) {
|
|
628
|
-
if (!this.unresolvedStrings[name])
|
|
629
|
-
this.errors.push({ message: `Unresolved @string reference ${JSON.stringify(node.name)}` });
|
|
630
|
-
this.unresolvedStrings[name] = true;
|
|
631
|
-
}
|
|
632
|
-
return this.clean({
|
|
633
|
-
kind: 'Block',
|
|
634
|
-
// if the string isn't found, add it as-is but exempt it from sentence casing
|
|
635
|
-
case: stringvalue ? undefined : 'preserve',
|
|
636
|
-
markup: {},
|
|
637
|
-
value: stringvalue ? JSON.parse(JSON.stringify(stringvalue)) : [this.text(node.name)],
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
clean_entry(node) {
|
|
641
|
-
const shortjournals = [];
|
|
642
|
-
for (const field of node.fields) {
|
|
643
|
-
if (exports.fields.unabbrev.includes(field.name) && Array.isArray(field.value)) {
|
|
644
|
-
const abbr = field.value.map(v => v.source).join('').toUpperCase();
|
|
645
|
-
const journal = this.options.unabbreviate[abbr];
|
|
646
|
-
if (journal) {
|
|
647
|
-
shortjournals.push(Object.assign(Object.assign({}, JSON.parse(JSON.stringify(field))), { name: 'shortjournal' }));
|
|
648
|
-
field.value = [this.text(journal)];
|
|
365
|
+
finally {
|
|
366
|
+
nodes.splice(0, content.length);
|
|
649
367
|
}
|
|
650
368
|
}
|
|
369
|
+
content.pop();
|
|
651
370
|
}
|
|
652
|
-
|
|
653
|
-
return node;
|
|
371
|
+
return null;
|
|
654
372
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
373
|
+
wraparg(node, macro) {
|
|
374
|
+
if (macro.content.match(/^(itshape|textsl|textit|emph|mkbibemph)$/))
|
|
375
|
+
node._renderInfo.emph = true;
|
|
376
|
+
if (macro.content.match(/^(textbf|mkbibbold|bfseries)$/))
|
|
377
|
+
node._renderInfo.bold = true;
|
|
378
|
+
if (macro.content.match(/^(textsc)$/))
|
|
379
|
+
node._renderInfo.smallCaps = true;
|
|
380
|
+
if (macro.content.match(/^(texttt)$/))
|
|
381
|
+
node._renderInfo.code = true;
|
|
382
|
+
return { type: 'argument', content: [node], openMark: '', closeMark: '', _renderInfo: { mode: node._renderInfo.mode } };
|
|
666
383
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
if (['chsf', 'bibstring', 'cite'].includes(node.command))
|
|
672
|
-
strip = true;
|
|
673
|
-
node.arguments.required.map(arg => this.stripNoCase(arg, strip, preserve));
|
|
674
|
-
break;
|
|
675
|
-
case 'Block':
|
|
676
|
-
case 'InlineMath':
|
|
677
|
-
case 'DisplayMath':
|
|
678
|
-
if (strip && node.case === 'protect') {
|
|
679
|
-
if (preserve) {
|
|
680
|
-
node.case = 'preserve';
|
|
681
|
-
}
|
|
682
|
-
else {
|
|
683
|
-
delete node.case;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
node.value.map(v => this.stripNoCase(v, strip || node.case === 'protect', preserve));
|
|
687
|
-
break;
|
|
688
|
-
case 'Field':
|
|
689
|
-
if (Array.isArray(node.value))
|
|
690
|
-
node.value.forEach(v => this.stripNoCase(v, strip, preserve));
|
|
691
|
-
break;
|
|
692
|
-
}
|
|
384
|
+
argtogroup(node) {
|
|
385
|
+
if (node.content.length === 1 && node.content[0].type === 'group')
|
|
386
|
+
return node.content[0];
|
|
387
|
+
return { type: 'group', content: node.content };
|
|
693
388
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
return this.text(singlechar);
|
|
711
|
-
if ((m = node.source.match(/^([\^_])\{([^{}]+)\}$/)) && ((singlechar = unicode2latex_1.latex2unicode[`${m[1]}${m[2]}`]) || (singlechar = unicode2latex_1.latex2unicode[`${m[1]}{${m[2]}}`])))
|
|
712
|
-
return this.text(singlechar);
|
|
713
|
-
const cmd = node.kind === 'SuperscriptCommand' ? '^' : '_';
|
|
714
|
-
if (typeof node.value === 'string' && (singlechar = unicode2latex_1.latex2unicode[`${cmd}${node.value}`] || unicode2latex_1.latex2unicode[`${cmd}{${node.value}}`])) {
|
|
715
|
-
return this.text(singlechar);
|
|
716
|
-
}
|
|
717
|
-
if (typeof node.value === 'string') {
|
|
718
|
-
value = [this.text(node.value)];
|
|
719
|
-
}
|
|
720
|
-
else if (!Array.isArray(node.value)) {
|
|
721
|
-
value = [node.value];
|
|
722
|
-
}
|
|
723
|
-
else {
|
|
724
|
-
value = node.value;
|
|
725
|
-
}
|
|
726
|
-
const mode = node.kind === 'SuperscriptCommand' ? 'sup' : 'sub';
|
|
727
|
-
return this.clean({
|
|
728
|
-
kind: 'Block',
|
|
729
|
-
markup: { [mode]: true },
|
|
730
|
-
value,
|
|
731
|
-
});
|
|
732
|
-
}
|
|
733
|
-
clean_environment(node) {
|
|
734
|
-
this.condense(node);
|
|
735
|
-
return node;
|
|
736
|
-
}
|
|
737
|
-
needsProtection(word) {
|
|
738
|
-
return !word.match(preserveCase.hasUpper) && !!word.match(preserveCase.hasLower);
|
|
389
|
+
argument(nodes, macro) {
|
|
390
|
+
if (!nodes.length)
|
|
391
|
+
return null;
|
|
392
|
+
if (nodes[0].type === 'whitespace')
|
|
393
|
+
nodes.shift();
|
|
394
|
+
if (!nodes.length)
|
|
395
|
+
return null;
|
|
396
|
+
if (nodes[0].type === 'string') {
|
|
397
|
+
const char = nodes[0].content[0];
|
|
398
|
+
nodes[0].content = nodes[0].content.substr(1);
|
|
399
|
+
const arg = Object.assign(Object.assign({}, nodes[0]), { content: char });
|
|
400
|
+
if (!nodes[0].content)
|
|
401
|
+
nodes.shift();
|
|
402
|
+
return this.wraparg(arg, macro);
|
|
403
|
+
}
|
|
404
|
+
return this.wraparg(nodes.shift(), macro);
|
|
739
405
|
}
|
|
740
|
-
|
|
406
|
+
unsupported(node) {
|
|
741
407
|
var _a;
|
|
742
|
-
this.
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
else {
|
|
752
|
-
preserve = false;
|
|
753
|
-
}
|
|
754
|
-
if (!preserve)
|
|
755
|
-
break;
|
|
756
|
-
}
|
|
757
|
-
if (preserve)
|
|
758
|
-
node.case = 'preserve';
|
|
759
|
-
}
|
|
760
|
-
if (node.kind === 'Block') {
|
|
761
|
-
for (const [markup, on] of Object.entries(node.markup)) {
|
|
762
|
-
if (!on)
|
|
763
|
-
delete node.markup[markup];
|
|
764
|
-
}
|
|
408
|
+
if (this.fallback)
|
|
409
|
+
return (_a = this.fallback(node, (0, unified_latex_util_print_raw_1.printRaw)(node), this.current)) !== null && _a !== void 0 ? _a : '';
|
|
410
|
+
switch (node.type) {
|
|
411
|
+
case 'macro':
|
|
412
|
+
throw new Error(`unhandled ${node.type} ${node.content} (${(0, unified_latex_util_print_raw_1.printRaw)(node)})`);
|
|
413
|
+
case 'environment':
|
|
414
|
+
throw new Error(`unhandled ${node.type} ${node.env} (${(0, unified_latex_util_print_raw_1.printRaw)(node)})`);
|
|
415
|
+
default:
|
|
416
|
+
throw new Error(`unhandled ${node.type} (${(0, unified_latex_util_print_raw_1.printRaw)(node)})`);
|
|
765
417
|
}
|
|
766
|
-
return node;
|
|
767
418
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|| unicode2latex_1.latex2unicode[`{\\${node.mark} ${char}}`]
|
|
773
|
-
|| unicode2latex_1.latex2unicode[`{\\${node.mark}${char}}`]
|
|
774
|
-
|| unicode2latex_1.latex2unicode[`\\${node.mark} ${char}`];
|
|
775
|
-
if (!unicode && !node.dotless && node.character.length === 1 && unicode2latex_1.combining.tounicode[node.mark])
|
|
776
|
-
unicode = node.character + unicode2latex_1.combining.tounicode[node.mark];
|
|
777
|
-
if (!unicode && !this.in_preamble)
|
|
778
|
-
return this.error(new TeXError(`Unhandled \\${node.mark}{${char}}`, node, this.chunk));
|
|
779
|
-
return this.text(unicode);
|
|
419
|
+
wrap(text, tag, wrap = true) {
|
|
420
|
+
if (!text || !wrap)
|
|
421
|
+
return text || '';
|
|
422
|
+
return `\x0E${tag}\x0F${text}\x0E/${tag}\x0F`;
|
|
780
423
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
424
|
+
registercommand(node) {
|
|
425
|
+
const types = (nodes) => nodes.map(n => n.type).join('.');
|
|
426
|
+
const group = (arg, kind) => {
|
|
427
|
+
if (!arg)
|
|
428
|
+
throw new Error(`missing ${kind} for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
|
|
429
|
+
if (types(arg.content) !== 'group')
|
|
430
|
+
throw new Error(`Malformed ${kind} for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
|
|
431
|
+
return arg.content[0].content;
|
|
432
|
+
};
|
|
433
|
+
if (!node.args)
|
|
434
|
+
throw new Error(`No arguments for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
|
|
435
|
+
const namearg = group(node.args[0], 'name');
|
|
436
|
+
if (types(namearg) !== 'macro')
|
|
437
|
+
throw new Error(`Unexpected name for ${(0, unified_latex_util_print_raw_1.printRaw)(node)} @ ${JSON.stringify(node.position)}`);
|
|
438
|
+
this.newcommands[namearg[0].content] = node.args[1];
|
|
439
|
+
return '';
|
|
785
440
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const candidate = this.first_text_block(child);
|
|
797
|
-
if (candidate)
|
|
798
|
-
return candidate;
|
|
799
|
-
break;
|
|
800
|
-
default:
|
|
801
|
-
return null;
|
|
802
|
-
}
|
|
441
|
+
subp(text, macro) {
|
|
442
|
+
let subp = '';
|
|
443
|
+
for (let char of text) {
|
|
444
|
+
char = unicode2latex_1.latex2unicode[`${macro}{${char}}`];
|
|
445
|
+
if (char) {
|
|
446
|
+
subp += char;
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
const tag = { _: 'sub', '^': 'sup' }[macro];
|
|
450
|
+
return `\x0E${tag}\x0F${text}\x0E/${tag}\x0F`;
|
|
803
451
|
}
|
|
804
452
|
}
|
|
805
|
-
|
|
806
|
-
return null;
|
|
807
|
-
}
|
|
453
|
+
return subp;
|
|
808
454
|
}
|
|
809
|
-
|
|
810
|
-
var _a;
|
|
811
|
-
|
|
812
|
-
if (
|
|
813
|
-
return
|
|
814
|
-
|
|
455
|
+
macro(node, context) {
|
|
456
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
457
|
+
const text = latex2unicode((0, unified_latex_util_print_raw_1.printRaw)(node), node);
|
|
458
|
+
if (text)
|
|
459
|
+
return text;
|
|
460
|
+
let url;
|
|
461
|
+
let label;
|
|
462
|
+
let arg;
|
|
463
|
+
let resolved;
|
|
464
|
+
switch (node.content) {
|
|
815
465
|
case 'newcommand':
|
|
816
|
-
|
|
817
|
-
&& node.arguments.required[0].kind === 'Block'
|
|
818
|
-
&& node.arguments.required[0].value.length === 1
|
|
819
|
-
&& node.arguments.required[0].value[0].kind === 'RegularCommand'
|
|
820
|
-
&& node.arguments.required[1].kind === 'Block') {
|
|
821
|
-
this.newcommands[node.arguments.required[0].value[0].command] = node.arguments.required[1].value;
|
|
822
|
-
return this.text();
|
|
823
|
-
}
|
|
824
|
-
// console.log('newcommand?', JSON.stringify(node, null, 2))
|
|
825
|
-
break;
|
|
826
|
-
case 'item':
|
|
827
|
-
return { kind: 'Markup', value: '<li>', source: node.source };
|
|
828
|
-
case 'frac':
|
|
829
|
-
if (arg = this.argument(node, 2)) {
|
|
830
|
-
if (arg[0].kind === 'Text' && arg[1].kind === 'Text' && (unicode = unicode2latex_1.latex2unicode[`\\frac{${arg[0].value}}{${arg[1].value}}`]))
|
|
831
|
-
return this.text(unicode);
|
|
832
|
-
return this.clean({
|
|
833
|
-
kind: 'Block',
|
|
834
|
-
case: 'protect',
|
|
835
|
-
markup: {},
|
|
836
|
-
value: [
|
|
837
|
-
{ kind: 'Block', markup: { sup: true }, value: [arg[0]] },
|
|
838
|
-
this.text('\u2044'),
|
|
839
|
-
{ kind: 'Block', markup: { sub: true }, value: [arg[1]] },
|
|
840
|
-
],
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
break;
|
|
844
|
-
// ignore
|
|
845
|
-
case 'vspace':
|
|
466
|
+
return this.registercommand(node);
|
|
846
467
|
case 'vphantom':
|
|
847
|
-
case 'path':
|
|
848
|
-
case 'aftergroup':
|
|
849
|
-
case 'ignorespaces':
|
|
850
|
-
case 'relax':
|
|
851
468
|
case 'noopsort':
|
|
852
|
-
case '
|
|
853
|
-
case '
|
|
854
|
-
|
|
855
|
-
case '
|
|
856
|
-
|
|
857
|
-
case '
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
return this.text(unicode);
|
|
863
|
-
return this.text(String.fromCharCode(parseInt(arg, 16)));
|
|
469
|
+
case 'left':
|
|
470
|
+
case 'right':
|
|
471
|
+
return '';
|
|
472
|
+
case 'path':
|
|
473
|
+
return ''; // until https://github.com/siefkenj/unified-latex/issues/94 is fixed
|
|
474
|
+
case 'hspace':
|
|
475
|
+
if (node.args && node.args.length) {
|
|
476
|
+
if ((0, unified_latex_util_print_raw_1.printRaw)(node.args).match(/^[{]?0[a-z]*$/))
|
|
477
|
+
return '';
|
|
478
|
+
return ' ';
|
|
864
479
|
}
|
|
865
|
-
|
|
866
|
-
case '
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
if (arg = this.argument(node, 'Block'))
|
|
870
|
-
return this.clean(arg);
|
|
871
|
-
break;
|
|
872
|
-
case 'enquote':
|
|
873
|
-
case 'mkbibquote':
|
|
874
|
-
case 'bibstring':
|
|
875
|
-
case 'cite':
|
|
876
|
-
case 'textcite':
|
|
480
|
+
return '';
|
|
481
|
+
case 'overline':
|
|
482
|
+
case 'bar':
|
|
483
|
+
return node.args.map(a => this.stringify(a, context)).join('').replace(/[a-z0-9]/ig, m => `${m}\u0305`);
|
|
877
484
|
case 'textup':
|
|
878
|
-
case 'citeauthor':
|
|
879
485
|
case 'textsc':
|
|
880
|
-
case '
|
|
486
|
+
case 'textrm':
|
|
881
487
|
case 'texttt':
|
|
882
|
-
case 'mkbibbold':
|
|
883
|
-
case 'section':
|
|
884
|
-
case 'subsection':
|
|
885
|
-
case 'subsubsection':
|
|
886
|
-
case 'subsubsubsection':
|
|
887
|
-
if (arg = this.argument(node, 'Block'))
|
|
888
|
-
return this.clean(arg);
|
|
889
|
-
break;
|
|
890
|
-
case 'textsuperscript':
|
|
891
|
-
case 'sp':
|
|
892
|
-
if ((arg = this.argument(node, 'Text')) && (unicode = unicode2latex_1.latex2unicode[`^{${arg}}`]))
|
|
893
|
-
return this.text(unicode);
|
|
894
|
-
if (arg = this.argument(node, 'Block'))
|
|
895
|
-
return this.clean(arg);
|
|
896
|
-
break;
|
|
897
|
-
case 'textsubscript':
|
|
898
|
-
case 'sb':
|
|
899
|
-
if ((arg = this.argument(node, 'Text')) && (unicode = unicode2latex_1.latex2unicode[`_{${arg}}`]))
|
|
900
|
-
return this.text(unicode);
|
|
901
|
-
if (arg = this.argument(node, 'Block'))
|
|
902
|
-
return this.clean(arg);
|
|
903
|
-
break;
|
|
904
|
-
case 'mkbibitalic':
|
|
905
|
-
case 'mkbibemph':
|
|
906
|
-
case 'textit':
|
|
907
|
-
case 'emph':
|
|
908
|
-
if (arg = this.argument(node, 'Block'))
|
|
909
|
-
return this.clean(arg);
|
|
910
|
-
if (arg = this.argument(node, 'Text'))
|
|
911
|
-
return this.clean({ kind: 'Block', markup: { italics: true }, value: [this.text(arg)] });
|
|
912
|
-
break;
|
|
913
|
-
case 'bibcyr':
|
|
914
|
-
if (this.argument(node, 'none'))
|
|
915
|
-
return this.text();
|
|
916
|
-
if (arg = this.argument(node, 'Block'))
|
|
917
|
-
return this.clean(arg);
|
|
918
|
-
break;
|
|
919
|
-
case 'hspace':
|
|
920
488
|
case 'mathrm':
|
|
921
|
-
case 'textrm':
|
|
922
|
-
case 'ocirc':
|
|
923
489
|
case 'mbox':
|
|
924
|
-
|
|
925
|
-
if (node.command === 'mbox' && !arg)
|
|
926
|
-
return this.text('\u200b');
|
|
927
|
-
unicode = unicode2latex_1.latex2unicode[`\\${node.command}{${arg}}`];
|
|
928
|
-
return this.text(unicode || (node.command === 'hspace' ? ' ' : arg));
|
|
929
|
-
}
|
|
930
|
-
else if (!node.arguments.required.length) {
|
|
931
|
-
return (node.command === 'mbox') ? this.text('\u200b') : this.text();
|
|
932
|
-
}
|
|
933
|
-
else if (arg = this.argument(node, 'Block')) {
|
|
934
|
-
return this.clean(arg);
|
|
935
|
-
}
|
|
936
|
-
break;
|
|
490
|
+
return node.args.map(n => this.stringify(n, context)).join('');
|
|
937
491
|
case 'href':
|
|
938
492
|
case 'url':
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
493
|
+
if (node.args) {
|
|
494
|
+
url = node.args[0];
|
|
495
|
+
label = node.args[node.content === 'url' ? 0 : 1];
|
|
496
|
+
}
|
|
497
|
+
return `<a href="${this.stringify(url, context)}">${this.stringify(label, context)}</a>`;
|
|
498
|
+
case 'relax':
|
|
499
|
+
case 'aftergroup':
|
|
500
|
+
case 'ignorespaces':
|
|
942
501
|
case 'em':
|
|
943
502
|
case 'it':
|
|
944
|
-
case 'itshape':
|
|
945
|
-
case 'bf':
|
|
946
|
-
case 'bfseries':
|
|
947
|
-
case 'sc':
|
|
948
|
-
case 'scshape':
|
|
949
503
|
case 'tt':
|
|
504
|
+
case 'sl':
|
|
505
|
+
return '';
|
|
950
506
|
case 'rm':
|
|
951
|
-
case '
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
case '
|
|
957
|
-
case '
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
case '
|
|
961
|
-
return node;
|
|
962
|
-
case '
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
507
|
+
case 'sc':
|
|
508
|
+
return '';
|
|
509
|
+
// bold/emph/smallcaps is handled in the wrapper
|
|
510
|
+
case 'textbf':
|
|
511
|
+
case 'mkbibbold':
|
|
512
|
+
case 'textit':
|
|
513
|
+
case 'emph':
|
|
514
|
+
case 'mkbibemph':
|
|
515
|
+
return this.stringify((_a = node.args) === null || _a === void 0 ? void 0 : _a[0], context);
|
|
516
|
+
case 'textsuperscript':
|
|
517
|
+
return this.subp(this.stringify((_b = node.args) === null || _b === void 0 ? void 0 : _b[0], context), '^');
|
|
518
|
+
case 'textsubscript':
|
|
519
|
+
return this.subp(this.stringify((_c = node.args) === null || _c === void 0 ? void 0 : _c[0], context), '_');
|
|
520
|
+
case '_':
|
|
521
|
+
case '^':
|
|
522
|
+
switch (latexMode(node)) {
|
|
523
|
+
case 'math':
|
|
524
|
+
return this.subp(this.stringify((_d = node.args) === null || _d === void 0 ? void 0 : _d[0], context), node.content);
|
|
525
|
+
default:
|
|
526
|
+
return node.content;
|
|
970
527
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
528
|
+
case 'LaTeX':
|
|
529
|
+
return this.wrap(`L${this.subp('A', '^')}T${this.subp('E', '_')}X`, 'ncx');
|
|
530
|
+
case 'enquote':
|
|
531
|
+
case 'mkbibquote':
|
|
532
|
+
return this.wrap(this.stringify((_e = node.args) === null || _e === void 0 ? void 0 : _e[0], context), 'enquote');
|
|
533
|
+
case '\\':
|
|
534
|
+
return context.mode === 'richtext' ? open.br : ' ';
|
|
535
|
+
case 'par':
|
|
536
|
+
return context.mode === 'richtext' ? open.p : ' ';
|
|
537
|
+
case 'item':
|
|
538
|
+
return context.mode === 'richtext' ? open.li : ' ';
|
|
539
|
+
case 'section':
|
|
540
|
+
case 'subsection':
|
|
541
|
+
case 'subsubsection':
|
|
542
|
+
case 'subsubsubsection':
|
|
543
|
+
return this.wrap(this.stringify((_f = node.args) === null || _f === void 0 ? void 0 : _f[0], context), `h${node.content.split('sub').length}`);
|
|
544
|
+
case 'frac':
|
|
545
|
+
arg = node.args.map(a => this.stringify(a, context));
|
|
546
|
+
if (arg.length === 2 && (resolved = unicode2latex_1.latex2unicode[`\\frac${arg.map(a => `{${a}}`).join('')}`]))
|
|
547
|
+
return resolved;
|
|
548
|
+
return arg.map((part, i) => this.subp(part, i ? '_' : '^')).join('\u2044');
|
|
549
|
+
case 'chsf':
|
|
550
|
+
case 'bibstring':
|
|
551
|
+
case 'cite':
|
|
552
|
+
case 'textcite':
|
|
553
|
+
case 'citeauthor':
|
|
554
|
+
// ncx protects but will be stripped later
|
|
555
|
+
return this.wrap(this.stringify((_g = node.args) === null || _g === void 0 ? void 0 : _g[0], context), 'ncx', context.mode === 'title');
|
|
974
556
|
default:
|
|
975
|
-
if (
|
|
976
|
-
return this.
|
|
977
|
-
|
|
978
|
-
markup: {},
|
|
979
|
-
value: JSON.parse(JSON.stringify(this.newcommands[node.command])),
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
if (unicode2latex_1.combining.tounicode[node.command]) {
|
|
983
|
-
node.arguments.required = this.clean(node.arguments.required);
|
|
984
|
-
let block;
|
|
985
|
-
if (node.arguments.required.length === 1 && node.arguments.required[0].kind === 'Text') {
|
|
986
|
-
// no idea why I can't just straight return this but typescript just won't shut up
|
|
987
|
-
block = {
|
|
988
|
-
kind: 'Block',
|
|
989
|
-
markup: {},
|
|
990
|
-
value: [{
|
|
991
|
-
kind: 'DiacriticCommand',
|
|
992
|
-
mark: node.command,
|
|
993
|
-
character: (node.arguments.required[0]).value,
|
|
994
|
-
dotless: false,
|
|
995
|
-
loc: node.arguments.required[0].loc,
|
|
996
|
-
source: node.arguments.required[0].source,
|
|
997
|
-
}],
|
|
998
|
-
};
|
|
999
|
-
return this.clean(block);
|
|
1000
|
-
}
|
|
1001
|
-
else if (block = this.first_text_block(node.arguments.required[0])) {
|
|
1002
|
-
let fixed = false;
|
|
1003
|
-
block.value = block.value.reduce((value, child) => {
|
|
1004
|
-
if (!fixed && child.kind === 'Text') {
|
|
1005
|
-
fixed = true;
|
|
1006
|
-
value.push({ kind: 'DiacriticCommand', mark: node.command, character: child.value[0] });
|
|
1007
|
-
value.push(Object.assign(Object.assign({}, child), { value: child.value.substring(1) }));
|
|
1008
|
-
}
|
|
1009
|
-
else {
|
|
1010
|
-
value.push(child);
|
|
1011
|
-
}
|
|
1012
|
-
return value;
|
|
1013
|
-
}, []);
|
|
1014
|
-
return this.clean({
|
|
1015
|
-
kind: 'Block',
|
|
1016
|
-
markup: {},
|
|
1017
|
-
value: node.arguments.required,
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
else {
|
|
1021
|
-
// overline without arguments doesn't seem to render in LaTeX
|
|
1022
|
-
if (node.command === 'overline')
|
|
1023
|
-
return this.text(' ');
|
|
1024
|
-
return this.clean({
|
|
1025
|
-
kind: 'Block',
|
|
1026
|
-
markup: {},
|
|
1027
|
-
value: [this.text(` ${unicode2latex_1.combining.tounicode[node.command]}`)].concat(node.arguments.required),
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
if (unicode = unicode2latex_1.latex2unicode[node.source] || unicode2latex_1.latex2unicode[`${node.source}{}`])
|
|
1032
|
-
return this.text(unicode);
|
|
1033
|
-
if ((unicode = unicode2latex_1.latex2unicode[`\\${node.command}`] || unicode2latex_1.latex2unicode[`\\${node.command}{}`]) && this.argument(node, 'none'))
|
|
1034
|
-
return this.text(unicode);
|
|
1035
|
-
if ((arg = this.argument(node, 'Text')) && (unicode = unicode2latex_1.latex2unicode[`\\${node.command}{${arg}}`]))
|
|
1036
|
-
return this.text(unicode);
|
|
1037
|
-
break;
|
|
557
|
+
if (this.newcommands[node.content])
|
|
558
|
+
return this.stringify(this.newcommands[node.content], context);
|
|
559
|
+
return this.unsupported(node);
|
|
1038
560
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
561
|
+
}
|
|
562
|
+
what(node) {
|
|
563
|
+
var _a;
|
|
564
|
+
if (!node)
|
|
565
|
+
return '';
|
|
566
|
+
switch (node.type) {
|
|
567
|
+
case 'macro': return `macro:${(_a = node._renderInfo.mode) !== null && _a !== void 0 ? _a : 'text'}:${node.content}`;
|
|
568
|
+
case 'environment': return `env:${node.env}`;
|
|
569
|
+
default: return node.type;
|
|
1043
570
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
571
|
+
}
|
|
572
|
+
environment(node, context) {
|
|
573
|
+
while (node.content.length && this.what(node.content[0]).match(/^parbreak|whitespace|macro:text:par$/))
|
|
574
|
+
node.content.shift();
|
|
575
|
+
while (node.content.length && this.what(node.content[node.content.length - 1]).match(/^parbreak|whitespace|macro:text:par$/))
|
|
576
|
+
node.content.pop();
|
|
577
|
+
switch (node.env) {
|
|
578
|
+
case 'quotation':
|
|
579
|
+
return this.wrap(node.content.map(n => this.stringify(n, context)).join(''), 'blockquote', context.mode === 'richtext');
|
|
580
|
+
case 'itemize':
|
|
581
|
+
return this.wrap(node.content.map(n => this.stringify(n, context)).join(''), 'ul', context.mode === 'richtext');
|
|
582
|
+
case 'em':
|
|
583
|
+
return this.wrap(node.content.map(n => this.stringify(n, context)).join(''), 'i', context.mode === 'richtext');
|
|
584
|
+
default:
|
|
585
|
+
return this.unsupported(node);
|
|
1046
586
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
587
|
+
}
|
|
588
|
+
stringify(node, context) {
|
|
589
|
+
let content = this.stringifyContent(node, context);
|
|
590
|
+
if (content && node._renderInfo) {
|
|
591
|
+
if (node._renderInfo.emph)
|
|
592
|
+
content = `${open.i}${content}${close.i}`;
|
|
593
|
+
if (node._renderInfo.bold)
|
|
594
|
+
content = `${open.b}${content}${close.b}`;
|
|
595
|
+
if (node._renderInfo.smallCaps)
|
|
596
|
+
content = `${open.sc}${content}${close.sc}`;
|
|
597
|
+
if (node._renderInfo.code)
|
|
598
|
+
content = `${open.code}${content}${close.code}`;
|
|
599
|
+
if (node._renderInfo.protectCase)
|
|
600
|
+
content = `${open.nc}${content}${close.nc}`;
|
|
601
|
+
}
|
|
602
|
+
return content;
|
|
603
|
+
}
|
|
604
|
+
stringifyContent(node, context) {
|
|
605
|
+
if (!node)
|
|
606
|
+
return '';
|
|
607
|
+
switch (node.type) {
|
|
608
|
+
case 'root':
|
|
609
|
+
case 'argument':
|
|
610
|
+
case 'group':
|
|
611
|
+
case 'inlinemath':
|
|
612
|
+
return node.content.map(n => this.stringify(n, context)).join('');
|
|
613
|
+
case 'string':
|
|
614
|
+
case 'verbatim':
|
|
615
|
+
return node.content;
|
|
616
|
+
case 'macro':
|
|
617
|
+
return this.macro(node, context);
|
|
618
|
+
case 'parbreak':
|
|
619
|
+
return context.mode === 'richtext' ? open.p : ' ';
|
|
620
|
+
case 'whitespace':
|
|
621
|
+
return node._renderInfo.mode === 'math' ? '' : ' ';
|
|
622
|
+
case 'comment':
|
|
623
|
+
return '';
|
|
624
|
+
case 'environment':
|
|
625
|
+
return this.environment(node, context);
|
|
626
|
+
case 'verb':
|
|
627
|
+
return node.content;
|
|
628
|
+
default:
|
|
629
|
+
return this.unsupported(node);
|
|
1049
630
|
}
|
|
1050
631
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
var _a, _b;
|
|
1054
|
-
if (!word.trim())
|
|
1055
|
-
return false;
|
|
1056
|
-
if (!word.match(preserveCase.hasAlphaNum))
|
|
1057
|
-
return true;
|
|
1058
|
-
word = word.replace(/[/’'”:()]/g, '');
|
|
1059
|
-
if (word === 'I')
|
|
632
|
+
protect(node) {
|
|
633
|
+
if (node.type === 'inlinemath')
|
|
1060
634
|
return true;
|
|
1061
|
-
if (
|
|
1062
|
-
return false;
|
|
1063
|
-
if (word.replace(preserveCase.notCaseSensitive) === '')
|
|
635
|
+
if (node.type !== 'group')
|
|
1064
636
|
return false;
|
|
1065
|
-
|
|
1066
|
-
// simple cap at start of field
|
|
1067
|
-
if (word.match(preserveCase.leadingCap) && ((_b = (_a = this.field) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.length) === 0)
|
|
637
|
+
if (!node.content.length)
|
|
1068
638
|
return false;
|
|
1069
|
-
|
|
1070
|
-
return true;
|
|
1071
|
-
if (word.length > 1 && word.match(preserveCase.joined))
|
|
1072
|
-
return false;
|
|
1073
|
-
if (word.match(preserveCase.hasUpper))
|
|
1074
|
-
return true;
|
|
1075
|
-
if (word.match(preserveCase.isNumber))
|
|
1076
|
-
return true;
|
|
1077
|
-
return false;
|
|
639
|
+
return (node.content[0].type !== 'macro');
|
|
1078
640
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
if (this.options.raw && this.field)
|
|
1085
|
-
node = this.text(node.source);
|
|
1086
|
-
switch (node.kind) {
|
|
1087
|
-
case 'Markup':
|
|
1088
|
-
if (this.field)
|
|
1089
|
-
this.field.text += node.value;
|
|
1090
|
-
break;
|
|
1091
|
-
case 'BracedComment':
|
|
1092
|
-
case 'LineComment':
|
|
1093
|
-
this.comments.push(node.value);
|
|
1094
|
-
break;
|
|
1095
|
-
case 'Entry':
|
|
1096
|
-
this.convert_entry(node);
|
|
1097
|
-
break;
|
|
1098
|
-
case 'Number':
|
|
1099
|
-
this.convert_number(node);
|
|
1100
|
-
break;
|
|
1101
|
-
case 'Text':
|
|
1102
|
-
this.convert_text(node);
|
|
1103
|
-
break;
|
|
1104
|
-
case 'Block':
|
|
1105
|
-
case 'InlineMath':
|
|
1106
|
-
case 'DisplayMath':
|
|
1107
|
-
// eslint-disable-next-line no-case-declarations
|
|
1108
|
-
const start = this.field ? this.field.text.length : null;
|
|
1109
|
-
// eslint-disable-next-line no-case-declarations
|
|
1110
|
-
const preserve = typeof start === 'number' && this.field.preserveRanges;
|
|
1111
|
-
this.convert_block(node);
|
|
1112
|
-
if (preserve && (node.case || node.kind.endsWith('Math')))
|
|
1113
|
-
this.preserve(start, this.field.text.length); // , `convert-block: case=${node.case}, math=${node.kind.endsWith('Math')}`)
|
|
1114
|
-
break;
|
|
1115
|
-
case 'Environment':
|
|
1116
|
-
this.convert_environment(node);
|
|
1117
|
-
break;
|
|
1118
|
-
case 'PreambleExpression':
|
|
1119
|
-
this.preamble.push(node.value.map(preamble => preamble.source).join('\n\n'));
|
|
1120
|
-
break;
|
|
1121
|
-
case 'StringDeclaration':
|
|
1122
|
-
break;
|
|
1123
|
-
default:
|
|
1124
|
-
if (node.kind === 'RegularCommand' && (node.command === 'href' || node.command === 'url')) {
|
|
1125
|
-
this.convert_href(node);
|
|
1126
|
-
}
|
|
1127
|
-
else if (node.kind === 'RegularCommand' && node.command === 'par') {
|
|
1128
|
-
this.field.text += this.field.html ? '<p>\n' : ' ';
|
|
1129
|
-
}
|
|
1130
|
-
else if (node.kind === 'RegularCommand' && node.command === '\\') {
|
|
1131
|
-
this.field.text += this.field.html ? '<b>\n' : ' ';
|
|
1132
|
-
}
|
|
1133
|
-
else {
|
|
1134
|
-
return this.error(new ParserError(`no converter for ${node.kind}: ${this.show(node)}`, node));
|
|
1135
|
-
}
|
|
641
|
+
mode(field) {
|
|
642
|
+
let mode = 'literal';
|
|
643
|
+
for (const [selected, fields] of Object.entries(this.fieldMode)) {
|
|
644
|
+
if (fields.find(match => typeof match === 'string' ? field === match : field.match(match)))
|
|
645
|
+
mode = selected;
|
|
1136
646
|
}
|
|
647
|
+
return mode;
|
|
1137
648
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
649
|
+
restoreMarkup(s) {
|
|
650
|
+
if (!s.includes('\x0E'))
|
|
651
|
+
return s;
|
|
652
|
+
const restored = [s.replace(/\x0E\/?ncx\x0F/ig, '')];
|
|
653
|
+
while (restored[0] !== restored[1]) {
|
|
654
|
+
restored.unshift(restored[0].replace(collapsable, '$2'));
|
|
655
|
+
}
|
|
656
|
+
return restored[0]
|
|
657
|
+
.replace(/(\x0Ep\x0F\s*){2,}/ig, '\x0Ep\x0F')
|
|
658
|
+
.replace(/\s*(\x0E\/p\x0F){2,}/ig, '\x0E/p\x0F')
|
|
659
|
+
.replace(/\x0Eenquote\x0F/ig, '\u201C').replace(/\x0E\/enquote\x0F/ig, '\u201D')
|
|
660
|
+
.replace(/\x0Esc\x0F/ig, '<span style="font-variant:small-caps;">').replace(/\x0E\/sc\x0F/ig, '</span>')
|
|
661
|
+
.replace(/\x0Enc\x0F/ig, '<span class="nocase">').replace(/\x0E\/nc\x0F/ig, '</span>')
|
|
662
|
+
.replace(/\x0E/ig, '<').replace(/\x0F/ig, '>');
|
|
1141
663
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
break;
|
|
1152
|
-
}
|
|
1153
|
-
switch (attr.toLowerCase()) {
|
|
1154
|
-
case 'family':
|
|
1155
|
-
parsed.lastName = value;
|
|
1156
|
-
break;
|
|
1157
|
-
case 'given-i':
|
|
1158
|
-
parsed.initial = value;
|
|
1159
|
-
break;
|
|
1160
|
-
case 'given':
|
|
1161
|
-
parsed.firstName = value;
|
|
1162
|
-
break;
|
|
1163
|
-
case 'prefix':
|
|
1164
|
-
parsed.prefix = value;
|
|
1165
|
-
break;
|
|
1166
|
-
case 'suffix':
|
|
1167
|
-
parsed.suffix = value;
|
|
1168
|
-
break;
|
|
1169
|
-
case 'useprefix':
|
|
1170
|
-
parsed.useprefix = value.toLowerCase() === 'true';
|
|
1171
|
-
break;
|
|
1172
|
-
case 'juniorcomma':
|
|
1173
|
-
parsed.useprefix = value.toLowerCase() === 'true';
|
|
1174
|
-
break;
|
|
1175
|
-
default:
|
|
1176
|
-
parsed[attr.toLowerCase()] = value;
|
|
1177
|
-
break;
|
|
664
|
+
stringField(field, value, sentenceCase, mode) {
|
|
665
|
+
if (FieldAction.unabbrev.includes(field)) {
|
|
666
|
+
let full = this.options.unabbreviations[value.toUpperCase()] || this.options.unabbreviations[value.toUpperCase().replace(/s\S+$/, '')];
|
|
667
|
+
if (!full) {
|
|
668
|
+
const m = value.toUpperCase().match(/(.*)(\s+\S*\d\S*)$/);
|
|
669
|
+
if (m) {
|
|
670
|
+
full = this.options.unabbreviations[m[1]];
|
|
671
|
+
if (full)
|
|
672
|
+
full += m[2];
|
|
1178
673
|
}
|
|
1179
674
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
675
|
+
if (full)
|
|
676
|
+
value = full;
|
|
677
|
+
if (!sentenceCase)
|
|
678
|
+
return value;
|
|
679
|
+
}
|
|
680
|
+
if (field === 'crossref')
|
|
681
|
+
return value;
|
|
682
|
+
if (FieldAction.parseInt.includes(field) && value.trim().match(/^-?\d+$/))
|
|
683
|
+
return parseInt(value);
|
|
684
|
+
if (mode === 'title' && sentenceCase) {
|
|
685
|
+
if (!this.options.sentenceCase.guess || !(0, sentence_case_2.guessSentenceCased)(value, /\x0E\/?([a-z]+)\x0F/ig)) {
|
|
686
|
+
value = (0, sentence_case_2.toSentenceCase)(value, {
|
|
687
|
+
preserveQuoted: this.options.sentenceCase.preserveQuoted,
|
|
688
|
+
subSentenceCapitalization: this.options.sentenceCase.subSentence,
|
|
689
|
+
markup: /\x0E\/?([a-z]+)\x0F/ig,
|
|
690
|
+
nocase: /\x0E(ncx?)\x0F.*?\x0E\/\1\x0F/ig,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
let cancel = (_match, stripped) => stripped;
|
|
694
|
+
switch (this.options.caseProtection) {
|
|
695
|
+
case 'strict':
|
|
696
|
+
cancel = (match, _stripped) => match;
|
|
697
|
+
break;
|
|
698
|
+
case 'as-needed':
|
|
699
|
+
cancel = (match, stripped) => {
|
|
700
|
+
const words = (0, sentence_case_2.tokenize)(stripped, /\x0E\/?([a-z]+)\x0F/ig);
|
|
701
|
+
return words.find(w => w.shape.match(/^(?!.*X).*x.*$/)) ? match : this.wrap(stripped, 'ncx');
|
|
1197
702
|
};
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
const [firstName, lastName] = this.splitOnce(parts[0], marker.space, true);
|
|
1202
|
-
if (lastName) {
|
|
1203
|
-
parsed = { firstName, lastName };
|
|
1204
|
-
}
|
|
1205
|
-
else {
|
|
1206
|
-
parsed = { lastName: firstName };
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
break;
|
|
1210
|
-
case 2: // lastname, firstname
|
|
1211
|
-
parsed = {
|
|
1212
|
-
lastName: parts[0],
|
|
1213
|
-
firstName: parts[1],
|
|
1214
|
-
};
|
|
1215
|
-
break;
|
|
1216
|
-
default: // lastname, suffix, firstname
|
|
1217
|
-
parsed = {
|
|
1218
|
-
lastName: parts[0],
|
|
1219
|
-
suffix: parts[1],
|
|
1220
|
-
firstName: parts.slice(2).join(marker.comma),
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
for (const [k, v] of Object.entries(parsed)) {
|
|
1224
|
-
if (typeof v !== 'string')
|
|
1225
|
-
continue;
|
|
1226
|
-
parsed[k] = marker.clean(v).trim();
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
return value.replace(/\x0Enc\x0F(.*?)\x0E\/nc\x0F/ig, cancel);
|
|
1227
706
|
}
|
|
1228
|
-
return
|
|
707
|
+
return value;
|
|
1229
708
|
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
709
|
+
field(entry, field, value, sentenceCase) {
|
|
710
|
+
const mode = this.mode(field);
|
|
711
|
+
const ast = unified_latex_util_pegjs_1.LatexPegParser.parse(value);
|
|
712
|
+
if (this.options.removeOuterBraces.includes(field) && ast.content.length === 1 && ast.content[0].type === 'group') {
|
|
713
|
+
ast.content = ast.content[0].content;
|
|
714
|
+
}
|
|
715
|
+
if (mode === 'verbatim') { // &^%@#&^%@# idiots wrapping verbatim fields
|
|
716
|
+
entry.fields[field] = (0, unified_latex_util_print_raw_1.printRaw)(ast);
|
|
717
|
+
return;
|
|
1233
718
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
donated: [],
|
|
1245
|
-
},
|
|
1246
|
-
};
|
|
1247
|
-
this.entries.push(this.entry);
|
|
1248
|
-
// order these first for language-dependent sentence casing
|
|
1249
|
-
const order = ['langid', 'hyphenation', 'language'];
|
|
1250
|
-
node.fields.sort((a, b) => {
|
|
1251
|
-
const ia = order.indexOf(a.name);
|
|
1252
|
-
const ib = order.indexOf(b.name);
|
|
1253
|
-
if (ia === -1 && ib === -1)
|
|
1254
|
-
return a.name.localeCompare(b.name); // doesn't matter really
|
|
1255
|
-
if (ia === -1)
|
|
1256
|
-
return 1;
|
|
1257
|
-
if (ib === -1)
|
|
1258
|
-
return -1;
|
|
1259
|
-
return ia - ib;
|
|
1260
|
-
});
|
|
1261
|
-
let sentenceCase = !!this.options.sentenceCase.length; // if sentenceCase is empty, no sentence casing
|
|
1262
|
-
for (const field of node.fields) {
|
|
1263
|
-
if (field.kind !== 'Field')
|
|
1264
|
-
return this.error(new ParserError(`Expected Field, got ${field.kind}`, node));
|
|
1265
|
-
this.startCleaning(field.name);
|
|
1266
|
-
/*
|
|
1267
|
-
if (this.options.raw && this.fieldType !== 'creator') {
|
|
1268
|
-
this.entry.fields[field.name] = [ field.value.map(v => v.source).join('') ]
|
|
1269
|
-
continue
|
|
1270
|
-
}
|
|
1271
|
-
*/
|
|
1272
|
-
this.field = {
|
|
1273
|
-
name: field.name,
|
|
1274
|
-
text: '',
|
|
1275
|
-
level: 0,
|
|
1276
|
-
words: {
|
|
1277
|
-
upper: 0,
|
|
1278
|
-
lower: 0,
|
|
1279
|
-
other: 0,
|
|
1280
|
-
},
|
|
1281
|
-
preserveRanges: (sentenceCase && exports.fields.title.includes(field.name)) ? [] : null,
|
|
1282
|
-
html: this.options.htmlFields.includes(field.name),
|
|
1283
|
-
};
|
|
1284
|
-
this.entry.fields[this.field.name] = this.entry.fields[this.field.name] || [];
|
|
1285
|
-
// special case for 'title = 2020'
|
|
1286
|
-
if (field.value.kind === 'Number') {
|
|
1287
|
-
this.entry.fields[this.field.name].push(field.value.value);
|
|
1288
|
-
this.field = null;
|
|
1289
|
-
continue;
|
|
719
|
+
if (mode === 'title') {
|
|
720
|
+
let root = [...ast.content];
|
|
721
|
+
while (root.length) {
|
|
722
|
+
const node = root.shift();
|
|
723
|
+
// only root groups offer case protecten -- but it may be as an macro arg, so mark here before gobbling
|
|
724
|
+
if (this.protect(node))
|
|
725
|
+
node._renderInfo = { root: true };
|
|
726
|
+
// environments are considered root when at root
|
|
727
|
+
if (node.type === 'environment')
|
|
728
|
+
root = [...root, ...node.content];
|
|
1290
729
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
730
|
+
}
|
|
731
|
+
// pass 0 -- register parse mode
|
|
732
|
+
(0, unified_latex_util_visit_1.visit)(ast, (node, info) => {
|
|
733
|
+
if (!node._renderInfo)
|
|
734
|
+
node._renderInfo = {};
|
|
735
|
+
node._renderInfo.mode = info.context.inMathMode ? 'math' : 'text';
|
|
736
|
+
// if (info.context.inMathMode || info.context.hasMathModeAncestor) return
|
|
737
|
+
if (mode === 'title' && node.type === 'inlinemath' && !info.parents.find(p => p._renderInfo.protectCase))
|
|
738
|
+
node._renderInfo.protectCase = true;
|
|
739
|
+
if (!info.context.inMathMode) {
|
|
740
|
+
if (mode === 'title' && node._renderInfo.root)
|
|
741
|
+
node._renderInfo.protectCase = true;
|
|
742
|
+
if (node.type === 'macro' && typeof node.escapeToken !== 'string')
|
|
743
|
+
node.escapeToken = '\\';
|
|
744
|
+
if (node.type === 'environment' && node.env === 'em')
|
|
745
|
+
node._renderInfo.emph = true;
|
|
1307
746
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
747
|
+
});
|
|
748
|
+
// pass 1 -- mark & normalize
|
|
749
|
+
(0, unified_latex_util_visit_1.visit)(ast, (nodes, info) => {
|
|
750
|
+
var _a;
|
|
751
|
+
let node;
|
|
752
|
+
const compacted = [];
|
|
753
|
+
let inif = 0;
|
|
754
|
+
while (nodes.length) {
|
|
755
|
+
if (node = this.ligature(nodes)) {
|
|
756
|
+
compacted.push(node);
|
|
757
|
+
continue;
|
|
1314
758
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
// {M. Halle, J. Bresnan, and G. Miller}
|
|
1320
|
-
if (this.field.text.includes(`${marker.comma}${marker.and}`)) { //
|
|
1321
|
-
this.field.text = this.field.text.replace(new RegExp(`${marker.comma}${marker.and}`, 'g'), marker.and).replace(new RegExp(marker.comma), marker.and);
|
|
759
|
+
node = nodes.shift();
|
|
760
|
+
if (node.type === 'macro' && node.content === 'ifdefined') {
|
|
761
|
+
inif += 1;
|
|
762
|
+
continue;
|
|
1322
763
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
this.entry.creators[this.field.name].push(this.parseName(creator));
|
|
764
|
+
else if (node.type === 'macro' && node.content === 'else') {
|
|
765
|
+
continue;
|
|
1326
766
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
767
|
+
else if (node.type === 'macro' && node.content === 'fi') {
|
|
768
|
+
inif = Math.max(inif - 1, 0);
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
else if (inif) {
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
const nargs = node.type === 'macro'
|
|
775
|
+
? narguments[node.content] || narguments[`${info.context.inMathMode ? 'math' : 'text'}\t${node.content}`]
|
|
776
|
+
: 0;
|
|
777
|
+
if (node.type === 'macro' && nargs) {
|
|
778
|
+
node.args = Array(nargs).fill(undefined).map(_i => this.argument(nodes, node)).filter(arg => arg);
|
|
779
|
+
if (node.content.match(/^(url|href)$/) && node.args.length) {
|
|
780
|
+
let url = node.args[0].content;
|
|
781
|
+
if (url.length === 1 && url[0].type === 'group')
|
|
782
|
+
url = url[0].content;
|
|
783
|
+
node.args[0] = this.wraparg({ type: 'string', content: (0, unified_latex_util_print_raw_1.printRaw)(url), _renderInfo: { mode: url[0]._renderInfo.mode } }, node);
|
|
1337
784
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
this.preserve(match.index, match.index + match[0].length);
|
|
1353
|
-
}
|
|
1354
|
-
preserveCase.quoted.lastIndex = 0;
|
|
1355
|
-
while ((match = preserveCase.quoted.exec(this.field.text))) {
|
|
1356
|
-
// eslint doesn't grok these are numbers
|
|
1357
|
-
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
1358
|
-
this.preserve(match.index, match.index + match[0].length);
|
|
785
|
+
}
|
|
786
|
+
else if (node.type === 'macro' && node.content.match(/^[a-z]+$/i) && ((_a = nodes[0]) === null || _a === void 0 ? void 0 : _a.type) === 'whitespace') {
|
|
787
|
+
nodes.shift();
|
|
788
|
+
}
|
|
789
|
+
compacted.push(node);
|
|
790
|
+
}
|
|
791
|
+
if (!info.context.inMathMode) {
|
|
792
|
+
// feed-forward inline macros
|
|
793
|
+
for (const [macro, markup] of Object.entries({ em: 'emph', it: 'emph', sl: 'emph', bf: 'bold', sc: 'smallCaps', tt: 'code' })) {
|
|
794
|
+
if (info.parents.find(p => p._renderInfo[markup]))
|
|
795
|
+
continue;
|
|
796
|
+
compacted.forEach((markup_node, i) => {
|
|
797
|
+
if (markup_node.type === 'macro' && markup_node.content === macro) {
|
|
798
|
+
compacted.slice(i + 1).forEach(n => n._renderInfo[markup] = true);
|
|
1359
799
|
}
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
nodes.push(...compacted);
|
|
804
|
+
}, { test: Array.isArray, includeArrays: true });
|
|
805
|
+
(0, unified_latex_util_replace_1.replaceNode)(ast, (node, _info) => {
|
|
806
|
+
if (node.type !== 'macro')
|
|
807
|
+
return;
|
|
808
|
+
if (node.escapeToken && unicode2latex_1.combining.tounicode[node.content]) {
|
|
809
|
+
let arg;
|
|
810
|
+
// no args, args of zero length, or first arg has no content
|
|
811
|
+
if (!node.args || node.args.length === 0 || node.args[0].content.length === 0) {
|
|
812
|
+
arg = { type: 'string', content: ' ', _renderInfo: {} };
|
|
813
|
+
}
|
|
814
|
+
else if (node.args.length !== 1 || node.args[0].content.length !== 1) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
arg = node.args[0].content[0];
|
|
819
|
+
}
|
|
820
|
+
if (arg.type === 'group') {
|
|
821
|
+
switch (arg.content.length) {
|
|
822
|
+
case 0:
|
|
823
|
+
arg = { type: 'string', content: ' ', _renderInfo: {} };
|
|
824
|
+
break;
|
|
825
|
+
case 1:
|
|
826
|
+
arg = arg.content[0];
|
|
827
|
+
break;
|
|
828
|
+
default:
|
|
829
|
+
return;
|
|
1360
830
|
}
|
|
1361
831
|
}
|
|
1362
|
-
|
|
832
|
+
switch (arg.type) {
|
|
833
|
+
case 'verbatim':
|
|
834
|
+
case 'string':
|
|
835
|
+
return { type: 'string', content: `${arg.content}${unicode2latex_1.combining.tounicode[node.content]}`, _renderInfo: {} };
|
|
836
|
+
default:
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
1363
839
|
}
|
|
840
|
+
let latex = `${node.escapeToken}${node.content}`;
|
|
841
|
+
latex += (node.args || []).map(arg => (0, unified_latex_util_print_raw_1.printRaw)(this.argtogroup(arg))).join('');
|
|
842
|
+
if (latex in unicode2latex_1.latex2unicode)
|
|
843
|
+
return { type: 'string', content: latex2unicode(latex, node), _renderInfo: {} };
|
|
844
|
+
// return null to delete
|
|
845
|
+
});
|
|
846
|
+
switch (mode) {
|
|
847
|
+
case 'creator':
|
|
848
|
+
entry.fields[field] = this.split(ast, /^and$/i, /(^& | & | &$)/).map(cr => this.parseCreator(cr)).filter(cr => Object.keys(cr).length);
|
|
849
|
+
break;
|
|
850
|
+
case 'commalist':
|
|
851
|
+
entry.fields[field] = this.split(ast, /^[;,]$/, /(&)/).map(elt => this.stringify(elt, { mode: 'literal' }).trim());
|
|
852
|
+
break;
|
|
853
|
+
case 'literallist':
|
|
854
|
+
entry.fields[field] = this.split(ast, /^and$/i, /(^& | & | &$)/).map(elt => this.stringify(elt, { mode: 'literal' }).trim());
|
|
855
|
+
break;
|
|
856
|
+
default:
|
|
857
|
+
entry.fields[field] = this.stringField(field, this.stringify(ast, { mode }), sentenceCase, mode);
|
|
858
|
+
break;
|
|
1364
859
|
}
|
|
1365
|
-
|
|
860
|
+
// recursively restores markup in string content. 'as string' is just here to pacify typescript
|
|
861
|
+
entry.fields[field] = JSON.parse(JSON.stringify(entry.fields[field], (k, v) => (typeof v === 'string' ? this.restoreMarkup(v) : v)));
|
|
1366
862
|
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
if (
|
|
1372
|
-
this.
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
this.
|
|
863
|
+
reset(options = {}) {
|
|
864
|
+
var _a;
|
|
865
|
+
const sentenceCase = Object.assign({ langids: English, guess: true, preserveQuoted: true }, (options.sentenceCase || {}));
|
|
866
|
+
this.options = Object.assign(Object.assign({ caseProtection: 'as-needed', unabbreviations: true, applyCrossRef: (_a = options.applyCrossRef) !== null && _a !== void 0 ? _a : true, fieldMode: {} }, options), { sentenceCase });
|
|
867
|
+
if (this.options.caseProtection === true)
|
|
868
|
+
this.options.caseProtection = 'as-needed';
|
|
869
|
+
if (typeof this.options.sentenceCase.langids === 'boolean')
|
|
870
|
+
this.options.sentenceCase.langids = this.options.sentenceCase.langids ? English : [];
|
|
871
|
+
this.options.sentenceCase.langids = this.options.sentenceCase.langids.map(langid => langid.toLowerCase());
|
|
872
|
+
if (typeof this.options.unabbreviations === 'boolean')
|
|
873
|
+
this.options.unabbreviations = this.options.unabbreviations ? unabbreviations : {};
|
|
874
|
+
const unabbr = {};
|
|
875
|
+
for (const abbr in this.options.unabbreviations) { // eslint-disable-line guard-for-in
|
|
876
|
+
unabbr[abbr.toUpperCase()] = this.options.unabbreviations[abbr];
|
|
877
|
+
}
|
|
878
|
+
this.options.unabbreviations = unabbr;
|
|
879
|
+
this.fieldMode = Object.entries(exports.FieldMode).reduce((acc, [mode, test]) => {
|
|
880
|
+
const strings = test.filter(fieldname_or_regex => typeof fieldname_or_regex === 'string' && !this.options.fieldMode[fieldname_or_regex]);
|
|
881
|
+
const regexes = test.filter(fieldname_or_regex => typeof fieldname_or_regex !== 'string');
|
|
882
|
+
acc[mode] = [...strings, ...regexes];
|
|
883
|
+
return acc;
|
|
884
|
+
}, {});
|
|
885
|
+
for (const [field, mode] of Object.entries(this.options.fieldMode)) {
|
|
886
|
+
this.fieldMode[mode].unshift(field);
|
|
887
|
+
}
|
|
888
|
+
if (!this.options.removeOuterBraces) {
|
|
889
|
+
this.options.removeOuterBraces = [
|
|
890
|
+
...FieldAction.removeOuterBraces,
|
|
891
|
+
...this.fieldMode.title,
|
|
892
|
+
...this.fieldMode.verbatim,
|
|
893
|
+
].filter(field => typeof field === 'string');
|
|
894
|
+
}
|
|
895
|
+
this.fallback = options.unsupported === 'ignore' ? ((_node, _tex) => '') : options.unsupported;
|
|
896
|
+
this.bib = {
|
|
897
|
+
errors: [],
|
|
898
|
+
entries: [],
|
|
899
|
+
comments: [],
|
|
900
|
+
strings: {},
|
|
901
|
+
preamble: [],
|
|
902
|
+
jabref: null,
|
|
903
|
+
};
|
|
1377
904
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1399
|
-
if (this.field.level === 0 && this.field.name.match(/^(keywords?|groups)$/)) {
|
|
1400
|
-
this.field.text += node.value.replace(/\s*[;,]\s*/g, marker.comma);
|
|
1401
|
-
return;
|
|
1402
|
-
}
|
|
1403
|
-
if (this.field.html) {
|
|
1404
|
-
this.field.text += node.value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1405
|
-
}
|
|
1406
|
-
else if (this.field.preserveRanges) {
|
|
1407
|
-
const words = node.value.split(/(\s+)/);
|
|
1408
|
-
for (const word of words) {
|
|
1409
|
-
const start = this.field.text.length;
|
|
1410
|
-
this.field.text += word;
|
|
1411
|
-
if (this.preserveCase(word))
|
|
1412
|
-
this.preserve(start, this.field.text.length); // , `word: ${JSON.stringify(word)}`)
|
|
905
|
+
reparse(entry) {
|
|
906
|
+
let langid = (entry.fields.langid || entry.fields.hyphenation || '').toLowerCase();
|
|
907
|
+
if (!langid && this.options.sentenceCase.language && entry.fields.language)
|
|
908
|
+
langid = entry.fields.language.toLowerCase();
|
|
909
|
+
const sentenceCase = this.options.sentenceCase.langids.includes(langid);
|
|
910
|
+
this.current = entry;
|
|
911
|
+
let keywords = []; // OMG #783
|
|
912
|
+
try {
|
|
913
|
+
for (const [field, value] of Object.entries(entry.fields)) {
|
|
914
|
+
if (!value.trim()) {
|
|
915
|
+
delete entry.fields[field];
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
this.field(entry, field, value, sentenceCase);
|
|
919
|
+
if (field.match(/^keywords\[\d+\]$/)) {
|
|
920
|
+
keywords = [...keywords, entry.fields[field]];
|
|
921
|
+
delete entry.fields[field];
|
|
922
|
+
}
|
|
923
|
+
if (typeof entry.fields[field] === 'string')
|
|
924
|
+
entry.fields[field] = entry.fields[field].trim();
|
|
1413
925
|
}
|
|
926
|
+
if (keywords.length)
|
|
927
|
+
entry.fields.keywords = [...(new Set([...(entry.fields.keywords || []), ...keywords]))].sort();
|
|
928
|
+
this.bib.entries.push(entry);
|
|
1414
929
|
}
|
|
1415
|
-
|
|
1416
|
-
this.
|
|
930
|
+
catch (err) {
|
|
931
|
+
this.bib.errors.push({ error: `${err.message}\n${entry.input}`, input: entry.input });
|
|
1417
932
|
}
|
|
1418
933
|
}
|
|
1419
|
-
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
quotation: ['<blockquote>', '</blockquote>'],
|
|
1424
|
-
}[node.env] || ['', ''];
|
|
1425
|
-
if (!open)
|
|
1426
|
-
this.error(new TeXError(`Unhandled \\${node.env}{...}`, node, this.chunk));
|
|
1427
|
-
this.field.text += open;
|
|
1428
|
-
this.convert_block(Object.assign(Object.assign({}, node), { kind: 'Block', markup: {} }));
|
|
1429
|
-
this.field.text += close;
|
|
934
|
+
content(tex) {
|
|
935
|
+
const entry = { key: '', type: '', fields: {} };
|
|
936
|
+
this.field(entry, 'tex', tex, false);
|
|
937
|
+
return entry.fields.tex;
|
|
1430
938
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
convert_block(node) {
|
|
1439
|
-
const start = this.field.text.length;
|
|
1440
|
-
let prefix = '';
|
|
1441
|
-
let postfix = '';
|
|
1442
|
-
if (this.options.caseProtection !== 'strict' && this.cleaning.type === 'other')
|
|
1443
|
-
delete node.case;
|
|
1444
|
-
if (this.cleaning.type === 'creator' && node.case === 'protect') {
|
|
1445
|
-
prefix += marker.literal;
|
|
1446
|
-
postfix = marker.literal + postfix;
|
|
1447
|
-
delete node.case;
|
|
939
|
+
prep(base) {
|
|
940
|
+
for (const preamble of base.preambles) {
|
|
941
|
+
try {
|
|
942
|
+
this.content(preamble);
|
|
943
|
+
}
|
|
944
|
+
catch (err) {
|
|
945
|
+
}
|
|
1448
946
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
postfix = this.options.markup.caseProtect.close + postfix;
|
|
947
|
+
for (const [k, v] of Object.entries(base.strings)) {
|
|
948
|
+
this.bib.strings[k] = this.content(v);
|
|
1452
949
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
950
|
+
}
|
|
951
|
+
finalize(base) {
|
|
952
|
+
var _a;
|
|
953
|
+
if (this.options.applyCrossRef) {
|
|
954
|
+
const entries = {};
|
|
955
|
+
for (const entry of this.bib.entries) {
|
|
956
|
+
if (entry.key)
|
|
957
|
+
entries[entry.key.toUpperCase()] = entry;
|
|
958
|
+
}
|
|
959
|
+
const order = [];
|
|
960
|
+
for (const entry of this.bib.entries) {
|
|
961
|
+
if (!entry.key || typeof entry.fields.crossref !== 'string')
|
|
962
|
+
continue;
|
|
963
|
+
const crossref = entry.fields.crossref.toUpperCase();
|
|
964
|
+
if (!entries[crossref])
|
|
965
|
+
continue;
|
|
966
|
+
const key = entry.key.toUpperCase();
|
|
967
|
+
if (!order.includes(crossref))
|
|
968
|
+
order.unshift(crossref);
|
|
969
|
+
if (!order.includes(key))
|
|
970
|
+
order.push(key);
|
|
971
|
+
}
|
|
972
|
+
for (const key of order) {
|
|
973
|
+
const child = entries[key.toUpperCase()];
|
|
974
|
+
const parent = entries[(_a = child.fields.crossref) === null || _a === void 0 ? void 0 : _a.toUpperCase()];
|
|
975
|
+
if (!parent)
|
|
976
|
+
continue;
|
|
977
|
+
for (const mappings of [crossref_json_1.default[child.type], crossref_json_1.default['*']].filter(m => m)) {
|
|
978
|
+
for (const mapping of [mappings[parent.type], mappings['*']].filter(m => m)) {
|
|
979
|
+
for (const [childfield, parentfield] of Object.entries(mapping)) {
|
|
980
|
+
if (!child.fields[childfield] && parent.fields[parentfield])
|
|
981
|
+
child.fields[childfield] = parent.fields[parentfield];
|
|
982
|
+
}
|
|
983
|
+
for (const field of (fields_json_1.default[child.type] || [])) {
|
|
984
|
+
if (!child.fields[field] && parent.fields[field])
|
|
985
|
+
child.fields[field] = parent.fields[field];
|
|
986
|
+
}
|
|
987
|
+
}
|
|
1458
988
|
}
|
|
1459
|
-
prefix += this.options.markup[markup].open;
|
|
1460
|
-
postfix = `${this.options.markup[markup].close}${postfix}`;
|
|
1461
989
|
}
|
|
1462
990
|
}
|
|
1463
|
-
const
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
this.
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
this.
|
|
1471
|
-
const
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
991
|
+
const { comments, jabref } = JabRef.parse(base.comments);
|
|
992
|
+
this.bib.comments = comments;
|
|
993
|
+
this.bib.jabref = jabref;
|
|
994
|
+
this.bib.preamble = base.preambles;
|
|
995
|
+
this.bib.errors = [...base.errors, ...this.bib.errors];
|
|
996
|
+
}
|
|
997
|
+
parse(input, options = {}) {
|
|
998
|
+
this.reset(options);
|
|
999
|
+
const base = bibtex.parse(input);
|
|
1000
|
+
this.prep(base);
|
|
1001
|
+
for (const entry of base.entries) {
|
|
1002
|
+
this.reparse(entry);
|
|
1003
|
+
}
|
|
1004
|
+
this.finalize(base);
|
|
1005
|
+
return this.bib;
|
|
1006
|
+
}
|
|
1007
|
+
async parseAsync(input, options = {}) {
|
|
1008
|
+
var _a, e_1, _b, _c;
|
|
1009
|
+
this.reset(options);
|
|
1010
|
+
const base = await bibtex.promises.parse(input);
|
|
1011
|
+
this.prep(base);
|
|
1012
|
+
try {
|
|
1013
|
+
for (var _d = true, _e = __asyncValues(asyncGenerator(base.entries)), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
|
|
1014
|
+
_c = _f.value;
|
|
1015
|
+
_d = false;
|
|
1016
|
+
const entry = _c;
|
|
1017
|
+
this.reparse(entry);
|
|
1018
|
+
}
|
|
1486
1019
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
const unicode = unicode2latex_1.latex2unicode[`${cmd}${char}`] || unicode2latex_1.latex2unicode[`${cmd}{${char}}`];
|
|
1492
|
-
script += unicode ? unicode : `<${mode}>${char}</${mode}>`;
|
|
1020
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
1021
|
+
finally {
|
|
1022
|
+
try {
|
|
1023
|
+
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
|
|
1493
1024
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
this.preserve(start, this.field.text.length); // , 'in convert-block ' + node.source || '<source>')
|
|
1025
|
+
finally { if (e_1) throw e_1.error; }
|
|
1026
|
+
}
|
|
1027
|
+
this.finalize(base);
|
|
1028
|
+
return this.bib;
|
|
1499
1029
|
}
|
|
1500
1030
|
}
|
|
1501
|
-
/**
|
|
1502
|
-
* parse bibtex. This will try to convert TeX commands into unicode equivalents, and apply `@string` expansion
|
|
1503
|
-
*/
|
|
1504
1031
|
function parse(input, options = {}) {
|
|
1505
|
-
const parser = new
|
|
1506
|
-
return parser.parse(input);
|
|
1032
|
+
const parser = new BibTeXParser;
|
|
1033
|
+
return parser.parse(input, options);
|
|
1507
1034
|
}
|
|
1508
1035
|
exports.parse = parse;
|
|
1509
|
-
function
|
|
1510
|
-
const parser = new
|
|
1511
|
-
return parser.
|
|
1036
|
+
async function parseAsync(input, options = {}) {
|
|
1037
|
+
const parser = new BibTeXParser;
|
|
1038
|
+
return await parser.parseAsync(input, options);
|
|
1512
1039
|
}
|
|
1513
|
-
exports.
|
|
1514
|
-
exports.promises = {
|
|
1515
|
-
async parse(input, options = {}) {
|
|
1516
|
-
const parser = new Parser(options);
|
|
1517
|
-
return await parser.parseAsync(input);
|
|
1518
|
-
},
|
|
1519
|
-
};
|
|
1040
|
+
exports.parseAsync = parseAsync;
|
|
1520
1041
|
//# sourceMappingURL=index.js.map
|