@larsgw/formica 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ *.ts linguist-language=TypeScript
@@ -0,0 +1,27 @@
1
+ name: Node.js CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ "main" ]
6
+ pull_request:
7
+ branches: [ "main" ]
8
+
9
+ jobs:
10
+ build:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ node-version: [18.x, 20.x]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v3
20
+ - name: Use Node.js ${{ matrix.node-version }}
21
+ uses: actions/setup-node@v3
22
+ with:
23
+ node-version: ${{ matrix.node-version }}
24
+ - run: npm install
25
+ - run: npm run build
26
+ - run: npm run lint
27
+ - run: npm test
package/CHANGELOG.md CHANGED
@@ -1,3 +1,44 @@
1
+ ## [0.5.1](https://github.com/identification-resources/formica/compare/v0.5.0...v0.5.1) (2023-11-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **resources:** fix file listing in processor ([009b980](https://github.com/identification-resources/formica/commit/009b98091b0f597e91213ace82252facbe3b5fed))
7
+
8
+
9
+
10
+ # [0.5.0](https://github.com/identification-resources/formica/compare/v0.4.3...v0.5.0) (2023-10-24)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **catalog:** make validation more robust ([522db8a](https://github.com/identification-resources/formica/commit/522db8ad428c2d4645569a7f541fd203f5d628e8))
16
+ * **csv:** fix csv formatting ([064e5e5](https://github.com/identification-resources/formica/commit/064e5e57b2a642d22850501ab2a0b95879779b85))
17
+ * **resources:** do not count abbreviations as species ([ac0cc5a](https://github.com/identification-resources/formica/commit/ac0cc5a7cfd1f68df9b8d1d1c543a2f593839daa))
18
+ * **resources:** fix typos in output column names ([0d02823](https://github.com/identification-resources/formica/commit/0d0282378b21e92fbe028a53a9d121f42e791cc5))
19
+
20
+
21
+ ### Features
22
+
23
+ * **resources:** encode names with spaces with underscores ([9c7efd4](https://github.com/identification-resources/formica/commit/9c7efd4daf80660be98f2fec8ef9faa5d5b42d67))
24
+ * **resources:** include verbatimIdentification column ([4a2e920](https://github.com/identification-resources/formica/commit/4a2e9201467347e900f5690d2301a3b231ded822))
25
+ * **resources:** move "scope" metadata to "catalog" ([286c5b2](https://github.com/identification-resources/formica/commit/286c5b223ce41336f3ebd63c1797403aad21aef6))
26
+ * **resources:** update processor configuration ([64daa26](https://github.com/identification-resources/formica/commit/64daa26d70c96df24298c7b78f2b93ef0f5b2a48))
27
+
28
+
29
+ ### BREAKING CHANGES
30
+
31
+ * **resources:** - "intragenericEpithet" is now "infragenericEpithet"
32
+ - "intraspecificEpithet" is now "infraspecificEpithet"
33
+ * **resources:** Adds additional column, between "higherClassification" and "colTaxonID".
34
+ * **resources:** - Instead of "-u, --update" use "-s modified"
35
+ - Instead of "--update-mapping" use "-s all"
36
+ * **resources:** Index will no longer contain "scope" array. "scope" field in YAML header
37
+ does no longer pass validation. Use the "taxon_scope" and "scope" fields
38
+ in "catalog" instead.
39
+
40
+
41
+
1
42
  ## [0.4.3](https://github.com/identification-resources/formica/compare/v0.4.2...v0.4.3) (2023-09-30)
2
43
 
3
44
 
@@ -1,2 +1,6 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ export declare enum ResourceProcessorSource {
3
+ All = "all",
4
+ Unprocessed = "unprocessed",
5
+ Modified = "modified"
6
+ }
@@ -48,20 +48,27 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
48
48
  }
49
49
  };
50
50
  Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.ResourceProcessorSource = void 0;
51
52
  var fs_1 = require("fs");
52
53
  var path = require("path");
53
54
  var child_process_1 = require("child_process");
54
55
  var util = require("util");
55
56
  var index_1 = require("../index");
56
57
  var util_1 = require("./util");
58
+ var ResourceProcessorSource;
59
+ (function (ResourceProcessorSource) {
60
+ ResourceProcessorSource["All"] = "all";
61
+ ResourceProcessorSource["Unprocessed"] = "unprocessed";
62
+ ResourceProcessorSource["Modified"] = "modified";
63
+ })(ResourceProcessorSource = exports.ResourceProcessorSource || (exports.ResourceProcessorSource = {}));
57
64
  var DWC_FIELDS = [
58
65
  'scientificNameID',
59
66
  'scientificName',
60
67
  'scientificNameAuthorship',
61
68
  'genericName',
62
- 'intragenericEpithet',
69
+ 'infragenericEpithet',
63
70
  'specificEpithet',
64
- 'intraspecificEpithet',
71
+ 'infraspecificEpithet',
65
72
  'taxonRank',
66
73
  'taxonRemarks',
67
74
  'collectionCode',
@@ -79,6 +86,7 @@ var DWC_FIELDS = [
79
86
  'genus',
80
87
  'subgenus',
81
88
  'higherClassification',
89
+ 'verbatimIdentification',
82
90
  'colTaxonID',
83
91
  'gbifTaxonID',
84
92
  'colAcceptedTaxonID',
@@ -122,6 +130,36 @@ function runGnverifier(names) {
122
130
  proc.stdin.end();
123
131
  });
124
132
  }
133
+ function listFiles(directory) {
134
+ return __awaiter(this, void 0, void 0, function () {
135
+ var input;
136
+ return __generator(this, function (_a) {
137
+ switch (_a.label) {
138
+ case 0: return [4 /*yield*/, fs_1.promises.readdir(directory)];
139
+ case 1:
140
+ input = _a.sent();
141
+ return [2 /*return*/, input.map(function (file) { return path.basename(file, '.txt'); }).sort(util_1.numericSort)];
142
+ }
143
+ });
144
+ });
145
+ }
146
+ function listUnprocessedFiles(directory, outputDirectory) {
147
+ return __awaiter(this, void 0, void 0, function () {
148
+ var input, output, _a;
149
+ return __generator(this, function (_b) {
150
+ switch (_b.label) {
151
+ case 0: return [4 /*yield*/, listFiles(directory)];
152
+ case 1:
153
+ input = _b.sent();
154
+ _a = Set.bind;
155
+ return [4 /*yield*/, fs_1.promises.readdir(outputDirectory)];
156
+ case 2:
157
+ output = new (_a.apply(Set, [void 0, _b.sent()]))();
158
+ return [2 /*return*/, input.filter(function (file) { return !output.has(file + '-1.csv'); })];
159
+ }
160
+ });
161
+ });
162
+ }
125
163
  function listChangedFiles(directory) {
126
164
  return __awaiter(this, void 0, void 0, function () {
127
165
  var output;
@@ -132,7 +170,7 @@ function listChangedFiles(directory) {
132
170
  })];
133
171
  case 1:
134
172
  output = _a.sent();
135
- return [2 /*return*/, output.trimEnd().split('\n').sort(util_1.numericSort)];
173
+ return [2 /*return*/, output.trimEnd().split('\n').map(function (file) { return path.basename(file, '.txt'); }).sort(util_1.numericSort)];
136
174
  }
137
175
  });
138
176
  });
@@ -162,72 +200,23 @@ var ResourceProcessor = /** @class */ (function () {
162
200
  this.DIR_DWC = path.join(this.DIR_ROOT, 'dwc');
163
201
  this.FILE_PROBLEMS = path.join(this.DIR_ROOT, 'problems.csv');
164
202
  }
165
- ResourceProcessor.prototype.run = function () {
203
+ ResourceProcessor.prototype.run = function (source, config) {
166
204
  return __awaiter(this, void 0, void 0, function () {
167
- var input, output, ids, _loop_1, this_1, _i, ids_1, id;
205
+ var ids, _i, ids_1, id;
168
206
  return __generator(this, function (_a) {
169
207
  switch (_a.label) {
170
- case 0: return [4 /*yield*/, fs_1.promises.readdir(this.DIR_TXT)];
208
+ case 0: return [4 /*yield*/, this.listWorks(source)];
171
209
  case 1:
172
- input = _a.sent();
173
- return [4 /*yield*/, fs_1.promises.readdir(this.DIR_DWC)];
174
- case 2:
175
- output = _a.sent();
176
- ids = input
177
- .map(function (file) { return path.basename(file, '.txt'); })
178
- .sort(function (a, b) { return parseInt(a.slice(1)) - parseInt(b.slice(1)); });
179
- _loop_1 = function (id) {
180
- return __generator(this, function (_b) {
181
- switch (_b.label) {
182
- case 0:
183
- // Skip existing files
184
- if (output.some(function (file) { return file.startsWith(id + '-'); })) {
185
- return [2 /*return*/, "continue"];
186
- }
187
- return [4 /*yield*/, this_1.processWork(id)];
188
- case 1:
189
- _b.sent();
190
- return [2 /*return*/];
191
- }
192
- });
193
- };
194
- this_1 = this;
210
+ ids = _a.sent();
195
211
  _i = 0, ids_1 = ids;
196
- _a.label = 3;
197
- case 3:
198
- if (!(_i < ids_1.length)) return [3 /*break*/, 6];
199
- id = ids_1[_i];
200
- return [5 /*yield**/, _loop_1(id)];
201
- case 4:
202
- _a.sent();
203
- _a.label = 5;
204
- case 5:
205
- _i++;
206
- return [3 /*break*/, 3];
207
- case 6: return [2 /*return*/];
208
- }
209
- });
210
- });
211
- };
212
- ResourceProcessor.prototype.runUpdate = function () {
213
- return __awaiter(this, void 0, void 0, function () {
214
- var _i, _a, file, id;
215
- return __generator(this, function (_b) {
216
- switch (_b.label) {
217
- case 0:
218
- _i = 0;
219
- return [4 /*yield*/, listChangedFiles(this.DIR_TXT)];
220
- case 1:
221
- _a = _b.sent();
222
- _b.label = 2;
212
+ _a.label = 2;
223
213
  case 2:
224
- if (!(_i < _a.length)) return [3 /*break*/, 5];
225
- file = _a[_i];
226
- id = path.basename(file, '.txt');
227
- return [4 /*yield*/, this.processWork(id, true)];
214
+ if (!(_i < ids_1.length)) return [3 /*break*/, 5];
215
+ id = ids_1[_i];
216
+ return [4 /*yield*/, this.processWork(id, config)];
228
217
  case 3:
229
- _b.sent();
230
- _b.label = 4;
218
+ _a.sent();
219
+ _a.label = 4;
231
220
  case 4:
232
221
  _i++;
233
222
  return [3 /*break*/, 2];
@@ -236,52 +225,41 @@ var ResourceProcessor = /** @class */ (function () {
236
225
  });
237
226
  });
238
227
  };
239
- ResourceProcessor.prototype.runMappingsUpdate = function () {
228
+ ResourceProcessor.prototype.listWorks = function (source) {
240
229
  return __awaiter(this, void 0, void 0, function () {
241
- var input, ids, _i, ids_2, id;
242
230
  return __generator(this, function (_a) {
243
- switch (_a.label) {
244
- case 0: return [4 /*yield*/, fs_1.promises.readdir(this.DIR_TXT)];
245
- case 1:
246
- input = _a.sent();
247
- ids = input
248
- .map(function (file) { return path.basename(file, '.txt'); })
249
- .sort(function (a, b) { return parseInt(a.slice(1)) - parseInt(b.slice(1)); });
250
- _i = 0, ids_2 = ids;
251
- _a.label = 2;
252
- case 2:
253
- if (!(_i < ids_2.length)) return [3 /*break*/, 5];
254
- id = ids_2[_i];
255
- return [4 /*yield*/, this.processWork(id, true)];
256
- case 3:
257
- _a.sent();
258
- _a.label = 4;
259
- case 4:
260
- _i++;
261
- return [3 /*break*/, 2];
262
- case 5: return [2 /*return*/];
231
+ switch (source) {
232
+ case ResourceProcessorSource.All:
233
+ return [2 /*return*/, listFiles(this.DIR_TXT)];
234
+ case ResourceProcessorSource.Unprocessed:
235
+ return [2 /*return*/, listUnprocessedFiles(this.DIR_TXT, this.DIR_DWC)];
236
+ case ResourceProcessorSource.Modified:
237
+ return [2 /*return*/, listChangedFiles(this.DIR_TXT)];
238
+ default:
239
+ return [2 /*return*/, []];
263
240
  }
241
+ return [2 /*return*/];
264
242
  });
265
243
  });
266
244
  };
267
- ResourceProcessor.prototype.processWork = function (id, update) {
245
+ ResourceProcessor.prototype.processWork = function (id, config) {
268
246
  return __awaiter(this, void 0, void 0, function () {
269
247
  var resources;
270
248
  var _this = this;
271
249
  return __generator(this, function (_a) {
272
250
  switch (_a.label) {
273
- case 0: return [4 /*yield*/, this.processResources(id, update)];
251
+ case 0: return [4 /*yield*/, this.processResources(id, config)];
274
252
  case 1:
275
253
  resources = _a.sent();
276
254
  return [4 /*yield*/, Promise.all(resources.map(function (resource) {
277
255
  var header = DWC_FIELDS;
278
256
  var table = [header];
279
- var _loop_2 = function (id_1) {
257
+ var _loop_1 = function (id_1) {
280
258
  var taxon = resource.taxa[id_1];
281
259
  table.push(header.map(function (column) { return taxon[column] || ''; }));
282
260
  };
283
261
  for (var id_1 in resource.taxa) {
284
- _loop_2(id_1);
262
+ _loop_1(id_1);
285
263
  }
286
264
  return fs_1.promises.writeFile(path.join(_this.DIR_DWC, "".concat(resource.file, ".csv")), index_1.csv.formatCsv(table, ',').trim());
287
265
  }))];
@@ -292,12 +270,12 @@ var ResourceProcessor = /** @class */ (function () {
292
270
  });
293
271
  });
294
272
  };
295
- ResourceProcessor.prototype.processResources = function (id, update) {
273
+ ResourceProcessor.prototype.processResources = function (id, config) {
296
274
  return __awaiter(this, void 0, void 0, function () {
297
275
  var resources, amendedResources, _i, resources_1, resource, results, skip, correct, choice, _a, reason;
298
276
  return __generator(this, function (_b) {
299
277
  switch (_b.label) {
300
- case 0: return [4 /*yield*/, this.processResourceText(id, update)];
278
+ case 0: return [4 /*yield*/, this.processResourceText(id, config)];
301
279
  case 1:
302
280
  resources = _b.sent();
303
281
  amendedResources = [];
@@ -306,7 +284,7 @@ var ResourceProcessor = /** @class */ (function () {
306
284
  case 2:
307
285
  if (!(_i < resources_1.length)) return [3 /*break*/, 11];
308
286
  resource = resources_1[_i];
309
- return [4 /*yield*/, this.processResourceDwc(resource)];
287
+ return [4 /*yield*/, this.processResourceDwc(resource, config)];
310
288
  case 3:
311
289
  results = _b.sent();
312
290
  return [4 /*yield*/, this.shouldBeSkipped(resource.id)];
@@ -339,7 +317,7 @@ var ResourceProcessor = /** @class */ (function () {
339
317
  case 8:
340
318
  {
341
319
  console.log("".concat(resource.workId, ": retrying ").concat(resource.id));
342
- return [2 /*return*/, this.processResources(id, update)];
320
+ return [2 /*return*/, this.processResources(id, config)];
343
321
  }
344
322
  _b.label = 9;
345
323
  case 9:
@@ -353,7 +331,7 @@ var ResourceProcessor = /** @class */ (function () {
353
331
  });
354
332
  });
355
333
  };
356
- ResourceProcessor.prototype.processResourceText = function (id, update) {
334
+ ResourceProcessor.prototype.processResourceText = function (id, config) {
357
335
  return __awaiter(this, void 0, void 0, function () {
358
336
  var filePath, file, old, dwc, _i, _a, file_1, filePath_1, _b, _c, _d, _e, resources, error_1, prefix, file;
359
337
  var _f;
@@ -367,7 +345,7 @@ var ResourceProcessor = /** @class */ (function () {
367
345
  case 1:
368
346
  file = _g.sent();
369
347
  old = undefined;
370
- if (!update) return [3 /*break*/, 8];
348
+ if (!config.update) return [3 /*break*/, 8];
371
349
  dwc = [];
372
350
  _i = 0;
373
351
  return [4 /*yield*/, fs_1.promises.readdir(this.DIR_DWC)];
@@ -412,19 +390,43 @@ var ResourceProcessor = /** @class */ (function () {
412
390
  delete require.cache[file];
413
391
  }
414
392
  }
415
- return [2 /*return*/, this.processResourceText(id, update)];
393
+ return [2 /*return*/, this.processResourceText(id, config)];
416
394
  case 12: return [2 /*return*/];
417
395
  }
418
396
  });
419
397
  });
420
398
  };
421
- ResourceProcessor.prototype.processResourceDwc = function (resource) {
399
+ ResourceProcessor.prototype.processResourceDwc = function (resource, config) {
422
400
  return __awaiter(this, void 0, void 0, function () {
423
- var filteredResults, taxonNames, names, id, name_1, result, _i, _a, results, _b, name_2, matches, _c, matches_1, match, source, currentRank, _d, _e, loirId, taxon, _f, amendResource, groupNameMatches, groupedNameMatches, amendedResource, _g, _h, _j, _k, source, matches;
424
- return __generator(this, function (_l) {
425
- switch (_l.label) {
401
+ var file, _a, header_1, rows, _b, _c, _i, rows_1, row, oldTaxon, taxon, filteredResults, taxonNames, names, id, name_1, result, _d, _e, results, _f, name_2, matches, _g, matches_1, match, source, currentRank, _h, _j, loirId, taxon, _k, amendResource, groupNameMatches, groupedNameMatches, amendedResource, _l, _m, _o, _p, source, matches;
402
+ return __generator(this, function (_q) {
403
+ switch (_q.label) {
426
404
  case 0:
427
405
  console.log("".concat(resource.workId, ": matching ").concat(resource.id));
406
+ if (!!config.updateMappings) return [3 /*break*/, 3];
407
+ file = path.join(this.DIR_DWC, resource.file + '.csv');
408
+ if (!(0, fs_1.existsSync)(file)) return [3 /*break*/, 2];
409
+ _c = (_b = index_1.csv).parseCsv;
410
+ return [4 /*yield*/, fs_1.promises.readFile(file, 'utf-8')];
411
+ case 1:
412
+ _a = _c.apply(_b, [_q.sent()]), header_1 = _a[0], rows = _a.slice(1);
413
+ for (_i = 0, rows_1 = rows; _i < rows_1.length; _i++) {
414
+ row = rows_1[_i];
415
+ oldTaxon = row.reduce(function (taxon, value, index) {
416
+ taxon[header_1[index]] = value;
417
+ return taxon;
418
+ }, {});
419
+ taxon = resource.taxa[oldTaxon.scientificNameID];
420
+ if (taxon) {
421
+ taxon.colTaxonID = oldTaxon.colTaxonID;
422
+ taxon.colAcceptedTaxonID = oldTaxon.colAcceptedTaxonID;
423
+ taxon.gbifTaxonID = oldTaxon.gbifTaxonID;
424
+ taxon.gbifAcceptedTaxonID = oldTaxon.gbifAcceptedTaxonID;
425
+ }
426
+ }
427
+ _q.label = 2;
428
+ case 2: return [2 /*return*/, resource];
429
+ case 3:
428
430
  filteredResults = {};
429
431
  taxonNames = {};
430
432
  names = new Set();
@@ -438,16 +440,16 @@ var ResourceProcessor = /** @class */ (function () {
438
440
  filteredResults[id] = [];
439
441
  }
440
442
  return [4 /*yield*/, runGnverifier(Array.from(names).join('\n'))];
441
- case 1:
442
- result = _l.sent();
443
- for (_i = 0, _a = result.trim().split('\n'); _i < _a.length; _i++) {
444
- results = _a[_i];
445
- _b = JSON.parse(results), name_2 = _b.name, matches = _b.results;
443
+ case 4:
444
+ result = _q.sent();
445
+ for (_d = 0, _e = result.trim().split('\n'); _d < _e.length; _d++) {
446
+ results = _e[_d];
447
+ _f = JSON.parse(results), name_2 = _f.name, matches = _f.results;
446
448
  if (!matches) {
447
449
  continue;
448
450
  }
449
- for (_c = 0, matches_1 = matches; _c < matches_1.length; _c++) {
450
- match = matches_1[_c];
451
+ for (_g = 0, matches_1 = matches; _g < matches_1.length; _g++) {
452
+ match = matches_1[_g];
451
453
  source = match.dataSourceId;
452
454
  currentRank = match.classificationRanks.split('|').pop();
453
455
  if (match.scoreDetails.cardinalityScore === 0) {
@@ -458,8 +460,8 @@ var ResourceProcessor = /** @class */ (function () {
458
460
  // GBIF species like "Nomada spec"
459
461
  continue;
460
462
  }
461
- for (_d = 0, _e = taxonNames[name_2]; _d < _e.length; _d++) {
462
- loirId = _e[_d];
463
+ for (_h = 0, _j = taxonNames[name_2]; _h < _j.length; _h++) {
464
+ loirId = _j[_h];
463
465
  taxon = resource.taxa[loirId];
464
466
  if (source === 11 && !GBIF_RANKS.includes(taxon.taxonRank)) {
465
467
  // Exclude GBIF matches for ranks that are not in GBIF
@@ -483,30 +485,30 @@ var ResourceProcessor = /** @class */ (function () {
483
485
  }
484
486
  }
485
487
  return [4 /*yield*/, Promise.resolve().then(function () { return require('../index'); })];
486
- case 2:
487
- _f = (_l.sent()).taxonNames, amendResource = _f.amendResource, groupNameMatches = _f.groupNameMatches;
488
+ case 5:
489
+ _k = (_q.sent()).taxonNames, amendResource = _k.amendResource, groupNameMatches = _k.groupNameMatches;
488
490
  groupedNameMatches = groupNameMatches(filteredResults);
489
491
  amendedResource = __assign(__assign({}, resource), { taxa: __assign({}, resource.taxa) });
490
- _g = groupedNameMatches;
491
- _h = [];
492
- for (_j in _g)
493
- _h.push(_j);
494
- _k = 0;
495
- _l.label = 3;
496
- case 3:
497
- if (!(_k < _h.length)) return [3 /*break*/, 6];
498
- _j = _h[_k];
499
- if (!(_j in _g)) return [3 /*break*/, 5];
500
- source = _j;
492
+ _l = groupedNameMatches;
493
+ _m = [];
494
+ for (_o in _l)
495
+ _m.push(_o);
496
+ _p = 0;
497
+ _q.label = 6;
498
+ case 6:
499
+ if (!(_p < _m.length)) return [3 /*break*/, 9];
500
+ _o = _m[_p];
501
+ if (!(_o in _l)) return [3 /*break*/, 8];
502
+ source = _o;
501
503
  return [4 /*yield*/, this.selectPrefixes(resource, groupedNameMatches, source)];
502
- case 4:
503
- matches = _l.sent();
504
+ case 7:
505
+ matches = _q.sent();
504
506
  amendResource(amendedResource, source, matches);
505
- _l.label = 5;
506
- case 5:
507
- _k++;
508
- return [3 /*break*/, 3];
509
- case 6: return [2 /*return*/, amendedResource];
507
+ _q.label = 8;
508
+ case 8:
509
+ _p++;
510
+ return [3 /*break*/, 6];
511
+ case 9: return [2 /*return*/, amendedResource];
510
512
  }
511
513
  });
512
514
  });
@@ -635,12 +637,14 @@ var ResourceProcessor = /** @class */ (function () {
635
637
  function main() {
636
638
  var args = util.parseArgs({
637
639
  options: {
638
- update: {
639
- type: 'boolean',
640
- short: 'u'
640
+ source: {
641
+ type: 'string',
642
+ short: 's',
643
+ default: 'unprocessed'
641
644
  },
642
- 'update-mappings': {
643
- type: 'boolean'
645
+ 'keep-mappings': {
646
+ type: 'boolean',
647
+ short: 'k'
644
648
  }
645
649
  },
646
650
  allowPositionals: true
@@ -649,17 +653,12 @@ function main() {
649
653
  process.on('exit', function () {
650
654
  process.stdout.write('\n');
651
655
  });
652
- var task;
653
- if (args.values.update) {
654
- task = processor.runUpdate();
655
- }
656
- else if (args.values['update-mappings']) {
657
- task = processor.runMappingsUpdate();
658
- }
659
- else {
660
- task = processor.run();
661
- }
662
- task.catch(function (error) {
656
+ var source = args.values.source;
657
+ var config = {
658
+ update: source !== 'unprocessed',
659
+ updateMappings: !args.values['keep-mappings']
660
+ };
661
+ processor.run(source, config).catch(function (error) {
663
662
  console.error(error);
664
663
  process.exit(1);
665
664
  });
@@ -22,10 +22,10 @@ exports.FORMATS = {
22
22
  };
23
23
  exports.CHECK = {
24
24
  MULTILANG: function (entry) {
25
- return entry.language.length > 1;
25
+ return Array.isArray(entry.language) && entry.language.length > 1;
26
26
  },
27
27
  ISBN: function (entry) {
28
- if (entry.ISBN.length < 2) {
28
+ if (!Array.isArray(entry.ISBN) || entry.ISBN.length < 2) {
29
29
  return false;
30
30
  }
31
31
  var a = entry.ISBN[0].length === 10;
package/lib/csv.js CHANGED
@@ -25,7 +25,7 @@ function formatCsv(table, delimiter) {
25
25
  .map(function (row) {
26
26
  return row.map(function (value) {
27
27
  if (/["\n]/.test(value) || value.includes(delimiter)) {
28
- return "\"".concat(value.replace(/"/, '"""'), "\"");
28
+ return "\"".concat(value.replace(/"/g, '""'), "\"");
29
29
  }
30
30
  else {
31
31
  return value;