@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,3 +1,12 @@
1
+ export class RecoverableSyntaxError<Result> extends SyntaxError {
2
+ result: Result
3
+
4
+ constructor (message: string, result: Result) {
5
+ super(message)
6
+ this.result = result
7
+ }
8
+ }
9
+
1
10
  export const RANKS: Rank[] = [
2
11
  'phylum',
3
12
  'subphylum',
@@ -138,10 +147,8 @@ function getSynonymRank (name: string, rank: Rank): Rank {
138
147
  const rankPrefix = rest.match(/^(?: |^)(st|r|ab|f|var|ssp|subsp)\. /)
139
148
  if (rankPrefix) {
140
149
  return RANK_LABELS_REVERSE[rankPrefix[1]] as string
141
- } else if (SUBGENUS_PATTERN.test(name)) {
142
- return 'subgenus'
143
150
  } else if (!BINAME_PATTERN.test(name)) {
144
- return rank
151
+ return SUBGENUS_PATTERN.test(name) ? 'subgenus' : rank
145
152
  } else if (/^ (?!sensu)[a-z0-9-]+($| )/.test(rest)) {
146
153
  return 'subspecies'
147
154
  } else {
@@ -280,29 +287,32 @@ export function parseName (name: string, rank: Rank, parent: WorkingTaxon): Work
280
287
  item.scientificNameAuthorship = capitalizeAuthors(citation)
281
288
  item.taxonRemarks = notes
282
289
  item.taxonRank = rank
290
+ item.genericName = undefined
291
+ item.infragenericEpithet = undefined
292
+ item.specificEpithet = undefined
293
+ item.infraspecificEpithet = undefined
283
294
 
284
- // @ts-expect-error TS1501: This regular expression flag is only available when targeting 'es6' or later.
285
295
  if (/[^\p{L}0-9\u{00D7}\- ]/u.test(taxon)) {
286
- throw new Error(`Taxon name contains unexpected characters: "${taxon}"`)
296
+ throw new RecoverableSyntaxError(`Taxon name contains unexpected characters: "${taxon}"`, item)
287
297
  }
288
298
 
289
299
  // Validate names and recompose binomial and trinomial names
290
300
  if (compareRanks('genus', rank) > 0) {
291
301
  item.scientificName = capitalize(taxon)
292
302
  if (taxon[0].toUpperCase() !== taxon[0]) {
293
- throw new Error(`Taxon name (${rank}) should be capitalized: "${taxon}"`)
303
+ throw new RecoverableSyntaxError(`Taxon name (${rank}) should be capitalized: "${taxon}"`, item)
294
304
  }
295
305
  } else if (rank === 'genus') {
296
306
  item.scientificName = capitalizeGenericName(taxon)
297
307
  if (taxon[0].toUpperCase() !== taxon[0] || (taxon[0] === HYBRID_SIGN && taxon[1].toUpperCase() !== taxon[1])) {
298
- throw new Error(`Generic epithet should be capitalized: "${taxon}"`)
308
+ throw new RecoverableSyntaxError(`Generic epithet should be capitalized: "${taxon}"`, item)
299
309
  }
300
310
  } else if (compareRanks('group', rank) > 0) {
301
311
  item.genericName = parentContext.genus
302
312
  item.infragenericEpithet = parentContext.subgenus
303
313
  item.scientificName = capitalize(taxon)
304
314
  if (taxon[0].toUpperCase() !== taxon[0]) {
305
- throw new Error(`Infrageneric epithet should be capitalized: "${taxon}"`)
315
+ throw new RecoverableSyntaxError(`Infrageneric epithet should be capitalized: "${taxon}"`, item)
306
316
  }
307
317
  } else if (rank === 'group') {
308
318
  item.genericName = parentContext.genus
@@ -310,8 +320,7 @@ export function parseName (name: string, rank: Rank, parent: WorkingTaxon): Work
310
320
  const specificEpithet = taxon.toLowerCase().replace(/(-group)?$/, '')
311
321
  item.scientificName = `${item.genericName} ${specificEpithet}-group`
312
322
  if (taxon.toLowerCase() !== taxon) {
313
- console.log(item, taxon)
314
- throw new Error(`Group name should be lowercase: "${taxon}"`)
323
+ throw new RecoverableSyntaxError(`Group name should be lowercase: "${taxon}"`, item)
315
324
  }
316
325
  } else if (rank === 'subgroup') {
317
326
  item.genericName = parentContext.genus
@@ -319,8 +328,7 @@ export function parseName (name: string, rank: Rank, parent: WorkingTaxon): Work
319
328
  const specificEpithet = taxon.toLowerCase().replace(/(-subgroup)?$/, '')
320
329
  item.scientificName = `${item.genericName} ${specificEpithet}-subgroup`
321
330
  if (taxon.toLowerCase() !== taxon) {
322
- console.log(item, taxon)
323
- throw new Error(`Subgroup name should be lowercase: "${taxon}"`)
331
+ throw new RecoverableSyntaxError(`Subgroup name should be lowercase: "${taxon}"`, item)
324
332
  }
325
333
  } else if (compareRanks('species', rank) > 0) {
326
334
  item.genericName = parentContext.genus
@@ -328,15 +336,13 @@ export function parseName (name: string, rank: Rank, parent: WorkingTaxon): Work
328
336
  const specificEpithet = taxon.toLowerCase()
329
337
  item.scientificName = `${item.genericName} ${specificEpithet}`
330
338
  if (specificEpithet !== taxon) {
331
- console.log(item, taxon)
332
- throw new Error(`Subgroup name should be lowercase: "${taxon}"`)
339
+ throw new RecoverableSyntaxError(`Taxon name should be lowercase: "${taxon}"`, item)
333
340
  }
334
341
  } else if (rank === 'species') {
335
342
  item.genericName = parentContext.genus
336
343
  item.infragenericEpithet = parentContext.subgenus
337
344
  if (taxon.toLowerCase() !== taxon && !/^[A-Z][a-z]+ [a-z]+\xD7[A-Z][a-z]+ [a-z]+$/.test(taxon)) {
338
- console.log(item, taxon)
339
- throw new Error(`Specific epithet should be lowercase: "${taxon}"`)
345
+ throw new RecoverableSyntaxError(`Specific epithet should be lowercase: "${taxon}"`, item)
340
346
  }
341
347
  item.specificEpithet = taxon
342
348
  item.scientificName = `${item.genericName} ${item.specificEpithet}`
@@ -359,8 +365,7 @@ export function parseName (name: string, rank: Rank, parent: WorkingTaxon): Work
359
365
  item.scientificName = nameParts.join(' ')
360
366
 
361
367
  if (item.infraspecificEpithet !== taxon) {
362
- console.log(item, taxon)
363
- throw new Error(`Infraspecific epithet should be lowercase: "${taxon}"`)
368
+ throw new RecoverableSyntaxError(`Infraspecific epithet should be lowercase: "${taxon}"`, item)
364
369
  }
365
370
  }
366
371
 
@@ -371,4 +376,4 @@ export function parseName (name: string, rank: Rank, parent: WorkingTaxon): Work
371
376
  }
372
377
 
373
378
  return item
374
- }
379
+ }
@@ -1,7 +1,7 @@
1
1
  import * as yaml from 'js-yaml'
2
2
  import { WorkResource } from './resource'
3
3
  import { createDiff, ResourceDiffType } from './diff-resource'
4
- import { parseName, RANKS } from './parse-name'
4
+ import { parseName, RANKS, RecoverableSyntaxError } from './parse-name'
5
5
 
6
6
  const MAIN_RANKS: Rank[] = [
7
7
  'kingdom',
@@ -144,7 +144,7 @@ function parseResourceContent (content: ResourceDiff, resource: Resource, oldIds
144
144
  let lineNumber = offsetLine
145
145
 
146
146
  const parents: Array<TaxonId | null> = []
147
- const previous = { id: '', indent: 0, group: { isLeaf: false, indent: 0 } }
147
+ const previous = { id: '', indent: 0, group: { isLeaf: false, indent: 0 }, errors: <SyntaxError[]>[] }
148
148
 
149
149
  for (const line of content) {
150
150
  const hasOriginalId = line.type !== ResourceDiffType.Added && !/^\s*(\[indet\]|> )/.test(line.original ?? line.text as string)
@@ -170,7 +170,6 @@ function parseResourceContent (content: ResourceDiff, resource: Resource, oldIds
170
170
  continue
171
171
  } else if (lineIndent <= previous.group.indent && (data[previous.id] && !previous.group.isLeaf)) {
172
172
  errors.push(makeParseError('Missing leaf taxon', lineNumber - 1))
173
- continue
174
173
  }
175
174
 
176
175
  // Update parentage
@@ -198,20 +197,28 @@ function parseResourceContent (content: ResourceDiff, resource: Resource, oldIds
198
197
  // Do not process "indet" lines further, as they only serve to indicate
199
198
  // that subtaxa are explicitely omitted
200
199
  if (name.startsWith('[indet]')) {
200
+ errors.push(...previous.errors)
201
+ previous.errors.length = 0
201
202
  previous.group.isLeaf = lineIndent / INDENT >= leafTaxonIndex
202
203
  continue
203
204
  }
204
205
 
205
206
  const parentId = parents.reduce((grandparent, parent) => parent ?? grandparent, null)
206
207
  const parent = parentId === null ? {} as WorkingTaxon : data[parentId]
207
- const rank = resource.metadata.levels[parents.length]
208
208
  let item
209
+ const itemErrors = []
209
210
 
210
211
  try {
212
+ const rank = resource.metadata.levels[parents.length]
211
213
  item = parseName(name, rank, parent)
212
214
  } catch (error) {
213
- errors.push(makeParseError(error.message, lineNumber))
214
- continue
215
+ if (error instanceof RecoverableSyntaxError) {
216
+ itemErrors.push(makeParseError(error.message, lineNumber))
217
+ item = error.result
218
+ } else {
219
+ errors.push(makeParseError(error.message, lineNumber))
220
+ continue
221
+ }
215
222
  }
216
223
 
217
224
  // Add higher classification info
@@ -236,12 +243,31 @@ function parseResourceContent (content: ResourceDiff, resource: Resource, oldIds
236
243
 
237
244
  // Amend "parent" with corrections, exit
238
245
  if (item.taxonomicStatus === 'incorrect') {
246
+ if (parent.taxonomicStatus !== 'accepted') {
247
+ // Remove corrected synonym from parentage
248
+ parents[parents.length - 1] = null
249
+ }
250
+
251
+ if (parent.incorrect) {
252
+ errors.push(makeParseError('Cannot apply a correction to a previous correction', lineNumber))
253
+ continue
254
+ } else if (parentId === null) {
255
+ errors.push(makeParseError('Cannot apply a correction to nothing', lineNumber))
256
+ continue
257
+ }
258
+
239
259
  parent.incorrect = { ...parent }
240
260
  for (const key in item) {
241
261
  if (key !== 'taxonomicStatus' && key !== 'verbatimIdentification') {
242
262
  parentAsObject[key] = itemAsObject[key]
243
263
  }
244
264
  }
265
+
266
+ // If "parent" is corrected, its errors can be dropped
267
+ previous.errors.length = 0
268
+ // ...but errors associated with the corrected name are added immediately
269
+ errors.push(...itemErrors)
270
+
245
271
  continue
246
272
  }
247
273
 
@@ -267,6 +293,8 @@ function parseResourceContent (content: ResourceDiff, resource: Resource, oldIds
267
293
  data[item.scientificNameID] = item
268
294
 
269
295
  // Update loop state
296
+ errors.push(...previous.errors)
297
+ previous.errors = itemErrors
270
298
  previous.id = item.scientificNameID
271
299
  if (item.taxonomicStatus === 'accepted') {
272
300
  previous.group.indent = previous.indent
@@ -274,6 +302,7 @@ function parseResourceContent (content: ResourceDiff, resource: Resource, oldIds
274
302
  }
275
303
  }
276
304
 
305
+ errors.push(...previous.errors)
277
306
  if (errors.length) {
278
307
  throw mergeParserErrors(errors)
279
308
  }
package/test/resources.js CHANGED
@@ -3,8 +3,8 @@ const assert = require('assert')
3
3
 
4
4
  const { catalog, resources } = require('../lib')
5
5
 
6
- suite('catalog', async (t) => {
7
- await test('reports missing required fields', (t) => {
6
+ suite('catalog', () => {
7
+ test('reports missing required fields', () => {
8
8
  const errors = catalog.loadData(`id
9
9
  B1`, 'catalog').validate()
10
10
  assert.deepStrictEqual(errors, [
@@ -18,8 +18,8 @@ B1`, 'catalog').validate()
18
18
  })
19
19
  })
20
20
 
21
- suite('resources', async (t) => {
22
- await test('parses author with initials', (t) => {
21
+ suite('resources', () => {
22
+ test('parses author with initials', () => {
23
23
  const [resource] = resources.parseTextFile(`---
24
24
  levels: [family, genus, species]
25
25
  ---
@@ -33,32 +33,7 @@ Sphecidae A. Costa, 1886
33
33
  assert.deepStrictEqual(Object.values(resource.taxa).map(taxon => taxon.scientificNameAuthorship), Array(3).fill('A. Costa, 1886'))
34
34
  })
35
35
 
36
- await test('does not validate name with correction', (t) => {
37
- const [resource] = resources.parseTextFile(`---
38
- levels: [species]
39
- ---
40
-
41
- Clytochrysus lapidarius (Panzer, 1804)
42
- = Crabo chrysostomus Lepeletier & Brullé, 1835
43
- > Crabro chrysostomus Lepeletier & Brullé, 1835
44
- `, 'T1')
45
- assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Clytochrysus lapidarius (Panzer, 1804)')
46
- })
47
-
48
- await test('errors for missing leaf taxa', (t) => {
49
- assert.throws(() => {
50
- resources.parseTextFile(`---
51
- levels: [family, genus, species]
52
- ---
53
-
54
- Cydnidae
55
- Cydnidae
56
- Legnotus
57
- limbosus`, 'T1')
58
- })
59
- })
60
-
61
- await test('parses synonyms starting with intraspecific ranks', (t) => {
36
+ test('parses synonyms starting with intraspecific ranks', () => {
62
37
  const [resource] = resources.parseTextFile(`---
63
38
  levels: [species]
64
39
  ---
@@ -69,7 +44,7 @@ Lygaeus equestris (Linnaeus, 1758)
69
44
  assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Lygaeus equestris f. lactans Horváth, 1899')
70
45
  })
71
46
 
72
- await test('parses accepted taxa starting with intraspecific ranks', (t) => {
47
+ test('parses accepted taxa starting with intraspecific ranks', () => {
73
48
  const [resource] = resources.parseTextFile(`---
74
49
  levels: [species, form]
75
50
  ---
@@ -80,18 +55,7 @@ Lygaeus equestris (Linnaeus, 1758)
80
55
  assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Lygaeus equestris f. lactans Horváth, 1899')
81
56
  })
82
57
 
83
- await test('does not validate "indet." lines', (t) => {
84
- const [resource] = resources.parseTextFile(`---
85
- levels: [genus, species]
86
- ---
87
-
88
- Drymus
89
- [indet]
90
- `, 'T1')
91
- assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Drymus')
92
- })
93
-
94
- await test('parses names containing non-ASCII characters', (t) => {
58
+ test('parses names containing non-ASCII characters', () => {
95
59
  const [resource] = resources.parseTextFile(`---
96
60
  levels: [species]
97
61
  ---
@@ -101,7 +65,7 @@ Nematus fåhraei Thomson
101
65
  assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Nematus fåhraei Thomson')
102
66
  })
103
67
 
104
- await test('parses synonyms in different genera', (t) => {
68
+ test('parses synonyms in different genera', () => {
105
69
  const [resource] = resources.parseTextFile(`---
106
70
  levels: [species]
107
71
  ---
@@ -113,7 +77,7 @@ Katamenes arbustorum subsp. burlinii
113
77
  assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Eumenes arbustorum var. burlinii')
114
78
  })
115
79
 
116
- await test('parses species without generic names', (t) => {
80
+ test('parses species without generic names', () => {
117
81
  const [resource] = resources.parseTextFile(`---
118
82
  levels: [genus, subgenus, species]
119
83
  ---
@@ -125,7 +89,7 @@ Microdynerus Thomson, 1874
125
89
  assert.strictEqual(resource.taxa['T1:1:3'].scientificName, 'Microdynerus microdynerus (Dalla Torre, 1889)')
126
90
  })
127
91
 
128
- await test('parses hybrids', (t) => {
92
+ test('parses hybrids', () => {
129
93
  const [resource] = resources.parseTextFile(`---
130
94
  levels: [species]
131
95
  ---
@@ -137,20 +101,7 @@ Tilia x vulgaris
137
101
  assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Tilia ×vulgaris')
138
102
  })
139
103
 
140
- await test('outputs corrected generic names', (t) => {
141
- const [resource] = resources.parseTextFile(`---
142
- levels: [genus, species]
143
- ---
144
-
145
- Bogdania Kerzhner, 1964
146
- > Bogdiana Kerzhner, 1964
147
- myrmica Kerzhner, 1964
148
- `, 'T1')
149
- assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Bogdiana Kerzhner, 1964')
150
- assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Bogdiana myrmica Kerzhner, 1964')
151
- })
152
-
153
- await test('parses cross-genus hybrids', (t) => {
104
+ test('parses cross-genus hybrids', () => {
154
105
  const [resource] = resources.parseTextFile(`---
155
106
  levels: [genus, species]
156
107
  ---
@@ -165,7 +116,7 @@ x Festulpia
165
116
  assert.strictEqual(resource.taxa['T1:1:3'].scientificName, '×Festulpia Festuca rubra×Vulpia bromoides')
166
117
  })
167
118
 
168
- await test('parses cross-genus hybrids without parent context', (t) => {
119
+ test('parses cross-genus hybrids without parent context', () => {
169
120
  const [resource] = resources.parseTextFile(`---
170
121
  levels: [species]
171
122
  ---
@@ -176,7 +127,7 @@ x Festulpia Festuca_rubra x Vulpia_bromoides
176
127
  assert.strictEqual(resource.taxa['T1:1:1'].verbatimIdentification, '× Festulpia Festuca rubra × Vulpia bromoides')
177
128
  })
178
129
 
179
- await test('handles skips in ranks', (t) => {
130
+ test('handles skips in ranks', () => {
180
131
  const [resource] = resources.parseTextFile(`---
181
132
  levels: [family, genus, species]
182
133
  ---
@@ -189,8 +140,59 @@ Apidae
189
140
  assert.strictEqual(resource.taxa['T1:1:2'].taxonRank, 'species')
190
141
  })
191
142
 
192
- await test('synonyms do not break recognition of missing leaf taxa (1)', (t) => {
143
+ test('parses genera with subgenus-rank synonyms', () => {
193
144
  const [resource] = resources.parseTextFile(`---
145
+ levels: [genus]
146
+ ---
147
+
148
+ Ectemnius Dahlbom
149
+ = Crabro (Ectemnius) Dahlbom
150
+ `, 'T1')
151
+ assert.strictEqual(resource.taxa['T1:1:2'].taxonRank, 'subgenus')
152
+ assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Ectemnius Dahlbom')
153
+ assert.strictEqual(resource.taxa['T1:1:2'].genericName, 'Crabro')
154
+ })
155
+
156
+ test('parses genera with like-name subgenera', () => {
157
+ const [resource] = resources.parseTextFile(`---
158
+ levels: [genus, subgenus]
159
+ ---
160
+
161
+ Polistes Latreille, 1802
162
+ Polistes Latreille, 1802
163
+ `, 'T1')
164
+ assert.strictEqual(resource.taxa['T1:1:2'].taxonRank, 'subgenus')
165
+ assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Polistes Latreille, 1802')
166
+ assert.strictEqual(resource.taxa['T1:1:2'].genericName, 'Polistes')
167
+ })
168
+
169
+ suite('leaf taxa checks', () => {
170
+ test('errors for missing leaf taxa', () => {
171
+ assert.throws(() => {
172
+ resources.parseTextFile(`---
173
+ levels: [family, genus, species]
174
+ ---
175
+
176
+ Cydnidae
177
+ Cydnidae
178
+ Legnotus
179
+ limbosus`, 'T1')
180
+ })
181
+ })
182
+
183
+ test('does not validate "indet." lines', () => {
184
+ const [resource] = resources.parseTextFile(`---
185
+ levels: [genus, species]
186
+ ---
187
+
188
+ Drymus
189
+ [indet]
190
+ `, 'T1')
191
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Drymus')
192
+ })
193
+
194
+ test('synonyms do not break recognition of missing leaf taxa (1)', () => {
195
+ const [resource] = resources.parseTextFile(`---
194
196
  levels: [genus, subgenus, species]
195
197
  ---
196
198
 
@@ -199,12 +201,12 @@ Bombus
199
201
  Bombus
200
202
  pascuorum
201
203
  `, 'T1')
202
- assert.strictEqual(resource.taxa['T1:1:4'].scientificName, 'Bombus pascuorum')
203
- })
204
+ assert.strictEqual(resource.taxa['T1:1:4'].scientificName, 'Bombus pascuorum')
205
+ })
204
206
 
205
- await test('synonyms do not break recognition of missing leaf taxa (2)', (t) => {
206
- assert.throws(() => {
207
- resources.parseTextFile(`---
207
+ test('synonyms do not break recognition of missing leaf taxa (2)', () => {
208
+ assert.throws(() => {
209
+ resources.parseTextFile(`---
208
210
  levels: [genus, subgenus, species]
209
211
  ---
210
212
 
@@ -214,12 +216,12 @@ Bombus
214
216
  Bombus
215
217
  pascuorum
216
218
  `, 'T1')
219
+ })
217
220
  })
218
- })
219
221
 
220
- await test('synonyms do not break recognition of missing leaf taxa (3)', (t) => {
221
- assert.throws(() => {
222
- resources.parseTextFile(`---
222
+ test('synonyms do not break recognition of missing leaf taxa (3)', () => {
223
+ assert.throws(() => {
224
+ resources.parseTextFile(`---
223
225
  levels: [family, genus, species]
224
226
  ---
225
227
 
@@ -229,32 +231,123 @@ Cydnidae
229
231
  Legnotus
230
232
  limbosus
231
233
  `, 'T1')
234
+ })
232
235
  })
233
236
  })
234
237
 
235
- await test('parses genera with subgenus-rank synonyms', (t) => {
236
- const [resource] = resources.parseTextFile(`---
237
- levels: [genus]
238
+ suite('corrections', () => {
239
+ test('outputs corrected generic names', () => {
240
+ const [resource] = resources.parseTextFile(`---
241
+ levels: [genus, species]
238
242
  ---
239
243
 
240
- Ectemnius Dahlbom
241
- = Crabro (Ectemnius) Dahlbom
244
+ Bogdania Kerzhner, 1964
245
+ > Bogdiana Kerzhner, 1964
246
+ myrmica Kerzhner, 1964
242
247
  `, 'T1')
243
- assert.strictEqual(resource.taxa['T1:1:2'].taxonRank, 'subgenus')
244
- assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Ectemnius Dahlbom')
245
- assert.strictEqual(resource.taxa['T1:1:2'].genericName, 'Crabro')
246
- })
248
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Bogdiana Kerzhner, 1964')
249
+ assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Bogdiana myrmica Kerzhner, 1964')
250
+ })
247
251
 
248
- await test('parses genera with like-name subgenera', (t) => {
249
- const [resource] = resources.parseTextFile(`---
250
- levels: [genus, subgenus]
252
+ test('does not validate name with correction', () => {
253
+ const [resource] = resources.parseTextFile(`---
254
+ levels: [species]
251
255
  ---
252
256
 
253
- Polistes Latreille, 1802
254
- Polistes Latreille, 1802
257
+ Clytochrysus lapidarius (Panzer, 1804)
258
+ = Crabo chrysostomus Lepeletier & Brullé, 1835
259
+ > Crabro chrysostomus Lepeletier & Brullé, 1835
255
260
  `, 'T1')
256
- assert.strictEqual(resource.taxa['T1:1:2'].taxonRank, 'subgenus')
257
- assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Polistes Latreille, 1802')
258
- assert.strictEqual(resource.taxa['T1:1:2'].genericName, 'Polistes')
261
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Clytochrysus lapidarius (Panzer, 1804)')
262
+ })
263
+
264
+ test('parses invalid but corrected name', () => {
265
+ const [resource] = resources.parseTextFile(`---
266
+ levels: [species]
267
+ ---
268
+
269
+ Crabro Kiesenwetteri A. Morawitz. 1866
270
+ > Crabro kiesenwetteri A. Morawitz. 1866
271
+ `, 'T1')
272
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Crabro kiesenwetteri A. Morawitz. 1866')
273
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificNameAuthorship, 'A. Morawitz. 1866')
274
+ assert.strictEqual(resource.taxa['T1:1:1'].verbatimIdentification, 'Crabro Kiesenwetteri A. Morawitz. 1866')
275
+ })
276
+
277
+ test('parses children of invalid but corrected name', () => {
278
+ const [resource] = resources.parseTextFile(`---
279
+ levels: [genus, species]
280
+ ---
281
+
282
+ Pirus L.
283
+ > Pyrus L.
284
+ aucuparia Gaertn.
285
+ Pirus domestica Sm.
286
+ Pirus aria Ehrh.
287
+ > Pyrus aria Ehrh.
288
+ `, 'T1')
289
+ assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Pyrus aucuparia Gaertn.')
290
+ assert.strictEqual(resource.taxa['T1:1:3'].scientificName, 'Pyrus domestica Sm.')
291
+ assert.strictEqual(resource.taxa['T1:1:4'].scientificName, 'Pyrus aria Ehrh.')
292
+ })
293
+
294
+ test('does not keep parts of invalid but corrected name', () => {
295
+ const [resource] = resources.parseTextFile(`---
296
+ levels: [species]
297
+ ---
298
+
299
+ Scolia 5-punctata FABRICIUS, 1781
300
+ > Scolia quinquepunctata FABRICIUS, 1781
301
+ `, 'T1')
302
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Scolia quinquepunctata Fabricius, 1781')
303
+ assert.strictEqual(resource.taxa['T1:1:1'].verbatimIdentification, 'Scolia 5-punctata FABRICIUS, 1781')
304
+ })
305
+
306
+ test('make correct diff when last line changes', () => {
307
+ const newText = `---
308
+ levels: [species]
309
+ ---
310
+
311
+ Bittacus Hageni Brauer
312
+ > Bittacus hageni Brauer
313
+ `
314
+ const oldText = `---
315
+ levels: [genus, species]
316
+ ---
317
+
318
+ Bittacus hageni Brauer
319
+ `
320
+
321
+ const [resource] = resources.parseTextFile(newText, 'T1', { txt: oldText, dwc: [[null, ['T:1:1'], ['T:1:2']]] })
322
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Bittacus hageni Brauer')
323
+ assert.strictEqual(resource.taxa['T1:1:1'].verbatimIdentification, 'Bittacus Hageni Brauer')
324
+ })
325
+
326
+ test('corrections of synonyms are correctly applied', () => {
327
+ const [resource] = resources.parseTextFile(`---
328
+ levels: [genus, subgenus, species]
329
+ ---
330
+
331
+ Lasius F.
332
+ = Domisthorpea Mor. & Drnt., 1915
333
+ > Donisthorpea Mor. & Drnt., 1915
334
+ fuliginosus Latr.
335
+ `, 'T1')
336
+ assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Donisthorpea Mor. & Drnt., 1915')
337
+ assert.strictEqual(resource.taxa['T1:1:3'].scientificName, 'Lasius fuliginosus Latr.')
338
+ })
339
+
340
+ test('corrections are correctly applied', () => {
341
+ const [resource] = resources.parseTextFile(`---
342
+ levels: [genus, species]
343
+ ---
344
+
345
+ Neopachygaster Austin, 1901
346
+ > Neopachygaster Austen, 1901
347
+ meromelas (Dufour, 1841)
348
+ `, 'T1')
349
+ assert.strictEqual(resource.taxa['T1:1:1'].scientificName, 'Neopachygaster Austen, 1901')
350
+ assert.strictEqual(resource.taxa['T1:1:2'].scientificName, 'Neopachygaster meromelas (Dufour, 1841)')
351
+ })
259
352
  })
260
353
  })
package/tsconfig.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "outDir": "./lib",
4
- "target": "es5",
4
+ "target": "es6",
5
5
 
6
6
  "noImplicitAny": true,
7
7
  "strictNullChecks": true,
8
8
  "noImplicitThis": true,
9
+
10
+ "module": "commonjs",
11
+ "moduleResolution": "node10",
9
12
  "esModuleInterop": true
10
13
  },
11
14
  "include": ["./src/**/*"]