@iebh/polyglot 4.5.0 → 4.5.1

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.
@@ -4,24 +4,19 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.parse = void 0;
7
-
8
7
  var _global = _interopRequireDefault(require("./global.js"));
9
-
10
8
  var _tools = _interopRequireDefault(require("./tools.js"));
11
-
12
9
  var _lodash = _interopRequireDefault(require("lodash"));
13
-
14
10
  var _fieldCodesParse = _interopRequireDefault(require("../data/fieldCodesParse.js"));
15
-
16
11
  var _meshTranslationsParse = _interopRequireDefault(require("../data/meshTranslationsParse.js"));
17
-
18
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
19
-
20
13
  // Parsing Objects
14
+
21
15
  // Escape all regular expression chars except for pipe
22
16
  function escapeRegExp(string) {
23
17
  return string.replace(/[.*+?^${}()[\]\\]/g, '\\$&'); // $& means the whole matched string
24
18
  }
19
+
25
20
  /**
26
21
  * Parse a given string into a lexical object tree
27
22
  * This tree can then be recompiled via each engines compile()
@@ -34,8 +29,6 @@ function escapeRegExp(string) {
34
29
  * @param {boolean} [options.preserveNewlines=true] Preserve newlines in the output as 'raw' tree nodes
35
30
  * @return {array} Array representing the parsed tree nodes
36
31
  */
37
-
38
-
39
32
  var parse = function parse(query, options) {
40
33
  var settings = _lodash["default"].defaults(options, {
41
34
  groupLines: false,
@@ -44,31 +37,24 @@ var parse = function parse(query, options) {
44
37
  preserveNewlines: true,
45
38
  transposeLines: true
46
39
  });
47
-
48
40
  _global["default"].variables.no_field_tag = []; // Empty array of offsets each time the query is parsed
49
41
 
50
42
  var q = query + ''; // Clone query
51
-
52
43
  var tree = {
53
44
  nodes: []
54
45
  }; // Tree is the full parsed tree
55
-
56
46
  var branchStack = [tree]; // Stack for where we are within the tree (will get pushed when a new group is encountered)
57
-
58
47
  var branch = tree; // Branch is the parent of leaf (branch always equals last element of branchStack)
59
-
60
48
  var lastGroup; // Optional reference to the previously created group (used to pin things)
61
-
62
49
  var leaf = branch.nodes; // Leaf is the currently active leaf node (usually branch.nodes)
63
-
64
50
  var afterWhitespace = true; // Set to true when the current character is following whitespace, a newline or the very start of the query
65
-
66
51
  var lineRefs = {}; // Object lookup for line references (usually something like `1. Foo`), only populated if `transposeLines` is true
67
- // Operate in line-by-line mode? {{{
68
52
 
53
+ // Operate in line-by-line mode? {{{
69
54
  if (settings.transposeLines || settings.groupLines || settings.removeNumbering) {
70
- var lines = q.split('\n'); // Remove numbering {{{
55
+ var lines = q.split('\n');
71
56
 
57
+ // Remove numbering {{{
72
58
  if (settings.removeNumbering) {
73
59
  var match;
74
60
  lines = lines.map(function (line) {
@@ -78,41 +64,38 @@ var parse = function parse(query, options) {
78
64
  return line;
79
65
  }
80
66
  });
81
- } // }}}
82
- // Group line content {{{
83
-
67
+ }
68
+ // }}}
84
69
 
70
+ // Group line content {{{
85
71
  if (settings.groupLines && (settings.groupLinesAlways || lines.length > 1)) {
86
72
  // Wrap lines provided they are not blank and are not just 'and', 'or', 'not' by themselves or a comment
87
73
  lines = lines.map(function (line) {
88
74
  return _lodash["default"].trim(line) && !/^\s*(and|or|not)\s*$/i.test(line) && !/^\s*#/.test(line) ? '(' + line + ')' : line;
89
75
  });
90
- } // }}}
91
-
76
+ }
77
+ // }}}
92
78
 
93
79
  q = lines.join('\n'); // Join up lines again
94
- } // }}}
95
- // Utility functions {{{
80
+ }
81
+ // }}}
96
82
 
83
+ // Utility functions {{{
97
84
  /**
98
85
  * Trim previous leaf content if it has any text
99
86
  * The leaf will be removed completely if it is now blank
100
87
  */
101
-
102
-
103
88
  function trimLastLeaf() {
104
89
  if (leaf && _lodash["default"].includes(['phrase', 'raw'], leaf.type) && / $/.test(leaf.content)) {
105
90
  leaf.content = leaf.content.substr(0, leaf.content.length - 1);
106
91
  if (!leaf.content) branch.nodes.pop();
107
92
  }
108
93
  }
109
-
110
94
  ;
111
95
  /**
112
96
  * End the previous line branch and create a new one
113
97
  * this function is run every time a new raw node is inserted
114
98
  */
115
-
116
99
  function newLine(currentNumber) {
117
100
  lastGroup = branch;
118
101
  branch = branchStack.pop();
@@ -128,10 +111,10 @@ var parse = function parse(query, options) {
128
111
  branch = newGroup;
129
112
  leaf = branch.nodes;
130
113
  }
114
+ ;
115
+ // }}}
131
116
 
132
- ; // }}}
133
117
  // Create a group for the first line
134
-
135
118
  var newGroup = {
136
119
  type: 'line',
137
120
  number: 1,
@@ -142,20 +125,19 @@ var parse = function parse(query, options) {
142
125
  branchStack.push(branch);
143
126
  branch = newGroup;
144
127
  leaf = branch.nodes;
145
- var lineNumber = 1; // Variable to store whether there is user entered line numbering
146
-
147
- var userLineNumber = false; // Variable to store byte offset of string at current point
128
+ var lineNumber = 1;
148
129
 
149
- var offset = 0; // Create string of field codes seperated by pipe operator
130
+ // Variable to store whether there is user entered line numbering
131
+ var userLineNumber = false;
132
+ // Variable to store byte offset of string at current point
133
+ var offset = 0;
150
134
 
135
+ // Create string of field codes seperated by pipe operator
151
136
  var fieldCodes = escapeRegExp(Object.keys(_fieldCodesParse["default"]).join("|"));
152
137
  var meshTranslations = escapeRegExp(Object.keys(_meshTranslationsParse["default"]).join("|"));
153
-
154
138
  while (q.length) {
155
139
  var cropString = true; // Whether to remove one charcater from the beginning of the string (set to false if the lexical match handles this behaviour itself)
156
-
157
140
  var match;
158
-
159
141
  if (/^\(/.test(q)) {
160
142
  var newGroup = {
161
143
  type: 'group',
@@ -167,13 +149,12 @@ var parse = function parse(query, options) {
167
149
  leaf = branch.nodes;
168
150
  } else if (/^\)/.test(q)) {
169
151
  lastGroup = branch;
170
-
171
152
  if (branchStack.length > 0) {
172
153
  branch = branchStack.pop();
173
- } else {// TODO: Code for popover message
154
+ } else {
155
+ // TODO: Code for popover message
174
156
  // branch.msg = "Extra closing bracket removed after term"
175
157
  }
176
-
177
158
  leaf = branch.nodes;
178
159
  } else if (match = /^([0-9]+)\s*[‐\-]\s*([0-9]+)(?:\/(AND|OR|NOT))/i.exec(q)) {
179
160
  // 1-7/OR
@@ -208,7 +189,6 @@ var parse = function parse(query, options) {
208
189
  });
209
190
  offset += match[1].length;
210
191
  q = q.substr(match[1].length); // NOTE we only move by the digits, not the whole expression - so we can still handle the AND/OR correctly
211
-
212
192
  cropString = false;
213
193
  } else {
214
194
  leaf.content += match[1];
@@ -218,27 +198,23 @@ var parse = function parse(query, options) {
218
198
  } else if (match = /^((AND|OR|NOT) +#?([0-9]+))($(?![\r\n])|\s+|\))/i.exec(q)) {
219
199
  // AND 2...
220
200
  trimLastLeaf();
221
-
222
201
  switch (match[2].toLowerCase()) {
223
202
  case "and":
224
203
  branch.nodes.push({
225
204
  type: 'joinAnd'
226
205
  });
227
206
  break;
228
-
229
207
  case "or":
230
208
  branch.nodes.push({
231
209
  type: 'joinOr'
232
210
  });
233
211
  break;
234
-
235
212
  case "not":
236
213
  branch.nodes.push({
237
214
  type: 'joinNot'
238
215
  });
239
216
  break;
240
217
  }
241
-
242
218
  leaf = undefined;
243
219
  cropString = false;
244
220
  branch.nodes.push({
@@ -316,265 +292,243 @@ var parse = function parse(query, options) {
316
292
  offset += match[0].length;
317
293
  q = q.substr(match[0].length);
318
294
  cropString = false;
319
- } // MESHTRANSLATIONS {{{
295
+ }
296
+ // MESHTRANSLATIONS {{{
320
297
  else if (afterWhitespace && (match = new RegExp("^(".concat(meshTranslations, ")"), "i").exec(q.toLowerCase().replace(/"/g, '')))) {
298
+ branch.nodes.push({
299
+ type: 'meshTranslation',
300
+ field: _meshTranslationsParse["default"][match[1]]
301
+ });
302
+ match = /.+?[\.\[]\S+[\.\]]/.exec(q);
303
+ offset += match[0].length;
304
+ q = q.substr(match[0].length);
305
+ cropString = false;
306
+ }
307
+ /// }}}
308
+ // MESH {{{
309
+ else if (match = /^\[(mesh terms|mesh|mh)(:NoExp|:no exp)?\]/i.exec(q)) {
310
+ // Mesh term - PubMed syntax
311
+ leaf.type = 'mesh';
312
+ leaf.field = match[2] ? 'Mesh search (Not exploded)' : 'Mesh search (exploded)';
313
+ if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
314
+ offset += match[0].length;
315
+ q = q.substr(match[0].length);
316
+ cropString = false;
317
+ } else if (match = /^([^\s\/]*)\/?([^\s\)\/]+)?\[(majr|mesh major topic)(:NoExp|:no exp)?\]/i.exec(q)) {
318
+ // Major Mesh term - PubMed syntax (No Quotes)
319
+ var newLeaf = {};
320
+ newLeaf.type = 'mesh';
321
+ newLeaf.content = match[1];
322
+ if (match[2]) {
323
+ newLeaf.heading = match[2];
324
+ }
325
+ newLeaf.field = match[4] ? 'MeSH Major Topic search (Not exploded)' : 'MeSH Major Topic search (exploded)';
326
+ if (/^["“”].*["“”]$/.test(newLeaf.content)) newLeaf.content = newLeaf.content.substr(1, newLeaf.content.length - 2); // Remove wrapping '"' characters
327
+ branch.nodes.push(newLeaf);
328
+ offset += match[0].length;
329
+ q = q.substr(match[0].length);
330
+ cropString = false;
331
+ } else if (match = /^"([^\\[]*)"\/?([^\s\)\/]+)?\[(majr|mesh major topic)(:NoExp|:no exp)?\]/i.exec(q)) {
332
+ // Major Mesh term - PubMed syntax (With Quotes)
333
+ var newLeaf = {};
334
+ newLeaf.type = 'mesh';
335
+ newLeaf.content = match[1];
336
+ if (match[2]) {
337
+ newLeaf.heading = match[2];
338
+ }
339
+ newLeaf.field = match[4] ? 'MeSH Major Topic search (Not exploded)' : 'MeSH Major Topic search (exploded)';
340
+ if (/^["“”].*["“”]$/.test(newLeaf.content)) newLeaf.content = newLeaf.content.substr(1, newLeaf.content.length - 2); // Remove wrapping '"' characters
341
+ branch.nodes.push(newLeaf);
342
+ offset += match[0].length;
343
+ q = q.substr(match[0].length);
344
+ cropString = false;
345
+ } else if (match = /^\[(mesh subheading|sh)\]/i.exec(q)) {
346
+ // Mesh subheading search - PubMed syntax
347
+ leaf.type = 'mesh';
348
+ leaf.field = 'MeSH subheading search';
349
+ if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
350
+ offset += match[0].length;
351
+ q = q.substr(match[0].length);
352
+ cropString = false;
353
+ } else if (match = /^\.(fs)\./i.exec(q)) {
354
+ // Mesh subheading search - Ovid syntax
355
+ var useLeaf;
356
+ if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
357
+ useLeaf = leaf;
358
+ } else if (_lodash["default"].isArray(leaf) && lastGroup) {
359
+ useLeaf = lastGroup;
360
+ }
361
+ leaf.type = 'mesh';
362
+ useLeaf.field = 'MeSH subheading search';
363
+ if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
364
+ offset += match[0].length;
365
+ q = q.substr(match[0].length);
366
+ cropString = false;
367
+ } else if (match = /^\.(xm|sh)\./i.exec(q)) {
368
+ // Mesh search (field codes) - Ovid syntax
369
+ var useLeaf;
370
+ if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
371
+ useLeaf = leaf;
372
+ } else if (_lodash["default"].isArray(leaf) && lastGroup) {
373
+ useLeaf = lastGroup;
374
+ }
375
+ leaf.type = 'mesh';
376
+ useLeaf.field = match[1] === "xm" ? 'Mesh search (exploded)' : 'Mesh search (Not exploded)';
377
+ if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
378
+ offset += match[0].length;
379
+ q = q.substr(match[0].length);
380
+ cropString = false;
381
+ } else if ((match = /^(exp "([^*]*?)"\/)\s*/i.exec(q)) || (match = /^(exp ([^*]*?)\/([^\s\)]+)?)\s*/i.exec(q))) {
382
+ // Mesh term - Ovid syntax (exploded)
383
+ var newLeaf = {
384
+ type: 'mesh',
385
+ field: 'Mesh search (exploded)',
386
+ content: match[2]
387
+ };
388
+ if (match[3]) {
389
+ newLeaf.heading = match[3];
390
+ }
391
+ branch.nodes.push(newLeaf);
392
+ offset += match[1].length;
393
+ q = q.substr(match[1].length);
394
+ cropString = false;
395
+ afterWhitespace = true;
396
+ } else if ((match = /^(exp \*"([^*]*?)"\/)\s*/i.exec(q)) || (match = /^(exp \*([^*]*?)\/([^\s\)]+)?)\s*/i.exec(q))) {
397
+ // Major Mesh term - Ovid syntax
398
+ var newLeaf = {
399
+ type: 'mesh',
400
+ field: 'MeSH Major Topic search (exploded)',
401
+ content: match[2]
402
+ };
403
+ if (match[3]) {
404
+ newLeaf.heading = match[3];
405
+ }
406
+ branch.nodes.push(newLeaf);
407
+ offset += match[1].length;
408
+ q = q.substr(match[1].length);
409
+ cropString = false;
410
+ afterWhitespace = true;
411
+ } else if (/^\//.test(q) && leaf && leaf.type && leaf.type == 'phrase') {
412
+ // Mesh term - Ovid syntax (non-exploded)
413
+ leaf.type = 'mesh';
414
+ // Major Mesh
415
+ if (leaf.content[0] == "*") {
416
+ leaf.content = leaf.content.substr(1);
417
+ leaf.field = 'MeSH Major Topic search (Not exploded)';
418
+ } else leaf.field = 'Mesh search (Not exploded)';
419
+ }
420
+ // }}}
421
+ else if (match = /^<(.*?)>/.exec(q)) {
422
+ branch.nodes.push({
423
+ type: 'template',
424
+ content: match[1].toLowerCase()
425
+ });
426
+ offset += match[0].length;
427
+ q = q.substr(match[0].length);
428
+ cropString = false;
429
+ } else if (match = /^(\n)+/.exec(q)) {
430
+ if (settings.preserveNewlines) {
431
+ var number_newline = match[0].length;
321
432
  branch.nodes.push({
322
- type: 'meshTranslation',
323
- field: _meshTranslationsParse["default"][match[1]]
433
+ type: 'raw',
434
+ content: '\n'.repeat(number_newline)
324
435
  });
325
- match = /.+?[\.\[]\S+[\.\]]/.exec(q);
436
+ leaf = undefined;
437
+ }
438
+ lineNumber += match[0].length;
439
+ if (branchStack.length > 0 && branchStack[branchStack.length - 1].nodes.every(function (node) {
440
+ return node.type !== "group";
441
+ })) {
442
+ // If we are currently inside a group don't add a newline group
443
+ newLine(lineNumber);
444
+ }
445
+ offset += match[0].length;
446
+ q = q.substr(match[0].length);
447
+ cropString = false;
448
+ afterWhitespace = true;
449
+ } else if (match = /^(\r)+/.exec(q)) {
450
+ offset += match[0].length;
451
+ q = q.substr(match[0].length);
452
+ cropString = false;
453
+ afterWhitespace = true;
454
+ }
455
+ // Match field codes {{{
456
+ else if (match = new RegExp("^(".concat(fieldCodes, ") *(\\[mp=[^\\]\\n]*\\])?"), "i").exec(q)) {
457
+ // Field specifier - PubMed syntax
458
+ // Figure out the leaf to use (usually the last one) or the previously used group
459
+ var useLeaf;
460
+ if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
461
+ useLeaf = leaf;
462
+ } else if (_lodash["default"].isArray(leaf) && lastGroup) {
463
+ useLeaf = lastGroup;
464
+ }
465
+ useLeaf.field = _fieldCodesParse["default"][match[1].toLowerCase()];
466
+ if (match[2]) {
326
467
  offset += match[0].length;
327
468
  q = q.substr(match[0].length);
328
- cropString = false;
329
- } /// }}}
330
- // MESH {{{
331
- else if (match = /^\[(mesh terms|mesh|mh)(:NoExp|:no exp)?\]/i.exec(q)) {
332
- // Mesh term - PubMed syntax
333
- leaf.type = 'mesh';
334
- leaf.field = match[2] ? 'Mesh search (Not exploded)' : 'Mesh search (exploded)';
335
- if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
336
-
337
- offset += match[0].length;
338
- q = q.substr(match[0].length);
339
- cropString = false;
340
- } else if (match = /^([^\s\/]*)\/?([^\s\)\/]+)?\[(majr|mesh major topic)(:NoExp|:no exp)?\]/i.exec(q)) {
341
- // Major Mesh term - PubMed syntax (No Quotes)
342
- var newLeaf = {};
343
- newLeaf.type = 'mesh';
344
- newLeaf.content = match[1];
345
-
346
- if (match[2]) {
347
- newLeaf.heading = match[2];
348
- }
349
-
350
- newLeaf.field = match[4] ? 'MeSH Major Topic search (Not exploded)' : 'MeSH Major Topic search (exploded)';
351
- if (/^["“”].*["“”]$/.test(newLeaf.content)) newLeaf.content = newLeaf.content.substr(1, newLeaf.content.length - 2); // Remove wrapping '"' characters
352
-
353
- branch.nodes.push(newLeaf);
354
- offset += match[0].length;
355
- q = q.substr(match[0].length);
356
- cropString = false;
357
- } else if (match = /^"([^\\[]*)"\/?([^\s\)\/]+)?\[(majr|mesh major topic)(:NoExp|:no exp)?\]/i.exec(q)) {
358
- // Major Mesh term - PubMed syntax (With Quotes)
359
- var newLeaf = {};
360
- newLeaf.type = 'mesh';
361
- newLeaf.content = match[1];
362
-
363
- if (match[2]) {
364
- newLeaf.heading = match[2];
365
- }
366
-
367
- newLeaf.field = match[4] ? 'MeSH Major Topic search (Not exploded)' : 'MeSH Major Topic search (exploded)';
368
- if (/^["“”].*["“”]$/.test(newLeaf.content)) newLeaf.content = newLeaf.content.substr(1, newLeaf.content.length - 2); // Remove wrapping '"' characters
369
-
370
- branch.nodes.push(newLeaf);
371
- offset += match[0].length;
372
- q = q.substr(match[0].length);
373
- cropString = false;
374
- } else if (match = /^\[(mesh subheading|sh)\]/i.exec(q)) {
375
- // Mesh subheading search - PubMed syntax
376
- leaf.type = 'mesh';
377
- leaf.field = 'MeSH subheading search';
378
- if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
379
-
380
- offset += match[0].length;
381
- q = q.substr(match[0].length);
382
- cropString = false;
383
- } else if (match = /^\.(fs)\./i.exec(q)) {
384
- // Mesh subheading search - Ovid syntax
385
- var useLeaf;
386
-
387
- if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
388
- useLeaf = leaf;
389
- } else if (_lodash["default"].isArray(leaf) && lastGroup) {
390
- useLeaf = lastGroup;
391
- }
392
-
393
- leaf.type = 'mesh';
394
- useLeaf.field = 'MeSH subheading search';
395
- if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
396
-
469
+ } else {
470
+ offset += match[1].length;
471
+ q = q.substr(match[1].length);
472
+ }
473
+ cropString = false;
474
+ }
475
+ // }}}
476
+ /// Comment {{{
477
+ else if (match = /^#([^\)\d\n][^\)\n]+)/.exec(q)) {
478
+ trimLastLeaf();
479
+ branch.nodes.push({
480
+ type: 'comment',
481
+ content: match[1]
482
+ });
483
+ leaf = undefined;
484
+ offset += match[0].length;
485
+ q = q.substr(match[0].length);
486
+ cropString = false;
487
+ }
488
+ // }}}
489
+ else {
490
+ var nextChar = q.substr(0, 1);
491
+ if ((_lodash["default"].isUndefined(leaf) || _lodash["default"].isArray(leaf)) && nextChar != ' ') {
492
+ // Leaf pointing to array entity - probably not created fallback leaf to append to
493
+ if (/^["“”]$/.test(nextChar) && (match = /^["“”](.*?)["“”]/.exec(q))) {
494
+ // First character is a speachmark - slurp until we see the next one
495
+ leaf = {
496
+ type: 'phrase',
497
+ content: match[1],
498
+ offset: offset
499
+ };
500
+ branch.nodes.push(leaf);
397
501
  offset += match[0].length;
398
502
  q = q.substr(match[0].length);
399
503
  cropString = false;
400
- } else if (match = /^\.(xm|sh)\./i.exec(q)) {
401
- // Mesh search (field codes) - Ovid syntax
402
- var useLeaf;
403
-
404
- if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
405
- useLeaf = leaf;
406
- } else if (_lodash["default"].isArray(leaf) && lastGroup) {
407
- useLeaf = lastGroup;
408
- }
409
-
410
- leaf.type = 'mesh';
411
- useLeaf.field = match[1] === "xm" ? 'Mesh search (exploded)' : 'Mesh search (Not exploded)';
412
- if (/^["“”].*["“”]$/.test(leaf.content)) leaf.content = leaf.content.substr(1, leaf.content.length - 2); // Remove wrapping '"' characters
413
-
504
+ } else if (match = /^[^\s:/[.)]+/.exec(q)) {
505
+ // Slurp the phrase until the space or any character which indicates the end of a phrase
506
+ leaf = {
507
+ type: 'phrase',
508
+ content: match[0],
509
+ offset: offset
510
+ };
511
+ branch.nodes.push(leaf);
414
512
  offset += match[0].length;
415
513
  q = q.substr(match[0].length);
416
514
  cropString = false;
417
- } else if ((match = /^(exp "([^*]*?)"\/)\s*/i.exec(q)) || (match = /^(exp ([^*]*?)\/([^\s\)]+)?)\s*/i.exec(q))) {
418
- // Mesh term - Ovid syntax (exploded)
419
- var newLeaf = {
420
- type: 'mesh',
421
- field: 'Mesh search (exploded)',
422
- content: match[2]
423
- };
424
-
425
- if (match[3]) {
426
- newLeaf.heading = match[3];
427
- }
428
-
429
- branch.nodes.push(newLeaf);
430
- offset += match[1].length;
431
- q = q.substr(match[1].length);
432
- cropString = false;
433
- afterWhitespace = true;
434
- } else if ((match = /^(exp \*"([^*]*?)"\/)\s*/i.exec(q)) || (match = /^(exp \*([^*]*?)\/([^\s\)]+)?)\s*/i.exec(q))) {
435
- // Major Mesh term - Ovid syntax
436
- var newLeaf = {
437
- type: 'mesh',
438
- field: 'MeSH Major Topic search (exploded)',
439
- content: match[2]
515
+ } else {
516
+ // All other first chars - just dump into a buffer and let it fill slowly
517
+ leaf = {
518
+ type: 'phrase',
519
+ content: nextChar,
520
+ offset: offset
440
521
  };
441
-
442
- if (match[3]) {
443
- newLeaf.heading = match[3];
444
- }
445
-
446
- branch.nodes.push(newLeaf);
447
- offset += match[1].length;
448
- q = q.substr(match[1].length);
449
- cropString = false;
450
- afterWhitespace = true;
451
- } else if (/^\//.test(q) && leaf && leaf.type && leaf.type == 'phrase') {
452
- // Mesh term - Ovid syntax (non-exploded)
453
- leaf.type = 'mesh'; // Major Mesh
454
-
455
- if (leaf.content[0] == "*") {
456
- leaf.content = leaf.content.substr(1);
457
- leaf.field = 'MeSH Major Topic search (Not exploded)';
458
- } else leaf.field = 'Mesh search (Not exploded)';
459
- } // }}}
460
- else if (match = /^<(.*?)>/.exec(q)) {
461
- branch.nodes.push({
462
- type: 'template',
463
- content: match[1].toLowerCase()
464
- });
465
- offset += match[0].length;
466
- q = q.substr(match[0].length);
467
- cropString = false;
468
- } else if (match = /^(\n)+/.exec(q)) {
469
- if (settings.preserveNewlines) {
470
- var number_newline = match[0].length;
471
- branch.nodes.push({
472
- type: 'raw',
473
- content: '\n'.repeat(number_newline)
474
- });
475
- leaf = undefined;
476
- }
477
-
478
- lineNumber += match[0].length;
479
-
480
- if (branchStack.length > 0 && branchStack[branchStack.length - 1].nodes.every(function (node) {
481
- return node.type !== "group";
482
- })) {
483
- // If we are currently inside a group don't add a newline group
484
- newLine(lineNumber);
485
- }
486
-
487
- offset += match[0].length;
488
- q = q.substr(match[0].length);
489
- cropString = false;
490
- afterWhitespace = true;
491
- } else if (match = /^(\r)+/.exec(q)) {
492
- offset += match[0].length;
493
- q = q.substr(match[0].length);
494
- cropString = false;
495
- afterWhitespace = true;
496
- } // Match field codes {{{
497
- else if (match = new RegExp("^(".concat(fieldCodes, ") *(\\[mp=[^\\]\\n]*\\])?"), "i").exec(q)) {
498
- // Field specifier - PubMed syntax
499
- // Figure out the leaf to use (usually the last one) or the previously used group
500
- var useLeaf;
501
-
502
- if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
503
- useLeaf = leaf;
504
- } else if (_lodash["default"].isArray(leaf) && lastGroup) {
505
- useLeaf = lastGroup;
506
- }
507
-
508
- useLeaf.field = _fieldCodesParse["default"][match[1].toLowerCase()];
509
-
510
- if (match[2]) {
511
- offset += match[0].length;
512
- q = q.substr(match[0].length);
513
- } else {
514
- offset += match[1].length;
515
- q = q.substr(match[1].length);
516
- }
517
-
518
- cropString = false;
519
- } // }}}
520
- /// Comment {{{
521
- else if (match = /^#([^\)\d\n][^\)\n]+)/.exec(q)) {
522
- trimLastLeaf();
523
- branch.nodes.push({
524
- type: 'comment',
525
- content: match[1]
526
- });
527
- leaf = undefined;
528
- offset += match[0].length;
529
- q = q.substr(match[0].length);
530
- cropString = false;
531
- } // }}}
532
- else {
533
- var nextChar = q.substr(0, 1);
534
-
535
- if ((_lodash["default"].isUndefined(leaf) || _lodash["default"].isArray(leaf)) && nextChar != ' ') {
536
- // Leaf pointing to array entity - probably not created fallback leaf to append to
537
- if (/^["“”]$/.test(nextChar) && (match = /^["“”](.*?)["“”]/.exec(q))) {
538
- // First character is a speachmark - slurp until we see the next one
539
- leaf = {
540
- type: 'phrase',
541
- content: match[1],
542
- offset: offset
543
- };
544
- branch.nodes.push(leaf);
545
- offset += match[0].length;
546
- q = q.substr(match[0].length);
547
- cropString = false;
548
- } else if (match = /^[^\s:/[.)]+/.exec(q)) {
549
- // Slurp the phrase until the space or any character which indicates the end of a phrase
550
- leaf = {
551
- type: 'phrase',
552
- content: match[0],
553
- offset: offset
554
- };
555
- branch.nodes.push(leaf);
556
- offset += match[0].length;
557
- q = q.substr(match[0].length);
558
- cropString = false;
559
- } else {
560
- // All other first chars - just dump into a buffer and let it fill slowly
561
- leaf = {
562
- type: 'phrase',
563
- content: nextChar,
564
- offset: offset
565
- };
566
- branch.nodes.push(leaf);
567
- }
568
- } else if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
569
- leaf.content += nextChar;
570
- }
571
-
572
- afterWhitespace = nextChar == ' '; // Is the nextChar whitespace? Then set the flag
573
- }
522
+ branch.nodes.push(leaf);
523
+ }
524
+ } else if (_lodash["default"].isObject(leaf) && leaf.type == 'phrase') {
525
+ leaf.content += nextChar;
526
+ }
527
+ afterWhitespace = nextChar == ' '; // Is the nextChar whitespace? Then set the flag
528
+ }
574
529
 
575
530
  if (cropString) {
576
531
  offset += 1; // Increment offset by 1
577
-
578
532
  q = q.substr(1); // Crop 1 character
579
533
  }
580
534
  }
@@ -582,33 +536,31 @@ var parse = function parse(query, options) {
582
536
  if (settings.transposeLines) {
583
537
  _tools["default"].visit(tree.nodes, ['ref'], function (node, path) {
584
538
  var reference;
585
- var line; // Find the matching line
586
-
539
+ var line;
540
+ // Find the matching line
587
541
  for (reference in node.ref) {
588
542
  var found = false;
589
-
590
543
  for (line in tree.nodes) {
591
544
  // If custom numbering is used only use nodes that are numbered by the user
592
545
  if (userLineNumber) {
593
546
  if (tree.nodes[line].number == node.ref[reference] && tree.nodes[line].isNumbered) {
594
547
  // Copy the nodes from that line into the reference nodes
595
- node.nodes.push(Array.from(tree.nodes[line].nodes)); // Pop the raw node
596
-
548
+ node.nodes.push(Array.from(tree.nodes[line].nodes));
549
+ // Pop the raw node
597
550
  node.nodes[reference].pop();
598
551
  found = true;
599
552
  }
600
553
  } else {
601
554
  if (tree.nodes[line].number == node.ref[reference]) {
602
555
  // Copy the nodes from that line into the reference nodes
603
- node.nodes.push(Array.from(tree.nodes[line].nodes)); // Pop the raw node
604
-
556
+ node.nodes.push(Array.from(tree.nodes[line].nodes));
557
+ // Pop the raw node
605
558
  node.nodes[reference].pop();
606
559
  found = true;
607
560
  }
608
561
  }
609
- } // Line not found, push error message
610
-
611
-
562
+ }
563
+ // Line not found, push error message
612
564
  if (!found) {
613
565
  node.nodes.push([{
614
566
  type: "phrase",
@@ -618,8 +570,6 @@ var parse = function parse(query, options) {
618
570
  }
619
571
  });
620
572
  }
621
-
622
573
  return tree.nodes;
623
574
  };
624
-
625
575
  exports.parse = parse;