@larsgw/formica 0.8.5 → 0.8.7

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,7 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RANKS = void 0;
3
+ exports.RANKS = exports.RecoverableSyntaxError = void 0;
4
4
  exports.parseName = parseName;
5
+ class RecoverableSyntaxError extends SyntaxError {
6
+ constructor(message, result) {
7
+ super(message);
8
+ this.result = result;
9
+ }
10
+ }
11
+ exports.RecoverableSyntaxError = RecoverableSyntaxError;
5
12
  exports.RANKS = [
6
13
  'phylum',
7
14
  'subphylum',
@@ -33,12 +40,12 @@ exports.RANKS = [
33
40
  'race', // not ICZN
34
41
  'stirps' // not ICZN
35
42
  ];
36
- var TAXONOMIC_STATUS = {
43
+ const TAXONOMIC_STATUS = {
37
44
  '>': 'incorrect',
38
45
  '+': 'heterotypic synonym',
39
46
  '=': 'synonym'
40
47
  };
41
- var RANK_LABELS = {
48
+ const RANK_LABELS = {
42
49
  'subspecies': 'subsp.',
43
50
  'variety': 'var.',
44
51
  'form': 'f.',
@@ -46,7 +53,7 @@ var RANK_LABELS = {
46
53
  'race': 'r.',
47
54
  'stirps': 'st.'
48
55
  };
49
- var RANK_LABELS_REVERSE = {
56
+ const RANK_LABELS_REVERSE = {
50
57
  'st': 'stirps',
51
58
  'r': 'race',
52
59
  'ab': 'aberration',
@@ -55,7 +62,7 @@ var RANK_LABELS_REVERSE = {
55
62
  'ssp': 'subspecies',
56
63
  'subsp': 'subspecies'
57
64
  };
58
- var HYBRID_SIGN = '\u00D7';
65
+ const HYBRID_SIGN = '\u00D7';
59
66
  /**
60
67
  * 1. Any number of
61
68
  * - capitalized words
@@ -66,9 +73,9 @@ var HYBRID_SIGN = '\u00D7';
66
73
  * 2. Followed by a capitalized word
67
74
  * 3. Optionally, followed by "et al."
68
75
  */
69
- var LOWERCASE_NAME_PARTICLES = ['y', 'der', 'den', 'de', 'van', 'von'].join('|');
70
- var SIMPLE_AUTHOR_PATTERN = '(?:(?:\\p{Lu}\\S*|&|in|ex|' + LOWERCASE_NAME_PARTICLES + ')\\s*)*\\p{Lu}\\S+(?:\\s+et\\s+al\\.)?';
71
- var NAME_PATTERN = new RegExp('^' +
76
+ const LOWERCASE_NAME_PARTICLES = ['y', 'der', 'den', 'de', 'van', 'von'].join('|');
77
+ const SIMPLE_AUTHOR_PATTERN = '(?:(?:\\p{Lu}\\S*|&|in|ex|' + LOWERCASE_NAME_PARTICLES + ')\\s*)*\\p{Lu}\\S+(?:\\s+et\\s+al\\.)?';
78
+ const NAME_PATTERN = new RegExp('^' +
72
79
  // $1 main name part
73
80
  '(\\S+)' +
74
81
  // $2 optional author citation
@@ -93,7 +100,7 @@ var NAME_PATTERN = new RegExp('^' +
93
100
  * $1 genus: ((?:x )?[A-Z]\S+)
94
101
  * $2 subgenus: (?:\(([A-Z]\S+?)\) )?
95
102
  */
96
- var SUBGENUS_PATTERN = /^([A-Z]\S+) (?:\(([A-Z]\S+?)\))(?= |$)/;
103
+ const SUBGENUS_PATTERN = /^([A-Z]\S+) (?:\(([A-Z]\S+?)\))(?= |$)/;
97
104
  /**
98
105
  * Structure
99
106
  * $1 genus+subgenus (+ trailing space): (?:([A-Z]\S+) (?:\(([A-Z]\S+?)\) )?)?
@@ -104,7 +111,7 @@ var SUBGENUS_PATTERN = /^([A-Z]\S+) (?:\(([A-Z]\S+?)\))(?= |$)/;
104
111
  * $2b hybrid: [a-z-][^\s.]+(?: x [a-z-]+)?
105
112
  * $2c intergeneric hybrid: [A-Z][a-z]+_[a-z-]+ x [A-Z][a-z]+_[a-z-]+
106
113
  */
107
- var BINAME_PATTERN = /^(?:((?:x )?[A-Z]\S+) (?:\(([A-Z]\S+?)\) )?)?(x [a-z-]+|[a-z-][^\s.]+(?: x [a-z-]+)?|[A-Z][a-z]+_[a-z-]+ x [A-Z][a-z]+_[a-z-]+)(?= |$)/;
114
+ const BINAME_PATTERN = /^(?:((?:x )?[A-Z]\S+) (?:\(([A-Z]\S+?)\) )?)?(x [a-z-]+|[a-z-][^\s.]+(?: x [a-z-]+)?|[A-Z][a-z]+_[a-z-]+ x [A-Z][a-z]+_[a-z-]+)(?= |$)/;
108
115
  function compareRanks(a, b) {
109
116
  return exports.RANKS.indexOf(a) - exports.RANKS.indexOf(b);
110
117
  }
@@ -121,16 +128,13 @@ function isUpperCase(name) {
121
128
  return name === name.toUpperCase();
122
129
  }
123
130
  function getSynonymRank(name, rank) {
124
- var rest = name.replace(BINAME_PATTERN, '');
125
- var rankPrefix = rest.match(/^(?: |^)(st|r|ab|f|var|ssp|subsp)\. /);
131
+ const rest = name.replace(BINAME_PATTERN, '');
132
+ const rankPrefix = rest.match(/^(?: |^)(st|r|ab|f|var|ssp|subsp)\. /);
126
133
  if (rankPrefix) {
127
134
  return RANK_LABELS_REVERSE[rankPrefix[1]];
128
135
  }
129
- else if (SUBGENUS_PATTERN.test(name)) {
130
- return 'subgenus';
131
- }
132
136
  else if (!BINAME_PATTERN.test(name)) {
133
- return rank;
137
+ return SUBGENUS_PATTERN.test(name) ? 'subgenus' : rank;
134
138
  }
135
139
  else if (/^ (?!sensu)[a-z0-9-]+($| )/.test(rest)) {
136
140
  return 'subspecies';
@@ -142,15 +146,15 @@ function getSynonymRank(name, rank) {
142
146
  function capitalizeAuthors(authors) {
143
147
  return authors
144
148
  .replace(/[^\x00-\x40\x5B-\x60\x7B-\x7F]+/g, // eslint-disable-line no-control-regex
145
- function (// eslint-disable-line no-control-regex
146
- name) { return isUpperCase(name) ? capitalize(name) : name; })
149
+ // eslint-disable-line no-control-regex
150
+ name => isUpperCase(name) ? capitalize(name) : name)
147
151
  .replace(/ Y /g, ' y ');
148
152
  }
149
153
  function parseName(name, rank, parent) {
150
154
  var _a, _b;
151
- var item = {};
155
+ const item = {};
152
156
  // Synonyms have the accepted name usage as 'parent'.
153
- var isSynonym = /^[+=>] /.test(name);
157
+ const isSynonym = /^[+=>] /.test(name);
154
158
  if (isSynonym) {
155
159
  item.taxonomicStatus = TAXONOMIC_STATUS[name[0]];
156
160
  name = name.replace(/^[+=>] (\? ?)?/, '');
@@ -170,7 +174,7 @@ function parseName(name, rank, parent) {
170
174
  // For parsing, it needs to match the current file. If relevant parents
171
175
  // (i.e. genus, species) had mistakes that were corrected, the uncorrected
172
176
  // genus and species names need to be used.
173
- var parentContext = {
177
+ const parentContext = {
174
178
  genus: parent.genus,
175
179
  subgenus: parent.subgenus,
176
180
  specificEpithet: parent.specificEpithet,
@@ -184,7 +188,7 @@ function parseName(name, rank, parent) {
184
188
  // provide parts of the name (e.g. bare species without a genus parent, or
185
189
  // even subspecies without a species or genus parent).
186
190
  if (isSynonym || !parentContext.genus || (compareRanks('species', rank) < 0 && !parentContext.specificEpithet)) {
187
- var _c = (_b = (_a = name.match(BINAME_PATTERN)) !== null && _a !== void 0 ? _a : name.match(SUBGENUS_PATTERN)) !== null && _b !== void 0 ? _b : [], genus = _c[1], subgenus = _c[2], species = _c[3];
191
+ const [, genus, subgenus, species] = (_b = (_a = name.match(BINAME_PATTERN)) !== null && _a !== void 0 ? _a : name.match(SUBGENUS_PATTERN)) !== null && _b !== void 0 ? _b : [];
188
192
  if (genus) {
189
193
  parentContext.incorrect.genus = genus;
190
194
  parentContext.genus = capitalizeGenericName(genus.replace(/(^| )x /, HYBRID_SIGN));
@@ -207,7 +211,7 @@ function parseName(name, rank, parent) {
207
211
  // further.
208
212
  if (compareRanks('group', rank) <= 0) {
209
213
  // Remove genus
210
- var genus = parentContext.incorrect.genus || parentContext.genus || '';
214
+ const genus = parentContext.incorrect.genus || parentContext.genus || '';
211
215
  if (name[0] === genus[0] && name.toLowerCase().startsWith(genus.toLowerCase() + ' ')) {
212
216
  name = name.slice(genus.length + 1);
213
217
  }
@@ -216,7 +220,7 @@ function parseName(name, rank, parent) {
216
220
  // Infraspecific taxa
217
221
  if (compareRanks('species', rank) < 0) {
218
222
  // Remove specific epithet
219
- var species = parentContext.incorrect.specificEpithet || parentContext.specificEpithet || '';
223
+ const species = parentContext.incorrect.specificEpithet || parentContext.specificEpithet || '';
220
224
  if (name.startsWith(species + ' ')) {
221
225
  name = name.slice(species.length + 1);
222
226
  }
@@ -226,7 +230,7 @@ function parseName(name, rank, parent) {
226
230
  }
227
231
  else if (compareRanks('genus', rank) <= 0) {
228
232
  // Remove genus
229
- var genus = parentContext.incorrect.genus || parentContext.genus || '';
233
+ const genus = parentContext.incorrect.genus || parentContext.genus || '';
230
234
  if (name[0] === genus[0] && name.toLowerCase().startsWith(genus.toLowerCase() + ' (')) {
231
235
  name = name.slice(genus.length + 1);
232
236
  }
@@ -242,9 +246,9 @@ function parseName(name, rank, parent) {
242
246
  }
243
247
  // Divide the name into the main scientific name (only the epithet for taxa
244
248
  // lower than genus), the authorship information, and optionally remarks
245
- var nameParts = name.match(NAME_PATTERN);
249
+ const nameParts = name.match(NAME_PATTERN);
246
250
  if (!nameParts) {
247
- throw new Error("Taxon \"".concat(name, "\" could not be parsed"));
251
+ throw new Error(`Taxon "${name}" could not be parsed`);
248
252
  }
249
253
  // To encode old names with spaces (e.g. "Orsillus pini canariensis Lindberg, 1953")
250
254
  // underscores are used, which are replaced here. This is also used for undescribed
@@ -253,25 +257,28 @@ function parseName(name, rank, parent) {
253
257
  if (nameParts[1].includes('_')) {
254
258
  nameParts[1] = nameParts[1].replace(/_/g, ' ');
255
259
  }
256
- var _ = nameParts[0], taxon = nameParts[1], _d = nameParts[2], citation = _d === void 0 ? '' : _d, notes = nameParts[3];
260
+ const [_, taxon, citation = '', notes] = nameParts;
257
261
  item.scientificNameAuthorship = capitalizeAuthors(citation);
258
262
  item.taxonRemarks = notes;
259
263
  item.taxonRank = rank;
260
- // @ts-expect-error TS1501: This regular expression flag is only available when targeting 'es6' or later.
264
+ item.genericName = undefined;
265
+ item.infragenericEpithet = undefined;
266
+ item.specificEpithet = undefined;
267
+ item.infraspecificEpithet = undefined;
261
268
  if (/[^\p{L}0-9\u{00D7}\- ]/u.test(taxon)) {
262
- throw new Error("Taxon name contains unexpected characters: \"".concat(taxon, "\""));
269
+ throw new RecoverableSyntaxError(`Taxon name contains unexpected characters: "${taxon}"`, item);
263
270
  }
264
271
  // Validate names and recompose binomial and trinomial names
265
272
  if (compareRanks('genus', rank) > 0) {
266
273
  item.scientificName = capitalize(taxon);
267
274
  if (taxon[0].toUpperCase() !== taxon[0]) {
268
- throw new Error("Taxon name (".concat(rank, ") should be capitalized: \"").concat(taxon, "\""));
275
+ throw new RecoverableSyntaxError(`Taxon name (${rank}) should be capitalized: "${taxon}"`, item);
269
276
  }
270
277
  }
271
278
  else if (rank === 'genus') {
272
279
  item.scientificName = capitalizeGenericName(taxon);
273
280
  if (taxon[0].toUpperCase() !== taxon[0] || (taxon[0] === HYBRID_SIGN && taxon[1].toUpperCase() !== taxon[1])) {
274
- throw new Error("Generic epithet should be capitalized: \"".concat(taxon, "\""));
281
+ throw new RecoverableSyntaxError(`Generic epithet should be capitalized: "${taxon}"`, item);
275
282
  }
276
283
  }
277
284
  else if (compareRanks('group', rank) > 0) {
@@ -279,48 +286,44 @@ function parseName(name, rank, parent) {
279
286
  item.infragenericEpithet = parentContext.subgenus;
280
287
  item.scientificName = capitalize(taxon);
281
288
  if (taxon[0].toUpperCase() !== taxon[0]) {
282
- throw new Error("Infrageneric epithet should be capitalized: \"".concat(taxon, "\""));
289
+ throw new RecoverableSyntaxError(`Infrageneric epithet should be capitalized: "${taxon}"`, item);
283
290
  }
284
291
  }
285
292
  else if (rank === 'group') {
286
293
  item.genericName = parentContext.genus;
287
294
  item.infragenericEpithet = parentContext.subgenus;
288
- var specificEpithet = taxon.toLowerCase().replace(/(-group)?$/, '');
289
- item.scientificName = "".concat(item.genericName, " ").concat(specificEpithet, "-group");
295
+ const specificEpithet = taxon.toLowerCase().replace(/(-group)?$/, '');
296
+ item.scientificName = `${item.genericName} ${specificEpithet}-group`;
290
297
  if (taxon.toLowerCase() !== taxon) {
291
- console.log(item, taxon);
292
- throw new Error("Group name should be lowercase: \"".concat(taxon, "\""));
298
+ throw new RecoverableSyntaxError(`Group name should be lowercase: "${taxon}"`, item);
293
299
  }
294
300
  }
295
301
  else if (rank === 'subgroup') {
296
302
  item.genericName = parentContext.genus;
297
303
  item.infragenericEpithet = parentContext.subgenus;
298
- var specificEpithet = taxon.toLowerCase().replace(/(-subgroup)?$/, '');
299
- item.scientificName = "".concat(item.genericName, " ").concat(specificEpithet, "-subgroup");
304
+ const specificEpithet = taxon.toLowerCase().replace(/(-subgroup)?$/, '');
305
+ item.scientificName = `${item.genericName} ${specificEpithet}-subgroup`;
300
306
  if (taxon.toLowerCase() !== taxon) {
301
- console.log(item, taxon);
302
- throw new Error("Subgroup name should be lowercase: \"".concat(taxon, "\""));
307
+ throw new RecoverableSyntaxError(`Subgroup name should be lowercase: "${taxon}"`, item);
303
308
  }
304
309
  }
305
310
  else if (compareRanks('species', rank) > 0) {
306
311
  item.genericName = parentContext.genus;
307
312
  item.infragenericEpithet = parentContext.subgenus;
308
- var specificEpithet = taxon.toLowerCase();
309
- item.scientificName = "".concat(item.genericName, " ").concat(specificEpithet);
313
+ const specificEpithet = taxon.toLowerCase();
314
+ item.scientificName = `${item.genericName} ${specificEpithet}`;
310
315
  if (specificEpithet !== taxon) {
311
- console.log(item, taxon);
312
- throw new Error("Subgroup name should be lowercase: \"".concat(taxon, "\""));
316
+ throw new RecoverableSyntaxError(`Taxon name should be lowercase: "${taxon}"`, item);
313
317
  }
314
318
  }
315
319
  else if (rank === 'species') {
316
320
  item.genericName = parentContext.genus;
317
321
  item.infragenericEpithet = parentContext.subgenus;
318
322
  if (taxon.toLowerCase() !== taxon && !/^[A-Z][a-z]+ [a-z]+\xD7[A-Z][a-z]+ [a-z]+$/.test(taxon)) {
319
- console.log(item, taxon);
320
- throw new Error("Specific epithet should be lowercase: \"".concat(taxon, "\""));
323
+ throw new RecoverableSyntaxError(`Specific epithet should be lowercase: "${taxon}"`, item);
321
324
  }
322
325
  item.specificEpithet = taxon;
323
- item.scientificName = "".concat(item.genericName, " ").concat(item.specificEpithet);
326
+ item.scientificName = `${item.genericName} ${item.specificEpithet}`;
324
327
  }
325
328
  else if (compareRanks('species', rank) < 0) {
326
329
  item.genericName = parentContext.genus;
@@ -329,24 +332,23 @@ function parseName(name, rank, parent) {
329
332
  item.infraspecificEpithet = taxon.toLowerCase();
330
333
  // If possible, names below species should have abbreviations for ranks,
331
334
  // like "subsp."
332
- var nameParts_1 = [
335
+ const nameParts = [
333
336
  item.genericName,
334
337
  item.specificEpithet,
335
338
  item.infraspecificEpithet
336
339
  ];
337
340
  if (item.taxonRank in RANK_LABELS) {
338
- nameParts_1.splice(2, 0, RANK_LABELS[item.taxonRank]);
341
+ nameParts.splice(2, 0, RANK_LABELS[item.taxonRank]);
339
342
  }
340
- item.scientificName = nameParts_1.join(' ');
343
+ item.scientificName = nameParts.join(' ');
341
344
  if (item.infraspecificEpithet !== taxon) {
342
- console.log(item, taxon);
343
- throw new Error("Infraspecific epithet should be lowercase: \"".concat(taxon, "\""));
345
+ throw new RecoverableSyntaxError(`Infraspecific epithet should be lowercase: "${taxon}"`, item);
344
346
  }
345
347
  }
346
348
  // Re-add authorship information
347
349
  item.scientificNameOnly = item.scientificName;
348
350
  if (item.scientificNameAuthorship) {
349
- item.scientificName += " ".concat(item.scientificNameAuthorship);
351
+ item.scientificName += ` ${item.scientificNameAuthorship}`;
350
352
  }
351
353
  return item;
352
354
  }