@retorquere/bibtex-parser 12.1.10 → 12.1.11

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.
@@ -1 +1 @@
1
- {"version":3,"file":"jabref.d.ts","sourceRoot":"","sources":["../../jabref.ts"],"names":[],"mappings":"AAuBA;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IAEjB;;OAEG;IACH,MAAM,EAAE,KAAK,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,EAAE,KAAK,EAAE,CAAA;IAEb;;;;OAIG;IACH,MAAM,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;KAAE,CAAA;IAEhC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAqFxF"}
1
+ {"version":3,"file":"jabref.d.ts","sourceRoot":"","sources":["../../jabref.ts"],"names":[],"mappings":"AAuBA;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IAEjB;;OAEG;IACH,MAAM,EAAE,KAAK,EAAE,CAAA;CAChB;AAED,qBAAa,cAAc;;IAGzB;;OAEG;IACH,IAAI,EAAE,KAAK,EAAE,CAAK;IAElB;;OAEG;IACK,aAAa,CAAC,EAAE,MAAM,CAAA;IAE9B;;OAEG;IACK,aAAa,CAAC,EAAE,MAAM,CAAA;IAE9B;;OAEG;IACK,YAAY,CAAC,EAAE,MAAM,CAAA;gBAEjB,IAAI,GAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,eAAe,GAAG,eAAe,GAAG,cAAc,CAAC,CAAM;IAcjH,wGAAwG;IACxG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAM7C;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAgFxF"}
Binary file
@@ -1,5 +1,8 @@
1
1
  /** @module wasm */
2
2
  import init, { initSync } from './bibtex_parser.js';
3
+ import { JabRefMetadata } from './jabref.js';
4
+ export { JabRefMetadata };
5
+ export type { Group as JabRefGroup } from './jabref.js';
3
6
  export type { InitInput, InitOutput, SyncInitInput } from './bibtex_parser.js';
4
7
  /** Initializes the WebAssembly parser; await this before using its exports. */
5
8
  export { init, initSync };
@@ -60,20 +63,6 @@ export interface ParseError {
60
63
  error: string;
61
64
  input?: string;
62
65
  }
63
- /** A group in JabRef's nested group hierarchy. */
64
- export interface JabRefGroup {
65
- name: string;
66
- entries: string[];
67
- groups: JabRefGroup[];
68
- }
69
- /** JabRef metadata extracted from a BibTeX library. */
70
- export interface JabRefMetadata {
71
- root: JabRefGroup[];
72
- groups: Record<string, JabRefGroup>;
73
- fileDirectory?: string;
74
- groupsversion?: number;
75
- databaseType?: string;
76
- }
77
66
  /** The parsed contents of a BibTeX library. */
78
67
  export interface Library {
79
68
  errors: ParseError[];
@@ -1,5 +1,7 @@
1
1
  /** @module wasm */
2
2
  import init, { initSync, parse as parseWasm, parseAsync as parseAsyncWasm, parseVerbatim as parseVerbatimWasm, parseVerbatimAsync as parseVerbatimAsyncWasm, tokenize as tokenizeWasm, toSentenceCase as toSentenceCaseWasm } from './bibtex_parser.js';
3
+ import { JabRefMetadata } from './jabref.js';
4
+ export { JabRefMetadata };
3
5
  /** Initializes the WebAssembly parser; await this before using its exports. */
4
6
  export { init, initSync };
5
7
  export default init;
@@ -57,20 +59,24 @@ function throwOnUnsupported(result) {
57
59
  throw new Error(unsupported.error);
58
60
  return result;
59
61
  }
62
+ function withJabRef(result) {
63
+ result.jabref = new JabRefMetadata(result.jabref);
64
+ return result;
65
+ }
60
66
  /** Parses BibTeX while leaving field contents uninterpreted. */
61
67
  export function parseVerbatim(input, options = {}) {
62
68
  const prepared = prepare(input, options);
63
- return parseVerbatimWasm(prepared.input, prepared.options);
69
+ return withJabRef(parseVerbatimWasm(prepared.input, prepared.options));
64
70
  }
65
71
  /** Asynchronous variant of {@link parseVerbatim}. */
66
72
  export async function parseVerbatimAsync(input, options = {}) {
67
73
  const prepared = prepare(input, options);
68
- return await parseVerbatimAsyncWasm(prepared.input, prepared.options);
74
+ return withJabRef(await parseVerbatimAsyncWasm(prepared.input, prepared.options));
69
75
  }
70
76
  /** Parses BibTeX or BibLaTeX source into a normalized library. */
71
77
  export function parse(input, options = {}) {
72
78
  const prepared = prepare(input, options);
73
- const result = parseWasm(prepared.input, prepared.options);
79
+ const result = withJabRef(parseWasm(prepared.input, prepared.options));
74
80
  if (options.unsupported === 'throw')
75
81
  return throwOnUnsupported(result);
76
82
  return result;
@@ -78,7 +84,7 @@ export function parse(input, options = {}) {
78
84
  /** Asynchronous variant of {@link parse}, yielding during large parses. */
79
85
  export async function parseAsync(input, options = {}) {
80
86
  const prepared = prepare(input, options);
81
- const result = await parseAsyncWasm(prepared.input, prepared.options);
87
+ const result = withJabRef(await parseAsyncWasm(prepared.input, prepared.options));
82
88
  if (options.unsupported === 'throw')
83
89
  return throwOnUnsupported(result);
84
90
  return result;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * A JabRef group.
3
+ */
4
+ export interface Group {
5
+ /**
6
+ * the group name
7
+ */
8
+ name: string;
9
+ /**
10
+ * The citation keys which are specified to belong to this group, after intersection calculation has been applied
11
+ */
12
+ entries: string[];
13
+ /**
14
+ * Sub-groups under this group
15
+ */
16
+ groups: Group[];
17
+ }
18
+ export declare class JabRefMetadata {
19
+ #private;
20
+ /**
21
+ * The root groups. You can find the nested groups in their `groups` property
22
+ */
23
+ root: Group[];
24
+ /**
25
+ * The base path for file paths
26
+ */
27
+ fileDirectory?: string;
28
+ /**
29
+ * The JabRef metadata format version
30
+ */
31
+ groupsversion?: number;
32
+ /**
33
+ * The JabRef metadata database type
34
+ */
35
+ databaseType?: string;
36
+ constructor(data?: Partial<Pick<JabRefMetadata, 'root' | 'fileDirectory' | 'groupsversion' | 'databaseType'>>);
37
+ /** Populates JabRef 3.8+ memberships in `root` by group name; duplicate names select the first node. */
38
+ addEntry(name: string, key: string): boolean;
39
+ }
40
+ /**
41
+ * Import the JabRef groups from the `@string` comments in which they were stored. You would typically pass the comments parsed by [[bibtex.parse]] in here.
42
+ *
43
+ * JabRef knows several group types, and this parser parses most, but not all of them:
44
+ *
45
+ * * independent group: the keys listed in the group are the entries that are considered to belong to it
46
+ * * intersection: the keys listed in the group are considered to belong to the group if they're also in the parent group
47
+ * * union: the keys listed in the group are considered to belong to the group, and also the keys that are in the parent group
48
+ * * query: not supported by this parser
49
+ */
50
+ export declare function parse(comments: string[]): {
51
+ comments: string[];
52
+ jabref: JabRefMetadata;
53
+ };
@@ -0,0 +1,133 @@
1
+ function decode(s = '', sep = ';') {
2
+ s = s.replace(/\r?\n/g, '');
3
+ let pos = 0;
4
+ const records = [''];
5
+ while (pos < s.length) {
6
+ switch (s[pos]) {
7
+ case '\\':
8
+ pos++;
9
+ records[0] += s[pos];
10
+ break;
11
+ case sep:
12
+ records.unshift('');
13
+ break;
14
+ default:
15
+ records[0] += s[pos];
16
+ }
17
+ pos++;
18
+ }
19
+ return records.reverse().filter(record => record);
20
+ }
21
+ export class JabRefMetadata {
22
+ #groups = new Map();
23
+ /**
24
+ * The root groups. You can find the nested groups in their `groups` property
25
+ */
26
+ root = [];
27
+ constructor(data = {}) {
28
+ this.root = data.root ?? [];
29
+ for (const field of ['fileDirectory', 'groupsversion', 'databaseType']) {
30
+ if (data[field] !== undefined)
31
+ Object.assign(this, { [field]: data[field] });
32
+ }
33
+ const index = (groups) => {
34
+ for (const group of groups) {
35
+ if (!this.#groups.has(group.name))
36
+ this.#groups.set(group.name, group);
37
+ index(group.groups);
38
+ }
39
+ };
40
+ index(this.root);
41
+ }
42
+ /** Populates JabRef 3.8+ memberships in `root` by group name; duplicate names select the first node. */
43
+ addEntry(name, key) {
44
+ const group = this.#groups.get(name);
45
+ if (!group)
46
+ return false;
47
+ if (!group.entries.includes(key))
48
+ group.entries.push(key);
49
+ return true;
50
+ }
51
+ }
52
+ /**
53
+ * Import the JabRef groups from the `@string` comments in which they were stored. You would typically pass the comments parsed by [[bibtex.parse]] in here.
54
+ *
55
+ * JabRef knows several group types, and this parser parses most, but not all of them:
56
+ *
57
+ * * independent group: the keys listed in the group are the entries that are considered to belong to it
58
+ * * intersection: the keys listed in the group are considered to belong to the group if they're also in the parent group
59
+ * * union: the keys listed in the group are considered to belong to the group, and also the keys that are in the parent group
60
+ * * query: not supported by this parser
61
+ */
62
+ export function parse(comments) {
63
+ const result = new JabRefMetadata();
64
+ const levels = [];
65
+ const decoded = {
66
+ fileDirectory: null,
67
+ groupsversion: null,
68
+ groupstree: null,
69
+ grouping: null,
70
+ databaseType: null,
71
+ };
72
+ comments = comments.filter(comment => {
73
+ const m = comment.match(/^jabref-meta:\s*([^:]+):([\s\S]*)/); // use \s\S because mozilla doesn't understand /s
74
+ if (m) {
75
+ decoded[m[1]] = decode(m[2]);
76
+ return false;
77
+ }
78
+ return true;
79
+ });
80
+ if (decoded.groupsversion)
81
+ result.groupsversion = parseInt(decoded.groupsversion[0].trim()); // eslint-disable-line @typescript-eslint/no-unsafe-argument
82
+ if (decoded.fileDirectory)
83
+ result.fileDirectory = decoded.fileDirectory[0];
84
+ if (decoded.databaseType)
85
+ result.databaseType = decoded.databaseType[0];
86
+ for (const tree of ['groupstree', 'grouping']) {
87
+ if (!decoded[tree])
88
+ continue;
89
+ for (const encoded of decoded[tree]) {
90
+ const fields = decode(encoded);
91
+ const level_type_name = decode(fields.shift(), ':');
92
+ const m = /^([0-9]+) (.+)/.exec(level_type_name[0]);
93
+ if (!m)
94
+ break;
95
+ const level = parseInt(m[1]);
96
+ const type = m[2]; // test for StaticGroup?
97
+ if (type === 'AllEntriesGroup')
98
+ continue; // root
99
+ const name = level_type_name[1];
100
+ const intersection = decode(fields.shift())[0];
101
+ const keys = tree === 'grouping' ? [] : fields.map(field => decode(field)[0]);
102
+ const group = {
103
+ name,
104
+ entries: keys,
105
+ groups: [],
106
+ };
107
+ if (levels.length < level) {
108
+ levels.push(group);
109
+ }
110
+ else {
111
+ levels[level - 1] = group;
112
+ }
113
+ if (level === 1) {
114
+ result.root.push(group);
115
+ }
116
+ else {
117
+ const parent = levels[level - 2];
118
+ switch (intersection) {
119
+ case '0': // independent
120
+ break;
121
+ case '1': // intersect
122
+ group.entries = group.entries.filter(key => parent.entries.includes(key));
123
+ break;
124
+ case '2': // union
125
+ group.entries = group.entries.concat(parent.entries.filter(key => !group.entries.includes(key)));
126
+ break;
127
+ }
128
+ levels[level - 2].groups.push(group);
129
+ }
130
+ }
131
+ }
132
+ return { comments, jabref: new JabRefMetadata(result) };
133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retorquere/bibtex-parser",
3
- "version": "12.1.10",
3
+ "version": "12.1.11",
4
4
  "description": "BibTeX parser",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",