@larsgw/formica 0.1.0

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.
Files changed (65) hide show
  1. package/.eslintrc.js +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +19 -0
  4. package/lib/bin/process-resources-index.d.ts +1 -0
  5. package/lib/bin/process-resources-index.js +142 -0
  6. package/lib/bin/process-resources.d.ts +1 -0
  7. package/lib/bin/process-resources.js +594 -0
  8. package/lib/bin/util.d.ts +16 -0
  9. package/lib/bin/util.js +125 -0
  10. package/lib/bin/validate-catalog.d.ts +2 -0
  11. package/lib/bin/validate-catalog.js +92 -0
  12. package/lib/bin/validate-resources-text.d.ts +2 -0
  13. package/lib/bin/validate-resources-text.js +78 -0
  14. package/lib/catalog/entities.d.ts +12 -0
  15. package/lib/catalog/entities.js +111 -0
  16. package/lib/catalog/entity.d.ts +13 -0
  17. package/lib/catalog/entity.js +103 -0
  18. package/lib/catalog/index.d.ts +4 -0
  19. package/lib/catalog/index.js +33 -0
  20. package/lib/catalog/tables/author.d.ts +4 -0
  21. package/lib/catalog/tables/author.js +33 -0
  22. package/lib/catalog/tables/index.d.ts +2 -0
  23. package/lib/catalog/tables/index.js +13 -0
  24. package/lib/catalog/tables/place.d.ts +4 -0
  25. package/lib/catalog/tables/place.js +32 -0
  26. package/lib/catalog/tables/publisher.d.ts +4 -0
  27. package/lib/catalog/tables/publisher.js +33 -0
  28. package/lib/catalog/tables/work.d.ts +5 -0
  29. package/lib/catalog/tables/work.js +82 -0
  30. package/lib/catalog/value.d.ts +19 -0
  31. package/lib/catalog/value.js +49 -0
  32. package/lib/csv.d.ts +2 -0
  33. package/lib/csv.js +37 -0
  34. package/lib/index.d.ts +3 -0
  35. package/lib/index.js +6 -0
  36. package/lib/resources/diff-resource.d.ts +7 -0
  37. package/lib/resources/diff-resource.js +152 -0
  38. package/lib/resources/index.d.ts +1 -0
  39. package/lib/resources/index.js +6 -0
  40. package/lib/resources/parse-text.d.ts +2 -0
  41. package/lib/resources/parse-text.js +499 -0
  42. package/lib/types.d.ts +62 -0
  43. package/lib/types.js +0 -0
  44. package/package.json +42 -0
  45. package/src/bin/process-resources-index.ts +73 -0
  46. package/src/bin/process-resources.ts +406 -0
  47. package/src/bin/util.ts +74 -0
  48. package/src/bin/validate-catalog.ts +37 -0
  49. package/src/bin/validate-resources-text.ts +25 -0
  50. package/src/catalog/entities.ts +62 -0
  51. package/src/catalog/entity.ts +113 -0
  52. package/src/catalog/index.ts +32 -0
  53. package/src/catalog/tables/author.ts +13 -0
  54. package/src/catalog/tables/index.ts +12 -0
  55. package/src/catalog/tables/place.ts +12 -0
  56. package/src/catalog/tables/publisher.ts +13 -0
  57. package/src/catalog/tables/work.ts +62 -0
  58. package/src/catalog/value.ts +48 -0
  59. package/src/csv.ts +33 -0
  60. package/src/index.ts +3 -0
  61. package/src/module.d.ts +105 -0
  62. package/src/resources/diff-resource.ts +155 -0
  63. package/src/resources/index.ts +4 -0
  64. package/src/resources/parse-text.ts +519 -0
  65. package/tsconfig.json +11 -0
@@ -0,0 +1,594 @@
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
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ var fs_1 = require("fs");
51
+ var path = require("path");
52
+ var child_process_1 = require("child_process");
53
+ var util = require("util");
54
+ var index_1 = require("../index");
55
+ var util_1 = require("./util");
56
+ var DWC_FIELDS = [
57
+ 'scientificNameID',
58
+ 'scientificName',
59
+ 'scientificNameAuthorship',
60
+ 'genericName',
61
+ 'intragenericEpithet',
62
+ 'specificEpithet',
63
+ 'intraspecificEpithet',
64
+ 'taxonRank',
65
+ 'taxonRemarks',
66
+ 'collectionCode',
67
+ 'taxonomicStatus',
68
+ 'acceptedNameUsageID',
69
+ 'acceptedNameUsage',
70
+ 'parentNameUsageID',
71
+ 'parentNameUsage',
72
+ 'kingdom',
73
+ 'phylum',
74
+ 'class',
75
+ 'order',
76
+ 'family',
77
+ 'subfamily',
78
+ 'genus',
79
+ 'subgenus',
80
+ 'higherClassification',
81
+ 'colTaxonID',
82
+ 'gbifTaxonID'
83
+ ];
84
+ var DISPLAY_FIELDS = [
85
+ 'scientificNameID',
86
+ 'taxonRank',
87
+ 'scientificName',
88
+ 'taxonomicStatus',
89
+ 'taxonRemarks',
90
+ 'colTaxonID',
91
+ 'gbifTaxonID'
92
+ ];
93
+ var GBIF_RANKS = [
94
+ 'kingdom',
95
+ 'phyllum',
96
+ 'class',
97
+ 'order',
98
+ 'family',
99
+ 'genus',
100
+ 'species',
101
+ 'subspecies',
102
+ 'variety'
103
+ ];
104
+ var VALID_COMMON_PREFIXES = [
105
+ 'Plantae|Tracheophyta',
106
+ 'Fungi',
107
+ 'Fungi|Ascomycota',
108
+ 'Fungi|Basidiomycota',
109
+ 'Fungi|Zygomycota'
110
+ ];
111
+ function runGnverifier(names) {
112
+ return new Promise(function (resolve, reject) {
113
+ var proc = (0, child_process_1.spawn)('gnverifier', ['-s', '1,11', '-M']);
114
+ var stdout = '';
115
+ proc.stdout.on('data', function (data) { stdout += data; });
116
+ proc.stderr.pipe(process.stdout);
117
+ proc.on('close', function (code) {
118
+ if (code === 0) {
119
+ resolve(stdout);
120
+ }
121
+ else {
122
+ reject();
123
+ }
124
+ });
125
+ proc.stdin.write(names);
126
+ proc.stdin.end();
127
+ });
128
+ }
129
+ function listChangedFiles(directory) {
130
+ return __awaiter(this, void 0, void 0, function () {
131
+ var output;
132
+ return __generator(this, function (_a) {
133
+ switch (_a.label) {
134
+ case 0: return [4 /*yield*/, (0, util_1.runCommand)('git', ['diff', '--name-only', 'HEAD', '--', directory], {
135
+ cwd: directory
136
+ })];
137
+ case 1:
138
+ output = _a.sent();
139
+ return [2 /*return*/, output.trimEnd().split('\n').sort(util_1.numericSort)];
140
+ }
141
+ });
142
+ });
143
+ }
144
+ function getOldFile(file) {
145
+ return __awaiter(this, void 0, void 0, function () {
146
+ var options, gitRoot;
147
+ return __generator(this, function (_a) {
148
+ switch (_a.label) {
149
+ case 0:
150
+ options = {
151
+ cwd: path.dirname(file)
152
+ };
153
+ return [4 /*yield*/, (0, util_1.runCommand)('git', ['rev-parse', '--show-toplevel'], options)];
154
+ case 1:
155
+ gitRoot = (_a.sent()).trim();
156
+ return [4 /*yield*/, (0, util_1.runCommand)('git', ['show', 'HEAD:' + path.relative(gitRoot, file)], options)];
157
+ case 2: return [2 /*return*/, _a.sent()];
158
+ }
159
+ });
160
+ });
161
+ }
162
+ var ResourceProcessor = /** @class */ (function () {
163
+ function ResourceProcessor(collectionPath) {
164
+ this.DIR_ROOT = path.resolve(collectionPath);
165
+ this.DIR_TXT = path.join(this.DIR_ROOT, 'txt');
166
+ this.DIR_DWC = path.join(this.DIR_ROOT, 'dwc');
167
+ this.FILE_PROBLEMS = path.join(this.DIR_ROOT, 'problems.csv');
168
+ }
169
+ ResourceProcessor.prototype.run = function () {
170
+ return __awaiter(this, void 0, void 0, function () {
171
+ var input, output, ids, _loop_1, this_1, _i, ids_1, id;
172
+ return __generator(this, function (_a) {
173
+ switch (_a.label) {
174
+ case 0: return [4 /*yield*/, fs_1.promises.readdir(this.DIR_TXT)];
175
+ case 1:
176
+ input = _a.sent();
177
+ return [4 /*yield*/, fs_1.promises.readdir(this.DIR_DWC)];
178
+ case 2:
179
+ output = _a.sent();
180
+ ids = input
181
+ .map(function (file) { return path.basename(file, '.txt'); })
182
+ .sort(function (a, b) { return parseInt(a.slice(1)) - parseInt(b.slice(1)); });
183
+ _loop_1 = function (id) {
184
+ return __generator(this, function (_b) {
185
+ switch (_b.label) {
186
+ case 0:
187
+ // Skip existing files
188
+ if (output.some(function (file) { return file.startsWith(id + '-'); })) {
189
+ return [2 /*return*/, "continue"];
190
+ }
191
+ return [4 /*yield*/, this_1.processWork(id)];
192
+ case 1:
193
+ _b.sent();
194
+ return [2 /*return*/];
195
+ }
196
+ });
197
+ };
198
+ this_1 = this;
199
+ _i = 0, ids_1 = ids;
200
+ _a.label = 3;
201
+ case 3:
202
+ if (!(_i < ids_1.length)) return [3 /*break*/, 6];
203
+ id = ids_1[_i];
204
+ return [5 /*yield**/, _loop_1(id)];
205
+ case 4:
206
+ _a.sent();
207
+ _a.label = 5;
208
+ case 5:
209
+ _i++;
210
+ return [3 /*break*/, 3];
211
+ case 6: return [2 /*return*/];
212
+ }
213
+ });
214
+ });
215
+ };
216
+ ResourceProcessor.prototype.runUpdate = function () {
217
+ return __awaiter(this, void 0, void 0, function () {
218
+ var _i, _a, file, id;
219
+ return __generator(this, function (_b) {
220
+ switch (_b.label) {
221
+ case 0:
222
+ _i = 0;
223
+ return [4 /*yield*/, listChangedFiles(this.DIR_TXT)];
224
+ case 1:
225
+ _a = _b.sent();
226
+ _b.label = 2;
227
+ case 2:
228
+ if (!(_i < _a.length)) return [3 /*break*/, 5];
229
+ file = _a[_i];
230
+ id = path.basename(file, '.txt');
231
+ return [4 /*yield*/, this.processWork(id, true)];
232
+ case 3:
233
+ _b.sent();
234
+ _b.label = 4;
235
+ case 4:
236
+ _i++;
237
+ return [3 /*break*/, 2];
238
+ case 5: return [2 /*return*/];
239
+ }
240
+ });
241
+ });
242
+ };
243
+ ResourceProcessor.prototype.processWork = function (id, update) {
244
+ return __awaiter(this, void 0, void 0, function () {
245
+ var resources;
246
+ var _this = this;
247
+ return __generator(this, function (_a) {
248
+ switch (_a.label) {
249
+ case 0: return [4 /*yield*/, this.processResources(id, update)];
250
+ case 1:
251
+ resources = _a.sent();
252
+ return [4 /*yield*/, Promise.all(resources.map(function (resource) {
253
+ var header = DWC_FIELDS;
254
+ var table = [header];
255
+ var _loop_2 = function (id_1) {
256
+ var taxon = resource.taxa[id_1];
257
+ table.push(header.map(function (column) { return taxon[column] || ''; }));
258
+ };
259
+ for (var id_1 in resource.taxa) {
260
+ _loop_2(id_1);
261
+ }
262
+ return fs_1.promises.writeFile(path.join(_this.DIR_DWC, "".concat(resource.file, ".csv")), index_1.csv.formatCsv(table, ',').trim());
263
+ }))];
264
+ case 2:
265
+ _a.sent();
266
+ return [2 /*return*/];
267
+ }
268
+ });
269
+ });
270
+ };
271
+ ResourceProcessor.prototype.processResources = function (id, update) {
272
+ return __awaiter(this, void 0, void 0, function () {
273
+ var resources, amendedResources, _i, resources_1, resource, _a, results, classifications, _b, _c, _d, _e, source, skip, correct, choice, _f, reason;
274
+ return __generator(this, function (_g) {
275
+ switch (_g.label) {
276
+ case 0: return [4 /*yield*/, this.processResourceText(id, update)];
277
+ case 1:
278
+ resources = _g.sent();
279
+ amendedResources = [];
280
+ _i = 0, resources_1 = resources;
281
+ _g.label = 2;
282
+ case 2:
283
+ if (!(_i < resources_1.length)) return [3 /*break*/, 15];
284
+ resource = resources_1[_i];
285
+ return [4 /*yield*/, this.processResourceDwc(resource)];
286
+ case 3:
287
+ _a = _g.sent(), results = _a[0], classifications = _a[1];
288
+ _b = classifications;
289
+ _c = [];
290
+ for (_d in _b)
291
+ _c.push(_d);
292
+ _e = 0;
293
+ _g.label = 4;
294
+ case 4:
295
+ if (!(_e < _c.length)) return [3 /*break*/, 7];
296
+ _d = _c[_e];
297
+ if (!(_d in _b)) return [3 /*break*/, 6];
298
+ source = _d;
299
+ return [4 /*yield*/, this.checkPrefix(resource, classifications, source)];
300
+ case 5:
301
+ _g.sent();
302
+ _g.label = 6;
303
+ case 6:
304
+ _e++;
305
+ return [3 /*break*/, 4];
306
+ case 7: return [4 /*yield*/, this.shouldBeSkipped(resource.id)];
307
+ case 8:
308
+ skip = _g.sent();
309
+ if (!!skip) return [3 /*break*/, 13];
310
+ correct = this.checkResults(results);
311
+ if (!!correct) return [3 /*break*/, 13];
312
+ return [4 /*yield*/, (0, util_1.promptForAnswers)("".concat(resource.workId, ": problems found in ").concat(resource.id, ". Skip or retry (s/r)? "), ['s', 'S', 'r', 'R'])];
313
+ case 9:
314
+ choice = _g.sent();
315
+ _f = choice;
316
+ switch (_f) {
317
+ case 's': return [3 /*break*/, 10];
318
+ case 'S': return [3 /*break*/, 10];
319
+ case 'r': return [3 /*break*/, 12];
320
+ case 'R': return [3 /*break*/, 12];
321
+ }
322
+ return [3 /*break*/, 13];
323
+ case 10: return [4 /*yield*/, (0, util_1.prompt)('Reason for skipping? ')];
324
+ case 11:
325
+ reason = _g.sent();
326
+ fs_1.promises.appendFile(this.FILE_PROBLEMS, index_1.csv.formatCsv([[
327
+ resource.workId,
328
+ resource.id,
329
+ reason
330
+ ]]));
331
+ console.log("".concat(resource.workId, ": skipping ").concat(resource.id));
332
+ return [3 /*break*/, 13];
333
+ case 12:
334
+ {
335
+ console.log("".concat(resource.workId, ": retrying ").concat(resource.id));
336
+ return [2 /*return*/, this.processResources(id, update)];
337
+ }
338
+ _g.label = 13;
339
+ case 13:
340
+ amendedResources.push(results);
341
+ _g.label = 14;
342
+ case 14:
343
+ _i++;
344
+ return [3 /*break*/, 2];
345
+ case 15: return [2 /*return*/, amendedResources];
346
+ }
347
+ });
348
+ });
349
+ };
350
+ ResourceProcessor.prototype.processResourceText = function (id, update) {
351
+ return __awaiter(this, void 0, void 0, function () {
352
+ var filePath, file, old, dwc, _i, _a, file_1, filePath_1, _b, _c, _d, _e, resources, error_1, prefix, file;
353
+ var _f;
354
+ return __generator(this, function (_g) {
355
+ switch (_g.label) {
356
+ case 0:
357
+ _g.trys.push([0, 10, , 12]);
358
+ console.log("".concat(id, ": generating Darwin Core"));
359
+ filePath = path.join(this.DIR_TXT, id + '.txt');
360
+ return [4 /*yield*/, fs_1.promises.readFile(filePath, 'utf-8')];
361
+ case 1:
362
+ file = _g.sent();
363
+ old = undefined;
364
+ if (!update) return [3 /*break*/, 8];
365
+ dwc = [];
366
+ _i = 0;
367
+ return [4 /*yield*/, fs_1.promises.readdir(this.DIR_DWC)];
368
+ case 2:
369
+ _a = _g.sent();
370
+ _g.label = 3;
371
+ case 3:
372
+ if (!(_i < _a.length)) return [3 /*break*/, 6];
373
+ file_1 = _a[_i];
374
+ if (!file_1.startsWith(id + '-')) return [3 /*break*/, 5];
375
+ filePath_1 = path.join(this.DIR_DWC, file_1);
376
+ _c = (_b = dwc).push;
377
+ _e = (_d = index_1.csv).parseCsv;
378
+ return [4 /*yield*/, getOldFile(filePath_1)];
379
+ case 4:
380
+ _c.apply(_b, [_e.apply(_d, [_g.sent()])]);
381
+ _g.label = 5;
382
+ case 5:
383
+ _i++;
384
+ return [3 /*break*/, 3];
385
+ case 6:
386
+ _f = {};
387
+ return [4 /*yield*/, getOldFile(filePath)];
388
+ case 7:
389
+ old = (_f.txt = _g.sent(), _f.dwc = dwc, _f);
390
+ _g.label = 8;
391
+ case 8: return [4 /*yield*/, Promise.resolve().then(function () { return require('../index'); })];
392
+ case 9:
393
+ resources = (_g.sent()).resources;
394
+ return [2 /*return*/, resources.parseTextFile(file, id, old)];
395
+ case 10:
396
+ error_1 = _g.sent();
397
+ console.log(error_1);
398
+ return [4 /*yield*/, (0, util_1.prompt)("".concat(id, ": generating Darwin Core failed, retry? "))
399
+ // Clear cache to re-import
400
+ ];
401
+ case 11:
402
+ _g.sent();
403
+ prefix = path.dirname(require.resolve('../index'));
404
+ for (file in require.cache) {
405
+ if (file.startsWith(prefix)) {
406
+ delete require.cache[file];
407
+ }
408
+ }
409
+ return [2 /*return*/, this.processResourceText(id, update)];
410
+ case 12: return [2 /*return*/];
411
+ }
412
+ });
413
+ });
414
+ };
415
+ ResourceProcessor.prototype.processResourceDwc = function (resource) {
416
+ return __awaiter(this, void 0, void 0, function () {
417
+ var taxa, names, id, name_1, result, classifications, _a, header, matches, _i, matches_1, match, name_2, source, id, classification, loirId, taxon, results;
418
+ return __generator(this, function (_b) {
419
+ switch (_b.label) {
420
+ case 0:
421
+ console.log("".concat(resource.workId, ": matching ").concat(resource.id));
422
+ taxa = {};
423
+ names = [];
424
+ for (id in resource.taxa) {
425
+ name_1 = resource.taxa[id].scientificName;
426
+ if (!taxa[name_1]) {
427
+ taxa[name_1] = {};
428
+ }
429
+ taxa[name_1][id] = __assign({}, resource.taxa[id]);
430
+ names.push(name_1);
431
+ }
432
+ return [4 /*yield*/, runGnverifier(names.join('\n'))];
433
+ case 1:
434
+ result = _b.sent();
435
+ classifications = { '1': [], '11': [] };
436
+ _a = index_1.csv.parseCsv(result), header = _a[0], matches = _a.slice(1);
437
+ for (_i = 0, matches_1 = matches; _i < matches_1.length; _i++) {
438
+ match = matches_1[_i];
439
+ name_2 = match[header.indexOf('ScientificName')];
440
+ source = match[header.indexOf('DataSourceId')];
441
+ id = match[header.indexOf('TaxonId')];
442
+ classification = match[header.indexOf('ClassificationPath')];
443
+ for (loirId in taxa[name_2]) {
444
+ taxon = taxa[name_2][loirId];
445
+ if (source === '1' && !taxon.colTaxonID) {
446
+ taxon.colTaxonID = id;
447
+ classifications[source].push([taxon, classification]);
448
+ }
449
+ if (source === '11' && GBIF_RANKS.includes(taxon.taxonRank) && !taxon.gbifTaxonID) {
450
+ taxon.gbifTaxonID = id;
451
+ classifications[source].push([taxon, classification]);
452
+ }
453
+ }
454
+ }
455
+ results = __assign(__assign({}, resource), { taxa: Object.fromEntries(Object.values(resource.taxa).map(function (taxon) { return [
456
+ taxon.scientificNameID,
457
+ taxa[taxon.scientificName][taxon.scientificNameID]
458
+ ]; })) });
459
+ return [2 /*return*/, [results, classifications]];
460
+ }
461
+ });
462
+ });
463
+ };
464
+ ResourceProcessor.prototype.checkPrefix = function (resource, classifications, source) {
465
+ return __awaiter(this, void 0, void 0, function () {
466
+ var lists, prefix, _i, _a, _b, taxon, list, parts, i, choice;
467
+ return __generator(this, function (_c) {
468
+ switch (_c.label) {
469
+ case 0:
470
+ lists = classifications[source];
471
+ if (!lists.length) {
472
+ return [2 /*return*/];
473
+ }
474
+ prefix = lists[0][1].split('|');
475
+ _i = 0, _a = lists.slice(1);
476
+ _c.label = 1;
477
+ case 1:
478
+ if (!(_i < _a.length)) return [3 /*break*/, 9];
479
+ _b = _a[_i], taxon = _b[0], list = _b[1];
480
+ parts = list.split('|');
481
+ i = 0;
482
+ _c.label = 2;
483
+ case 2:
484
+ if (!(i < parts.length)) return [3 /*break*/, 8];
485
+ if (!(parts[i] !== prefix[i] && i < 3)) return [3 /*break*/, 7];
486
+ choice = void 0;
487
+ if (!(source === '1' || taxon.taxonomicStatus !== 'accepted')) return [3 /*break*/, 3];
488
+ choice = 'd';
489
+ return [3 /*break*/, 6];
490
+ case 3:
491
+ if (!VALID_COMMON_PREFIXES.includes(prefix.slice(0, i).join('|'))) return [3 /*break*/, 4];
492
+ choice = 'k';
493
+ return [3 /*break*/, 6];
494
+ case 4:
495
+ console.log("".concat(resource.workId, ": source ").concat(source, " results in short prefix \"").concat(prefix.slice(0, i).join('|'), "\" (").concat(i, " taxa)"));
496
+ console.log(" taxon: ".concat(taxon.scientificNameID, " \"").concat(taxon.scientificName, "\""));
497
+ console.log(" class: ".concat(parts.join('|')));
498
+ console.log(" prefx: ".concat(prefix.join('|')));
499
+ return [4 /*yield*/, (0, util_1.promptForAnswers)(" Keep or delete (k/d)? ", ['k', 'K', 'd', 'D'])];
500
+ case 5:
501
+ choice = _c.sent();
502
+ _c.label = 6;
503
+ case 6:
504
+ switch (choice) {
505
+ case 'k':
506
+ case 'K': {
507
+ console.log(" keeping...");
508
+ break;
509
+ }
510
+ case 'd':
511
+ case 'D': {
512
+ console.log(" deleting...");
513
+ if (source === '1') {
514
+ delete taxon.colTaxonID;
515
+ }
516
+ else if (source === '11') {
517
+ delete taxon.gbifTaxonID;
518
+ }
519
+ break;
520
+ }
521
+ }
522
+ return [3 /*break*/, 8];
523
+ case 7:
524
+ i++;
525
+ return [3 /*break*/, 2];
526
+ case 8:
527
+ _i++;
528
+ return [3 /*break*/, 1];
529
+ case 9: return [2 /*return*/];
530
+ }
531
+ });
532
+ });
533
+ };
534
+ ResourceProcessor.prototype.checkResults = function (resource) {
535
+ var correct = true;
536
+ var missing = [];
537
+ for (var id in resource.taxa) {
538
+ var taxon = resource.taxa[id];
539
+ if (taxon.taxonomicStatus !== 'accepted') {
540
+ continue;
541
+ }
542
+ var missingCol = false; // !taxon.colTaxonID
543
+ var missingGbif = GBIF_RANKS.includes(taxon.taxonRank) && !taxon.gbifTaxonID;
544
+ if (missingCol || missingGbif) {
545
+ correct = false;
546
+ missing.push(taxon);
547
+ }
548
+ }
549
+ if (missing.length) {
550
+ console.table(missing, DISPLAY_FIELDS);
551
+ }
552
+ return correct;
553
+ };
554
+ ResourceProcessor.prototype.shouldBeSkipped = function (id) {
555
+ return __awaiter(this, void 0, void 0, function () {
556
+ var problems, _a, _b;
557
+ return __generator(this, function (_c) {
558
+ switch (_c.label) {
559
+ case 0:
560
+ _b = (_a = index_1.csv).parseCsv;
561
+ return [4 /*yield*/, fs_1.promises.readFile(this.FILE_PROBLEMS, 'utf8')];
562
+ case 1:
563
+ problems = _b.apply(_a, [_c.sent()]);
564
+ return [2 /*return*/, problems.some(function (_a) {
565
+ var _work = _a[0], resource = _a[1], _problem = _a[2];
566
+ return resource === id;
567
+ })];
568
+ }
569
+ });
570
+ });
571
+ };
572
+ return ResourceProcessor;
573
+ }());
574
+ function main() {
575
+ var args = util.parseArgs({
576
+ options: {
577
+ update: {
578
+ type: 'boolean',
579
+ short: 'u'
580
+ }
581
+ },
582
+ allowPositionals: true
583
+ });
584
+ var processor = new ResourceProcessor(args.positionals[0]);
585
+ process.on('exit', function () {
586
+ process.stdout.write('\n');
587
+ });
588
+ var task = args.values.update ? processor.runUpdate() : processor.run();
589
+ task.catch(function (error) {
590
+ console.error(error);
591
+ process.exit(1);
592
+ });
593
+ }
594
+ main();
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Comparison function to sort strings with numerical components.
3
+ */
4
+ export declare function numericSort(a: string, b: string): number;
5
+ /**
6
+ * Create a CLI prompt and return any answer.
7
+ */
8
+ export declare function prompt(question: string): Promise<string>;
9
+ /**
10
+ * Create a CLI prompt and only accept certain answers.
11
+ */
12
+ export declare function promptForAnswers(question: string, answers: string[]): Promise<string>;
13
+ /**
14
+ * Run a command and return stdout.
15
+ */
16
+ export declare function runCommand(command: string, args: string[], options?: Record<string, unknown>): Promise<string>;