@retorquere/bibtex-parser 7.0.10 → 7.0.12
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/chunker.d.ts +11 -1
- package/chunker.js +67 -36
- package/grammar.js +293 -330
- package/index.js +1 -0
- package/package.json +1 -1
- package/unabbrev.json +27 -27
package/chunker.d.ts
CHANGED
|
@@ -37,14 +37,24 @@ export interface ParserOptions {
|
|
|
37
37
|
*/
|
|
38
38
|
max_entries?: number;
|
|
39
39
|
}
|
|
40
|
+
type Entry = {
|
|
41
|
+
type: string;
|
|
42
|
+
key?: string;
|
|
43
|
+
fields: Record<string, string>;
|
|
44
|
+
};
|
|
40
45
|
/**
|
|
41
|
-
* Reads the bibtex input and splits it into separate chunks of
|
|
46
|
+
* Reads the bibtex input and splits it into separate chunks of `string`s, `@comment`s, and bibtex entries. Useful for detecting if a file is bibtex file and for filtering out basic errors that would
|
|
42
47
|
* make the more sophisticated [[bibtex.parse]] reject the whole file
|
|
43
48
|
*
|
|
44
49
|
* @returns array of chunks, with markers for type and errors (if any) found.
|
|
45
50
|
*/
|
|
46
51
|
export declare function parse(input: string, options?: ParserOptions): Chunk[];
|
|
52
|
+
export declare function entries(input: string, options?: ParserOptions): {
|
|
53
|
+
entries: Entry[];
|
|
54
|
+
errors: Chunk[];
|
|
55
|
+
};
|
|
47
56
|
export declare const promises: {
|
|
48
57
|
parse(input: string, options?: ParserOptions): Promise<Chunk[]>;
|
|
49
58
|
};
|
|
59
|
+
export {};
|
|
50
60
|
//# sourceMappingURL=chunker.d.ts.map
|
package/chunker.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// CommonJS port by Mikola Lysenko 2013
|
|
6
6
|
//
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.promises = exports.parse = void 0;
|
|
8
|
+
exports.promises = exports.entries = exports.parse = void 0;
|
|
9
9
|
class ParseError extends Error {
|
|
10
10
|
constructor(message, parser) {
|
|
11
11
|
message += ` @ ${parser.pos}`;
|
|
@@ -29,21 +29,24 @@ const letter = new RegExp('[' + [
|
|
|
29
29
|
/\u00AA\u00BA\u01BB\u01C0-\u01C3\u0294\u05D0-\u05EA\u05F0-\u05F2\u0620-\u063F\u0641-\u064A\u066E-\u066F\u0671-\u06D3\u06D5\u06EE-\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u0800-\u0815\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0972-\u0980\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0-\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B35-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0-\u0CE1\u0CF1-\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065-\u1066\u106E-\u1070\u1075-\u1081\u108E\u10D0-\u10FA\u10FD-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17DC\u1820-\u1842\u1844-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE-\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C77\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5-\u1CF6\u2135-\u2138\u2D30-\u2D67\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3006\u303C\u3041-\u3096\u309F\u30A1-\u30FA\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA014\uA016-\uA48C\uA4D0-\uA4F7\uA500-\uA60B\uA610-\uA61F\uA62A-\uA62B\uA66E\uA6A0-\uA6E5\uA78F\uA7F7\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9E0-\uA9E4\uA9E7-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA6F\uAA71-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5-\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADC\uAAE0-\uAAEA\uAAF2\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40-\uFB41\uFB43-\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF66-\uFF6F\uFF71-\uFF9D\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC/.source,
|
|
30
30
|
].join('') + ']');
|
|
31
31
|
class BibtexParser {
|
|
32
|
-
|
|
32
|
+
reset(input) {
|
|
33
|
+
this.input = input;
|
|
33
34
|
this.pos = 0;
|
|
34
|
-
this.entries =
|
|
35
|
+
this.entries = [];
|
|
36
|
+
this.strings = {};
|
|
35
37
|
this.parsing = null;
|
|
36
38
|
this.chunks = [];
|
|
39
|
+
// this.linebreaks = undefined
|
|
37
40
|
}
|
|
38
41
|
parse(input, options = {}) {
|
|
42
|
+
this.reset(input);
|
|
39
43
|
this.max_entries = options.max_entries || 0;
|
|
40
|
-
this.input = input;
|
|
41
44
|
this.bibtex();
|
|
42
45
|
return this.chunks;
|
|
43
46
|
}
|
|
44
47
|
async parseAsync(input, options = {}) {
|
|
48
|
+
this.reset(input);
|
|
45
49
|
this.max_entries = options.max_entries || 0;
|
|
46
|
-
this.input = input;
|
|
47
50
|
await this.bibtexAsync();
|
|
48
51
|
return this.chunks;
|
|
49
52
|
}
|
|
@@ -141,7 +144,8 @@ class BibtexParser {
|
|
|
141
144
|
return this.value_quotes();
|
|
142
145
|
}
|
|
143
146
|
else {
|
|
144
|
-
|
|
147
|
+
const bare = this.key();
|
|
148
|
+
return this.strings[bare] || bare;
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
value() {
|
|
@@ -177,9 +181,16 @@ class BibtexParser {
|
|
|
177
181
|
}
|
|
178
182
|
this.match('=');
|
|
179
183
|
const val = this.value();
|
|
180
|
-
|
|
184
|
+
if (this.parsing === 'string') {
|
|
185
|
+
this.strings[key.toLowerCase()] = val;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this.entries[0].fields[key] = val;
|
|
189
|
+
}
|
|
181
190
|
}
|
|
182
|
-
|
|
191
|
+
entry(_d) {
|
|
192
|
+
this.entries[0].key = this.key(true);
|
|
193
|
+
this.match(',');
|
|
183
194
|
this.key_equals_value();
|
|
184
195
|
while (this.tryMatch(',')) {
|
|
185
196
|
this.match(',');
|
|
@@ -190,14 +201,9 @@ class BibtexParser {
|
|
|
190
201
|
this.key_equals_value();
|
|
191
202
|
}
|
|
192
203
|
}
|
|
193
|
-
entry(_d) {
|
|
194
|
-
this.parsing = this.key(true);
|
|
195
|
-
this.match(',');
|
|
196
|
-
this.key_value_list();
|
|
197
|
-
}
|
|
198
204
|
directive() {
|
|
199
205
|
this.match('@');
|
|
200
|
-
return
|
|
206
|
+
return this.key().toLowerCase();
|
|
201
207
|
}
|
|
202
208
|
string() {
|
|
203
209
|
this.key_equals_value();
|
|
@@ -225,7 +231,7 @@ class BibtexParser {
|
|
|
225
231
|
}
|
|
226
232
|
*/
|
|
227
233
|
hasMore() {
|
|
228
|
-
if (this.max_entries && this.entries >= this.max_entries)
|
|
234
|
+
if (this.max_entries && this.entries.length >= this.max_entries)
|
|
229
235
|
return false;
|
|
230
236
|
return (this.pos < this.input.length);
|
|
231
237
|
}
|
|
@@ -238,6 +244,15 @@ class BibtexParser {
|
|
|
238
244
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
239
245
|
return this.hasMore() ? (new Promise(resolve => resolve(this.parseNext()))).then(() => this.bibtexAsync()) : Promise.resolve(null);
|
|
240
246
|
}
|
|
247
|
+
matchGuard() {
|
|
248
|
+
for (const guard of ['{}', '()']) {
|
|
249
|
+
if (this.tryMatch(guard[0])) {
|
|
250
|
+
this.match(guard[0]);
|
|
251
|
+
return guard[1];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
throw new ParseError(`Token mismatch, expected '{' or '(', found ${JSON.stringify(this.input.substr(this.pos, 20))}...`, this); // eslint-disable-line no-magic-numbers
|
|
255
|
+
}
|
|
241
256
|
parseNext() {
|
|
242
257
|
// this.progress()
|
|
243
258
|
const chunk = {
|
|
@@ -253,39 +268,30 @@ class BibtexParser {
|
|
|
253
268
|
return;
|
|
254
269
|
let guard = '';
|
|
255
270
|
try {
|
|
256
|
-
const d = this.directive();
|
|
271
|
+
const d = this.parsing = this.directive();
|
|
257
272
|
switch (d) {
|
|
258
|
-
case '
|
|
259
|
-
this.
|
|
273
|
+
case 'string':
|
|
274
|
+
guard = this.matchGuard();
|
|
260
275
|
this.string();
|
|
261
|
-
this.match(
|
|
276
|
+
this.match(guard);
|
|
262
277
|
chunk.stringDeclaration = true;
|
|
263
278
|
break;
|
|
264
|
-
case '
|
|
265
|
-
this.
|
|
279
|
+
case 'preamble':
|
|
280
|
+
guard = this.matchGuard();
|
|
266
281
|
this.preamble();
|
|
267
|
-
this.match(
|
|
282
|
+
this.match(guard);
|
|
268
283
|
chunk.preamble = true;
|
|
269
284
|
break;
|
|
270
|
-
case '
|
|
285
|
+
case 'comment':
|
|
271
286
|
this.comment();
|
|
272
287
|
chunk.comment = true;
|
|
273
288
|
break;
|
|
274
289
|
default:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
else if (this.tryMatch('(')) {
|
|
279
|
-
guard = '()';
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
throw new ParseError(`Token mismatch, expected '{' or '(', found ${JSON.stringify(this.input.substr(this.pos, 20))}...`, this); // eslint-disable-line no-magic-numbers
|
|
283
|
-
}
|
|
284
|
-
this.match(guard[0]);
|
|
290
|
+
guard = this.matchGuard();
|
|
291
|
+
this.entries.unshift({ type: d, fields: {} });
|
|
285
292
|
this.entry(d);
|
|
286
|
-
this.match(guard
|
|
293
|
+
this.match(guard);
|
|
287
294
|
chunk.entry = true;
|
|
288
|
-
this.entries++;
|
|
289
295
|
break;
|
|
290
296
|
}
|
|
291
297
|
}
|
|
@@ -297,6 +303,22 @@ class BibtexParser {
|
|
|
297
303
|
this.pos = chunk.offset.pos + 1;
|
|
298
304
|
while (this.pos < this.input.length && this.input[this.pos] !== '@')
|
|
299
305
|
this.pos++;
|
|
306
|
+
/*
|
|
307
|
+
if (!this.linebreaks) {
|
|
308
|
+
this.linebreaks = []
|
|
309
|
+
for (let pos = 0; pos < this.input.length; pos++) {
|
|
310
|
+
if (this.input[pos] === '\n') this.linebreaks.push({ pos, line: this.linebreaks.length + 1 })
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const line = this.linebreaks.find(l => l.pos >= chunk.offset.pos)
|
|
314
|
+
if (line) {
|
|
315
|
+
chunk.offset.line = line.line
|
|
316
|
+
chunk.offset.pos = chunk.offset.pos - line.pos
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
chunk.offset.line = 1
|
|
320
|
+
}
|
|
321
|
+
*/
|
|
300
322
|
}
|
|
301
323
|
const text = this.input.substring(chunk.offset.pos, this.pos);
|
|
302
324
|
const last = this.chunks.length - 1;
|
|
@@ -310,7 +332,7 @@ class BibtexParser {
|
|
|
310
332
|
}
|
|
311
333
|
}
|
|
312
334
|
/**
|
|
313
|
-
* Reads the bibtex input and splits it into separate chunks of
|
|
335
|
+
* Reads the bibtex input and splits it into separate chunks of `string`s, `@comment`s, and bibtex entries. Useful for detecting if a file is bibtex file and for filtering out basic errors that would
|
|
314
336
|
* make the more sophisticated [[bibtex.parse]] reject the whole file
|
|
315
337
|
*
|
|
316
338
|
* @returns array of chunks, with markers for type and errors (if any) found.
|
|
@@ -319,6 +341,15 @@ function parse(input, options = {}) {
|
|
|
319
341
|
return (new BibtexParser).parse(input, options);
|
|
320
342
|
}
|
|
321
343
|
exports.parse = parse;
|
|
344
|
+
function entries(input, options = {}) {
|
|
345
|
+
const parser = new BibtexParser;
|
|
346
|
+
parser.parse(input, options);
|
|
347
|
+
return {
|
|
348
|
+
entries: parser.entries.reverse(),
|
|
349
|
+
errors: parser.chunks.filter(chunk => chunk.error),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
exports.entries = entries;
|
|
322
353
|
exports.promises = {
|
|
323
354
|
async parse(input, options = {}) {
|
|
324
355
|
return await (new BibtexParser).parseAsync(input, options);
|