@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,15 +1,4 @@
1
1
  "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
3
  if (k2 === undefined) k2 = k;
15
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -46,11 +35,11 @@ var __importStar = (this && this.__importStar) || (function () {
46
35
  Object.defineProperty(exports, "__esModule", { value: true });
47
36
  exports.parseFile = parseFile;
48
37
  exports.parseFileHeader = parseFileHeader;
49
- var yaml = __importStar(require("js-yaml"));
50
- var resource_1 = require("./resource");
51
- var diff_resource_1 = require("./diff-resource");
52
- var parse_name_1 = require("./parse-name");
53
- var MAIN_RANKS = [
38
+ const yaml = __importStar(require("js-yaml"));
39
+ const resource_1 = require("./resource");
40
+ const diff_resource_1 = require("./diff-resource");
41
+ const parse_name_1 = require("./parse-name");
42
+ const MAIN_RANKS = [
54
43
  'kingdom',
55
44
  'phylum',
56
45
  'class',
@@ -59,7 +48,7 @@ var MAIN_RANKS = [
59
48
  'genus',
60
49
  'species'
61
50
  ];
62
- var DWC_RANKS = [
51
+ const DWC_RANKS = [
63
52
  'kingdom',
64
53
  'phylum',
65
54
  'class',
@@ -69,28 +58,27 @@ var DWC_RANKS = [
69
58
  'genus',
70
59
  'subgenus'
71
60
  ];
72
- var FLAGS = [
61
+ const FLAGS = [
73
62
  'MISSING_TAXA',
74
63
  'MISSING_PARENT_TAXA',
75
64
  'MISSING_SYNONYMS',
76
65
  'MISSING_AUTHORSHIP'
77
66
  ];
78
- var RESOURCE_DELIMITER = '\n\n===\n\n';
79
- var INDENT = 2;
80
- function makeParseError(message, line, column) {
81
- if (column === void 0) { column = 1; }
82
- return new SyntaxError("[".concat(line, ":").concat(column, "] ").concat(message));
67
+ const RESOURCE_DELIMITER = '\n\n===\n\n';
68
+ const INDENT = 2;
69
+ function makeParseError(message, line, column = 1) {
70
+ return new SyntaxError(`[${line}:${column}] ${message}`);
83
71
  }
84
72
  function mergeParserErrors(errors) {
85
- return new SyntaxError(errors.map(function (error) { return error.message; }).join('\n'));
73
+ return new SyntaxError(errors.map(error => error.message).join('\n'));
86
74
  }
87
75
  function parseHeader(header) {
88
- var config = yaml.load(header);
76
+ const config = yaml.load(header);
89
77
  if (typeof config !== 'object' || Array.isArray(config) || config === null) {
90
78
  throw new SyntaxError('yaml header should be an object');
91
79
  }
92
80
  // Invalid configuration
93
- var levels;
81
+ let levels;
94
82
  if (!('levels' in config)) {
95
83
  levels = [];
96
84
  }
@@ -108,18 +96,18 @@ function parseHeader(header) {
108
96
  throw new SyntaxError('Resource contains no taxa');
109
97
  }
110
98
  // Invalid taxon ranks
111
- var invalidTaxonRanks = levels.filter(function (rank) { return !parse_name_1.RANKS.includes(rank); });
99
+ const invalidTaxonRanks = levels.filter(rank => !parse_name_1.RANKS.includes(rank));
112
100
  if (invalidTaxonRanks.length) {
113
- throw new SyntaxError("\"levels\" contains invalid values: ".concat(invalidTaxonRanks.join(', ')));
101
+ throw new SyntaxError(`"levels" contains invalid values: ${invalidTaxonRanks.join(', ')}`);
114
102
  }
115
- var metadata = { levels: levels };
103
+ const metadata = { levels };
116
104
  if ('catalog' in config && typeof config.catalog === 'object' && config.catalog !== null) {
117
- var catalog = {};
105
+ const catalog = {};
118
106
  if ('id' in config.catalog) {
119
107
  throw new SyntaxError('"catalog" should not contain id');
120
108
  }
121
- for (var key in config.catalog) {
122
- var value = config.catalog[key];
109
+ for (const key in config.catalog) {
110
+ const value = config.catalog[key];
123
111
  if (typeof value === 'number') {
124
112
  catalog[key] = value.toString();
125
113
  }
@@ -127,22 +115,16 @@ function parseHeader(header) {
127
115
  catalog[key] = value;
128
116
  }
129
117
  else {
130
- throw new SyntaxError("\"catalog\" should contain only strings (\"".concat(key, "\")"));
118
+ throw new SyntaxError(`"catalog" should contain only strings ("${key}")`);
131
119
  }
132
120
  }
133
- var work = new resource_1.WorkResource(catalog);
134
- var errors = work.validate().filter(function (_a) {
135
- var error = _a.error;
136
- return error !== 'Value(s) required but missing';
137
- });
121
+ const work = new resource_1.WorkResource(catalog);
122
+ const errors = work.validate().filter(({ error }) => error !== 'Value(s) required but missing');
138
123
  if (errors.length > 0) {
139
- throw new SyntaxError("\"catalog\" contains errors: ".concat(errors.map(function (_a) {
140
- var field = _a.field, error = _a.error;
141
- return "[".concat(field, "] ").concat(error);
142
- }).join('; ')));
124
+ throw new SyntaxError(`"catalog" contains errors: ${errors.map(({ field, error }) => `[${field}] ${error}`).join('; ')}`);
143
125
  }
144
126
  metadata.catalog = {};
145
- for (var key in work.fields) {
127
+ for (const key in work.fields) {
146
128
  metadata.catalog[key] = work.get(key);
147
129
  }
148
130
  }
@@ -150,40 +132,39 @@ function parseHeader(header) {
150
132
  if (!Array.isArray(config.flags)) {
151
133
  throw new SyntaxError('"flags" should be an array if present');
152
134
  }
153
- var invalidFlags = config.flags.filter(function (flag) { return !FLAGS.includes(flag); });
135
+ const invalidFlags = config.flags.filter(flag => !FLAGS.includes(flag));
154
136
  if (invalidFlags.length) {
155
- throw new SyntaxError("\"flags\" contains invalid values: ".concat(invalidFlags.join(', ')));
137
+ throw new SyntaxError(`"flags" contains invalid values: ${invalidFlags.join(', ')}`);
156
138
  }
157
139
  metadata.flags = config.flags;
158
140
  }
159
141
  return metadata;
160
142
  }
161
143
  function parseResource(resource) {
162
- var _a = resource.content.split(/(\n---\n+)/), header = _a[0], _ = _a[1], rest = _a.slice(2);
163
- var config;
144
+ const [header, _, ...rest] = resource.content.split(/(\n---\n+)/);
145
+ let config;
164
146
  try {
165
147
  config = parseHeader(header);
166
148
  }
167
149
  catch (error) {
168
150
  throw makeParseError(error.message, resource.offsetLine + 1);
169
151
  }
170
- var content = rest.join('');
171
- var offsetLine = resource.offsetLine + (header + _).split('\n').length - 1;
172
- return [config, { content: content, offsetLine: offsetLine }];
152
+ const content = rest.join('');
153
+ const offsetLine = resource.offsetLine + (header + _).split('\n').length - 1;
154
+ return [config, { content, offsetLine }];
173
155
  }
174
156
  function parseResourceContent(content, resource, oldIds, offsetLine) {
175
157
  var _a, _b;
176
- var leafTaxonIndex = resource.metadata.levels.reduce(function (last, rank, i) { return MAIN_RANKS.includes(rank) ? i : last; }, 0);
177
- var data = resource.taxa;
178
- var errors = [];
179
- var id = 0;
180
- var newId = Math.max.apply(Math, oldIds);
181
- var lineNumber = offsetLine;
182
- var parents = [];
183
- var previous = { id: '', indent: 0, group: { isLeaf: false, indent: 0 } };
184
- for (var _i = 0, content_1 = content; _i < content_1.length; _i++) {
185
- var line = content_1[_i];
186
- var hasOriginalId = line.type !== diff_resource_1.ResourceDiffType.Added && !/^\s*(\[indet\]|> )/.test((_a = line.original) !== null && _a !== void 0 ? _a : line.text);
158
+ const leafTaxonIndex = resource.metadata.levels.reduce((last, rank, i) => MAIN_RANKS.includes(rank) ? i : last, 0);
159
+ const data = resource.taxa;
160
+ const errors = [];
161
+ let id = 0;
162
+ let newId = Math.max(...oldIds);
163
+ let lineNumber = offsetLine;
164
+ const parents = [];
165
+ const previous = { id: '', indent: 0, group: { isLeaf: false, indent: 0 }, errors: [] };
166
+ for (const line of content) {
167
+ const hasOriginalId = line.type !== diff_resource_1.ResourceDiffType.Added && !/^\s*(\[indet\]|> )/.test((_a = line.original) !== null && _a !== void 0 ? _a : line.text);
187
168
  if (hasOriginalId) {
188
169
  id++;
189
170
  }
@@ -193,25 +174,24 @@ function parseResourceContent(content, resource, oldIds, offsetLine) {
193
174
  else {
194
175
  lineNumber++;
195
176
  }
196
- var _c = line.text.match(/^(\s*)(.*)/).slice(1), indentation = _c[0], name_1 = _c[1];
197
- var lineIndent = indentation.length;
177
+ const [indentation, name] = line.text.match(/^(\s*)(.*)/).slice(1);
178
+ const lineIndent = indentation.length;
198
179
  // Validate line
199
180
  if (lineIndent % INDENT === 1) {
200
181
  errors.push(makeParseError('Too much or little indentation', lineNumber));
201
182
  continue;
202
183
  }
203
- else if (lineIndent / INDENT >= resource.metadata.levels.length && !/^[+=>] /.test(name_1)) {
184
+ else if (lineIndent / INDENT >= resource.metadata.levels.length && !/^[+=>] /.test(name)) {
204
185
  errors.push(makeParseError('Too much indentation', lineNumber));
205
186
  continue;
206
187
  }
207
188
  else if (lineIndent <= previous.group.indent && (data[previous.id] && !previous.group.isLeaf)) {
208
189
  errors.push(makeParseError('Missing leaf taxon', lineNumber - 1));
209
- continue;
210
190
  }
211
191
  // Update parentage
212
192
  if (lineIndent > previous.indent) {
213
193
  // Do not count synonyms as parents (unless this is correcting a typo in the synonym)
214
- if (data[previous.id] && data[previous.id].taxonomicStatus === 'accepted' || name_1.startsWith('> ')) {
194
+ if (data[previous.id] && data[previous.id].taxonomicStatus === 'accepted' || name.startsWith('> ')) {
215
195
  parents.push(previous.id);
216
196
  }
217
197
  else {
@@ -221,7 +201,7 @@ function parseResourceContent(content, resource, oldIds, offsetLine) {
221
201
  // e.g. if a certain genus has only species
222
202
  // whereas other genera in the same key also
223
203
  // have subgenera
224
- for (var i = previous.indent + INDENT; i < lineIndent; i += INDENT) {
204
+ for (let i = previous.indent + INDENT; i < lineIndent; i += INDENT) {
225
205
  parents.push(null);
226
206
  }
227
207
  }
@@ -231,32 +211,40 @@ function parseResourceContent(content, resource, oldIds, offsetLine) {
231
211
  previous.indent = lineIndent;
232
212
  // Do not process "indet" lines further, as they only serve to indicate
233
213
  // that subtaxa are explicitely omitted
234
- if (name_1.startsWith('[indet]')) {
214
+ if (name.startsWith('[indet]')) {
215
+ errors.push(...previous.errors);
216
+ previous.errors.length = 0;
235
217
  previous.group.isLeaf = lineIndent / INDENT >= leafTaxonIndex;
236
218
  continue;
237
219
  }
238
- var parentId = parents.reduce(function (grandparent, parent) { return parent !== null && parent !== void 0 ? parent : grandparent; }, null);
239
- var parent_1 = parentId === null ? {} : data[parentId];
240
- var rank = resource.metadata.levels[parents.length];
241
- var item = void 0;
220
+ const parentId = parents.reduce((grandparent, parent) => parent !== null && parent !== void 0 ? parent : grandparent, null);
221
+ const parent = parentId === null ? {} : data[parentId];
222
+ let item;
223
+ const itemErrors = [];
242
224
  try {
243
- item = (0, parse_name_1.parseName)(name_1, rank, parent_1);
225
+ const rank = resource.metadata.levels[parents.length];
226
+ item = (0, parse_name_1.parseName)(name, rank, parent);
244
227
  }
245
228
  catch (error) {
246
- errors.push(makeParseError(error.message, lineNumber));
247
- continue;
229
+ if (error instanceof parse_name_1.RecoverableSyntaxError) {
230
+ itemErrors.push(makeParseError(error.message, lineNumber));
231
+ item = error.result;
232
+ }
233
+ else {
234
+ errors.push(makeParseError(error.message, lineNumber));
235
+ continue;
236
+ }
248
237
  }
249
238
  // Add higher classification info
250
- var itemAsObject = item;
251
- var parentAsObject = parent_1;
252
- for (var _d = 0, DWC_RANKS_1 = DWC_RANKS; _d < DWC_RANKS_1.length; _d++) {
253
- var rank_1 = DWC_RANKS_1[_d];
254
- itemAsObject[rank_1] = undefined;
255
- if (parentAsObject[rank_1]) {
256
- itemAsObject[rank_1] = parentAsObject[rank_1];
239
+ const itemAsObject = item;
240
+ const parentAsObject = parent;
241
+ for (const rank of DWC_RANKS) {
242
+ itemAsObject[rank] = undefined;
243
+ if (parentAsObject[rank]) {
244
+ itemAsObject[rank] = parentAsObject[rank];
257
245
  }
258
- if (item.taxonRank === rank_1) {
259
- itemAsObject[rank_1] = item.scientificNameOnly;
246
+ if (item.taxonRank === rank) {
247
+ itemAsObject[rank] = item.scientificNameOnly;
260
248
  }
261
249
  }
262
250
  if (item.genericName && !item.genus) {
@@ -267,82 +255,99 @@ function parseResourceContent(content, resource, oldIds, offsetLine) {
267
255
  }
268
256
  // Amend "parent" with corrections, exit
269
257
  if (item.taxonomicStatus === 'incorrect') {
270
- parent_1.incorrect = __assign({}, parent_1);
271
- for (var key in item) {
258
+ if (parent.taxonomicStatus !== 'accepted') {
259
+ // Remove corrected synonym from parentage
260
+ parents[parents.length - 1] = null;
261
+ }
262
+ if (parent.incorrect) {
263
+ errors.push(makeParseError('Cannot apply a correction to a previous correction', lineNumber));
264
+ continue;
265
+ }
266
+ else if (parentId === null) {
267
+ errors.push(makeParseError('Cannot apply a correction to nothing', lineNumber));
268
+ continue;
269
+ }
270
+ parent.incorrect = Object.assign({}, parent);
271
+ for (const key in item) {
272
272
  if (key !== 'taxonomicStatus' && key !== 'verbatimIdentification') {
273
273
  parentAsObject[key] = itemAsObject[key];
274
274
  }
275
275
  }
276
+ // If "parent" is corrected, its errors can be dropped
277
+ previous.errors.length = 0;
278
+ // ...but errors associated with the corrected name are added immediately
279
+ errors.push(...itemErrors);
276
280
  continue;
277
281
  }
278
282
  // Add more classification info
279
- var isSynonym = item.taxonomicStatus !== 'accepted';
283
+ const isSynonym = item.taxonomicStatus !== 'accepted';
280
284
  if (isSynonym) {
281
- item.higherClassification = parent_1.higherClassification;
285
+ item.higherClassification = parent.higherClassification;
282
286
  }
283
- else if (parent_1.higherClassification) {
284
- item.higherClassification = parent_1.higherClassification + " | ".concat(parent_1.scientificNameOnly);
287
+ else if (parent.higherClassification) {
288
+ item.higherClassification = parent.higherClassification + ` | ${parent.scientificNameOnly}`;
285
289
  }
286
290
  else if (parentId) {
287
- item.higherClassification = parent_1.scientificNameOnly;
291
+ item.higherClassification = parent.scientificNameOnly;
288
292
  }
289
293
  // Set identifiers
290
- item.scientificNameID = "".concat(resource.id, ":").concat(hasOriginalId ? ((_b = oldIds[id - 1]) !== null && _b !== void 0 ? _b : id) : ++newId);
291
- item.parentNameUsageID = isSynonym ? undefined : parent_1.scientificNameID;
292
- item.parentNameUsage = isSynonym ? undefined : parent_1.scientificName;
293
- item.acceptedNameUsageID = isSynonym ? parent_1.scientificNameID : undefined;
294
- item.acceptedNameUsage = isSynonym ? parent_1.scientificName : undefined;
294
+ item.scientificNameID = `${resource.id}:${hasOriginalId ? ((_b = oldIds[id - 1]) !== null && _b !== void 0 ? _b : id) : ++newId}`;
295
+ item.parentNameUsageID = isSynonym ? undefined : parent.scientificNameID;
296
+ item.parentNameUsage = isSynonym ? undefined : parent.scientificName;
297
+ item.acceptedNameUsageID = isSynonym ? parent.scientificNameID : undefined;
298
+ item.acceptedNameUsage = isSynonym ? parent.scientificName : undefined;
295
299
  item.collectionCode = resource.id;
296
300
  data[item.scientificNameID] = item;
297
301
  // Update loop state
302
+ errors.push(...previous.errors);
303
+ previous.errors = itemErrors;
298
304
  previous.id = item.scientificNameID;
299
305
  if (item.taxonomicStatus === 'accepted') {
300
306
  previous.group.indent = previous.indent;
301
307
  previous.group.isLeaf = lineIndent / INDENT >= leafTaxonIndex;
302
308
  }
303
309
  }
310
+ errors.push(...previous.errors);
304
311
  if (errors.length) {
305
312
  throw mergeParserErrors(errors);
306
313
  }
307
314
  return resource;
308
315
  }
309
316
  function splitResources(file) {
310
- var resources = [];
311
- var offsetLine = 0;
312
- for (var _i = 0, _a = file.split(RESOURCE_DELIMITER); _i < _a.length; _i++) {
313
- var content = _a[_i];
314
- resources.push({ content: content, offsetLine: offsetLine });
317
+ const resources = [];
318
+ let offsetLine = 0;
319
+ for (const content of file.split(RESOURCE_DELIMITER)) {
320
+ resources.push({ content, offsetLine });
315
321
  offsetLine += (content + RESOURCE_DELIMITER).split('\n').length - 1;
316
322
  }
317
323
  return resources;
318
324
  }
319
325
  function parseFile(file, id, old) {
320
- var oldResources = old ? splitResources(old.txt) : [];
321
- var newResources = splitResources(file);
322
- var resources = [];
323
- var errors = [];
324
- for (var index = 0; index < newResources.length; index++) {
325
- var _a = parseResource(newResources[index]), config = _a[0], content = _a[1];
326
- var template = {
327
- id: "".concat(id, ":").concat(index + 1),
328
- file: "".concat(id, "-").concat(index + 1),
326
+ const oldResources = old ? splitResources(old.txt) : [];
327
+ const newResources = splitResources(file);
328
+ const resources = [];
329
+ const errors = [];
330
+ for (let index = 0; index < newResources.length; index++) {
331
+ const [config, content] = parseResource(newResources[index]);
332
+ const template = {
333
+ id: `${id}:${index + 1}`,
334
+ file: `${id}-${index + 1}`,
329
335
  workId: id,
330
336
  metadata: config,
331
337
  taxa: {}
332
338
  };
333
- var diff = void 0;
339
+ let diff;
334
340
  if (oldResources[index]) {
335
341
  diff = (0, diff_resource_1.createDiff)(content.content, parseResource(oldResources[index])[1].content);
336
342
  // Ignore empty lines
337
- diff = diff.filter(function (line) { return line.text !== ''; });
343
+ diff = diff.filter(line => line.text !== '');
338
344
  }
339
345
  else {
340
346
  diff = (0, diff_resource_1.createDiff)(content.content, content.content);
341
347
  }
342
- var oldIds = [];
348
+ const oldIds = [];
343
349
  if (old) {
344
- for (var _i = 0, _b = old.dwc[index].slice(1); _i < _b.length; _i++) {
345
- var row = _b[_i];
350
+ for (const row of old.dwc[index].slice(1)) {
346
351
  oldIds.push(parseInt(row[0].split(':')[2]));
347
352
  }
348
353
  }
@@ -359,5 +364,5 @@ function parseFile(file, id, old) {
359
364
  return resources;
360
365
  }
361
366
  function parseFileHeader(file) {
362
- return splitResources(file).map(function (resource) { return parseResource(resource)[0]; });
367
+ return splitResources(file).map(resource => parseResource(resource)[0]);
363
368
  }
@@ -1,30 +1,12 @@
1
1
  "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- if (typeof b !== "function" && b !== null)
11
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
- extendStatics(d, b);
13
- function __() { this.constructor = d; }
14
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
- };
16
- })();
17
2
  Object.defineProperty(exports, "__esModule", { value: true });
18
3
  exports.WorkResource = void 0;
19
- var work_1 = require("../catalog/tables/work");
20
- var WorkResource = /** @class */ (function (_super) {
21
- __extends(WorkResource, _super);
22
- function WorkResource(values) {
23
- var _this = _super.call(this, values) || this;
24
- _this.schema.version_of.format = /^B[1-9]\d*:[1-9]\d*$/;
25
- _this.schema.duplicate_of.format = /^B[1-9]\d*:[1-9]\d*$/;
26
- return _this;
4
+ const work_1 = require("../catalog/tables/work");
5
+ class WorkResource extends work_1.Work {
6
+ constructor(values) {
7
+ super(values);
8
+ this.schema.version_of.format = /^B[1-9]\d*:[1-9]\d*$/;
9
+ this.schema.duplicate_of.format = /^B[1-9]\d*:[1-9]\d*$/;
27
10
  }
28
- return WorkResource;
29
- }(work_1.Work));
11
+ }
30
12
  exports.WorkResource = WorkResource;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.groupNameMatches = groupNameMatches;
4
4
  exports.amendResource = amendResource;
5
- var MINIMUM_PREFIX_LENGTH = 3;
6
- var VALID_COMMON_PREFIXES = new Set([
5
+ const MINIMUM_PREFIX_LENGTH = 3;
6
+ const VALID_COMMON_PREFIXES = new Set([
7
7
  'Plantae|Tracheophyta',
8
8
  'Fungi',
9
9
  'Fungi|Ascomycota',
@@ -11,7 +11,7 @@ var VALID_COMMON_PREFIXES = new Set([
11
11
  'Fungi|Zygomycota'
12
12
  ]);
13
13
  function getCommonPrefix(a, b) {
14
- for (var i = 0; i < Math.max(a.length, b.length); i++) {
14
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
15
15
  if (a[i] !== b[i]) {
16
16
  return a.slice(0, i);
17
17
  }
@@ -19,17 +19,17 @@ function getCommonPrefix(a, b) {
19
19
  return a.slice();
20
20
  }
21
21
  function isValidPrefix(a, b) {
22
- var prefix = getCommonPrefix(a, b);
22
+ const prefix = getCommonPrefix(a, b);
23
23
  return VALID_COMMON_PREFIXES.has(prefix.join('|')) || prefix.length >= MINIMUM_PREFIX_LENGTH;
24
24
  }
25
25
  function groupNameMatches(results) {
26
- var prefixes = {};
27
- for (var scientificNameID in results) {
28
- var _loop_1 = function (result) {
26
+ const prefixes = {};
27
+ for (const scientificNameID in results) {
28
+ for (const result of results[scientificNameID]) {
29
29
  if (!prefixes[result.source]) {
30
30
  prefixes[result.source] = [];
31
31
  }
32
- var prefix = prefixes[result.source].find(function (prefix) { return isValidPrefix(prefix[0], result.classificationPath); });
32
+ let prefix = prefixes[result.source].find(prefix => isValidPrefix(prefix[0], result.classificationPath));
33
33
  if (!prefix) {
34
34
  prefix = [result.classificationPath, {}];
35
35
  prefixes[result.source].push(prefix);
@@ -38,21 +38,16 @@ function groupNameMatches(results) {
38
38
  prefix[0] = getCommonPrefix(prefix[0], result.classificationPath);
39
39
  }
40
40
  if (scientificNameID in prefix[1]) {
41
- return "continue";
41
+ continue;
42
42
  }
43
43
  prefix[1][scientificNameID] = result;
44
- };
45
- for (var _i = 0, _a = results[scientificNameID]; _i < _a.length; _i++) {
46
- var result = _a[_i];
47
- _loop_1(result);
48
44
  }
49
45
  }
50
- var groupedNameMatches = {};
51
- for (var source in prefixes) {
46
+ const groupedNameMatches = {};
47
+ for (const source in prefixes) {
52
48
  groupedNameMatches[source] = prefixes[source]
53
- .sort(function (a, b) { return Object.keys(b[1]).length - Object.keys(a[1]).length; })
54
- .reduce(function (map, _a) {
55
- var prefix = _a[0], taxa = _a[1];
49
+ .sort((a, b) => Object.keys(b[1]).length - Object.keys(a[1]).length)
50
+ .reduce((map, [prefix, taxa]) => {
56
51
  map[prefix.join('|')] = taxa;
57
52
  return map;
58
53
  }, {});
@@ -60,8 +55,8 @@ function groupNameMatches(results) {
60
55
  return groupedNameMatches;
61
56
  }
62
57
  function amendResource(resource, source, matches) {
63
- for (var id in matches) {
64
- var match = matches[id];
58
+ for (const id in matches) {
59
+ const match = matches[id];
65
60
  if (source === '1') {
66
61
  resource.taxa[id].colTaxonID = match.id;
67
62
  if (match.currentId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larsgw/formica",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
4
  "description": "SDK and tools for data from the Library of Identification Resources",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -189,34 +189,38 @@ function getWordTokensFromLines (lines: ResourceDiff): string[] {
189
189
  return lines.flatMap(change => tokenizeWords(change.text as string).concat('\n'))
190
190
  }
191
191
 
192
+ type MultilineDiffPart = { added: ResourceDiff, deleted: ResourceDiff }
193
+
194
+ function mergeDiffPart (diffPart: MultilineDiffPart): ResourceDiff {
195
+ if (diffPart.added.length && diffPart.deleted.length) {
196
+ return convertWordDiff(diffTokens(getWordTokensFromLines(diffPart.added), getWordTokensFromLines(diffPart.deleted)))
197
+ } else if (diffPart.added.length) {
198
+ return diffPart.added
199
+ } else if (diffPart.deleted.length) {
200
+ return diffPart.deleted.map(change => ({ text: undefined, original: change.text, type: change.type }))
201
+ } else {
202
+ return []
203
+ }
204
+ }
205
+
192
206
  export function createDiff (a: string, b: string): ResourceDiff {
193
207
  const lines: ResourceDiff = diffTokens(tokenizeLines(a.trimEnd()), tokenizeLines(b.trimEnd()))
194
208
 
195
209
  const changes: ResourceDiff = []
196
- const diffPart: Record<string, ResourceDiff> = { added: [], deleted: [] }
210
+ const diffPart: MultilineDiffPart = { added: [], deleted: [] }
197
211
  for (let i = 0; i < lines.length; i++) {
198
212
  if (lines[i].type === ResourceDiffType.Added) {
199
213
  diffPart.added.push(lines[i])
200
- continue
201
214
  } else if (lines[i].type === ResourceDiffType.Deleted) {
202
215
  diffPart.deleted.push(lines[i])
203
- continue
204
- }
205
-
206
- if (diffPart.added.length && diffPart.deleted.length) {
207
- changes.push(...convertWordDiff(diffTokens(getWordTokensFromLines(diffPart.added), getWordTokensFromLines(diffPart.deleted))))
208
- diffPart.added.length = 0
209
- diffPart.deleted.length = 0
210
- } else if (diffPart.added.length) {
211
- changes.push(...diffPart.added)
216
+ } else {
217
+ changes.push(...mergeDiffPart(diffPart), lines[i])
212
218
  diffPart.added.length = 0
213
- } else if (diffPart.deleted.length) {
214
- changes.push(...diffPart.deleted.map(change => ({ text: undefined, original: change.text, type: change.type })))
215
219
  diffPart.deleted.length = 0
216
220
  }
217
-
218
- changes.push(lines[i])
219
221
  }
220
222
 
223
+ changes.push(...mergeDiffPart(diffPart))
224
+
221
225
  return changes
222
226
  }