@larsgw/formica 0.1.1 → 0.2.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/CHANGELOG.md +53 -0
- package/lib/bin/process-resources-index.js +0 -0
- package/lib/bin/process-resources.js +0 -0
- package/lib/bin/validate-catalog.js +0 -0
- package/lib/bin/validate-resources-text.js +0 -0
- package/lib/catalog/tables/work.js +1 -0
- package/lib/resources/parse-text.js +28 -4
- package/package.json +5 -1
- package/src/catalog/tables/work.ts +1 -0
- package/src/resources/parse-text.ts +33 -5
- package/test/resources.js +19 -0
- package/lib/types.d.ts +0 -62
- package/lib/types.js +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
## [0.2.1](https://github.com/identification-resources/formica/compare/v0.2.0...v0.2.1) (2023-08-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **resources:** do not validate old versions ([1a8dd2e](https://github.com/identification-resources/formica/commit/1a8dd2e0e373489e287d1fd89dbb7443245c5214))
|
|
7
|
+
* **resources:** fix check for missing leaf taxa ([035f1ad](https://github.com/identification-resources/formica/commit/035f1ad20efa80b388ec3828d4ace4518c7b344e))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# [0.2.0](https://github.com/identification-resources/formica/compare/v0.1.1...v0.2.0) (2023-08-09)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **catalog:** add taxon_scope column ([6a06c37](https://github.com/identification-resources/formica/commit/6a06c37ec0640a8ffbc258ad6a4d81d84d35fee9))
|
|
17
|
+
* **resources:** check for missing leaf taxa ([387c47d](https://github.com/identification-resources/formica/commit/387c47d10bb7f1fb09a68c10dfa869bb924b7633))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## [0.1.1](https://github.com/identification-resources/formica/compare/v0.1.0...v0.1.1) (2023-05-10)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
* **processor:** add Node hashbang ([51dee57](https://github.com/identification-resources/formica/commit/51dee57b8547afba449b2b846bd7d65e7927368f))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# [0.1.0](https://github.com/identification-resources/formica/compare/fed91fd6f350c47bd067d221a4d0e2278a199dae...v0.1.0) (2023-03-01)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* **resources:** fix typo in taxon name pattern ([8f1b6cf](https://github.com/identification-resources/formica/commit/8f1b6cfa3858edb83c0aee589b84ad760ab815af))
|
|
36
|
+
* **resources:** improve name parsing heuristics ([a40642e](https://github.com/identification-resources/formica/commit/a40642e9bdaeaae363584712e45f218809a5754b))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
* **catalog:** add SDK for catalog data ([fed91fd](https://github.com/identification-resources/formica/commit/fed91fd6f350c47bd067d221a4d0e2278a199dae))
|
|
42
|
+
* **csv:** allow custom delims in output ([b523614](https://github.com/identification-resources/formica/commit/b523614171b0ff96347cb876a08106df413c4032))
|
|
43
|
+
* **processor:** processor for DwC creation ([0e6f21d](https://github.com/identification-resources/formica/commit/0e6f21dfe00a2892348a4ab04fcaf3d6c8324a91))
|
|
44
|
+
* **processor:** processor for DwC indexing ([279773b](https://github.com/identification-resources/formica/commit/279773b085676cf7cb3eb4d81496ad219ac85bce))
|
|
45
|
+
* **resources:** add SDK for resource text files ([0acd36d](https://github.com/identification-resources/formica/commit/0acd36dde04cc1240cb8be97d48812b201b2685a))
|
|
46
|
+
* **resources:** add support for cluster markings ([112315c](https://github.com/identification-resources/formica/commit/112315c7ebd7151c4e2cc77ab20e0cec3f579db6))
|
|
47
|
+
* **resources:** add support for diffs as input ([9751627](https://github.com/identification-resources/formica/commit/9751627a916f47552661596048f1f0d44d89b102))
|
|
48
|
+
* **resources:** add support for hybrids ([e49e96a](https://github.com/identification-resources/formica/commit/e49e96af9c3958bab2a3b0508b1fc8a018b80716))
|
|
49
|
+
* **validate:** add catalog validation script ([4cdf785](https://github.com/identification-resources/formica/commit/4cdf785afb2c77320cd9b5b76483e3464c0f1cff))
|
|
50
|
+
* **validate:** add script to validate resources ([246fb5d](https://github.com/identification-resources/formica/commit/246fb5dd8da03e736884850874cc51a11be9985c))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -44,6 +44,7 @@ var Work = /** @class */ (function (_super) {
|
|
|
44
44
|
license: { required: false, multiple: true, format: value_1.FORMATS.LICENSE },
|
|
45
45
|
key_type: { required: true, multiple: true, format: value_1.FORMATS.KEY_TYPE },
|
|
46
46
|
taxon: { required: true, multiple: true },
|
|
47
|
+
taxon_scope: { required: false, multiple: true },
|
|
47
48
|
scope: { required: false, multiple: true },
|
|
48
49
|
region: { required: true, multiple: true },
|
|
49
50
|
complete: { required: false, multiple: false, format: value_1.FORMATS.COMPLETE },
|
|
@@ -43,6 +43,15 @@ var RANKS = [
|
|
|
43
43
|
'race',
|
|
44
44
|
'stirps' // not ICZN
|
|
45
45
|
];
|
|
46
|
+
var MAIN_RANKS = [
|
|
47
|
+
'kingdom',
|
|
48
|
+
'phylum',
|
|
49
|
+
'class',
|
|
50
|
+
'order',
|
|
51
|
+
'family',
|
|
52
|
+
'genus',
|
|
53
|
+
'species'
|
|
54
|
+
];
|
|
46
55
|
var DWC_RANKS = [
|
|
47
56
|
'kingdom',
|
|
48
57
|
'phylum',
|
|
@@ -350,10 +359,7 @@ function parseHeader(header) {
|
|
|
350
359
|
}
|
|
351
360
|
return metadata;
|
|
352
361
|
}
|
|
353
|
-
function
|
|
354
|
-
var _a = resource.split(/(\n---\n+)/), header = _a[0], _ = _a[1], rest = _a.slice(2);
|
|
355
|
-
var config = parseHeader(header);
|
|
356
|
-
var content = rest.join('');
|
|
362
|
+
function validateResource(config, content) {
|
|
357
363
|
// Check for too much indentation
|
|
358
364
|
var longerIndent = new RegExp("^( ){".concat(config.levels.length - 1, "}(?! [+=>] ) "), 'm');
|
|
359
365
|
var longerIndentMatch = content.match(longerIndent);
|
|
@@ -362,6 +368,23 @@ function parseResource(resource) {
|
|
|
362
368
|
var line = (content.slice(0, offset).match(/\n/g) || []).length + 1;
|
|
363
369
|
throw new SyntaxError("Too much indentation at ".concat(line, ":0\n").concat(content.slice(offset).split('\n', 1), "\n^"));
|
|
364
370
|
}
|
|
371
|
+
// Check for missing leaf taxa
|
|
372
|
+
var leafTaxonRank = config.levels.filter(function (rank) { return MAIN_RANKS.includes(rank); }).pop();
|
|
373
|
+
var leafTaxonParentIndent = config.levels.indexOf(leafTaxonRank) - 1;
|
|
374
|
+
if (leafTaxonRank && leafTaxonParentIndent >= 0) {
|
|
375
|
+
var missingLeafTaxa = new RegExp("^((?: ){0,".concat(leafTaxonParentIndent, "})(?![+=> ] ).*\\n(\\1( )+[+=>].*\\n)*(?!\\1 )"), 'm');
|
|
376
|
+
var missingLeafTaxaMatch = content.match(missingLeafTaxa);
|
|
377
|
+
if (missingLeafTaxaMatch !== null) {
|
|
378
|
+
var offset = missingLeafTaxaMatch.index;
|
|
379
|
+
var line = (content.slice(0, offset).match(/\n/g) || []).length + 1;
|
|
380
|
+
throw new SyntaxError("Missing leaf taxon at ".concat(line, ":0\n").concat(content.slice(offset).split('\n', 1), "\n^"));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function parseResource(resource) {
|
|
385
|
+
var _a = resource.split(/(\n---\n+)/), header = _a[0], _ = _a[1], rest = _a.slice(2);
|
|
386
|
+
var config = parseHeader(header);
|
|
387
|
+
var content = rest.join('');
|
|
365
388
|
return [config, content];
|
|
366
389
|
}
|
|
367
390
|
function parseResourceContent(content, resource, oldIds) {
|
|
@@ -468,6 +491,7 @@ function parseFile(file, id, old) {
|
|
|
468
491
|
var oldResources = old ? splitResources(old.txt) : [];
|
|
469
492
|
return splitResources(file).map(function (resource, index) {
|
|
470
493
|
var _a = parseResource(resource), config = _a[0], content = _a[1];
|
|
494
|
+
validateResource(config, content);
|
|
471
495
|
var template = {
|
|
472
496
|
id: "".concat(id, ":").concat(index + 1),
|
|
473
497
|
file: "".concat(id, "-").concat(index + 1),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@larsgw/formica",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
|
@@ -11,9 +11,12 @@
|
|
|
11
11
|
"loir-resources-index": "./lib/bin/process-resources-index.js"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
+
"test": "node --test --test-reporter spec",
|
|
14
15
|
"lint": "eslint src",
|
|
15
16
|
"build": "tsc -d",
|
|
17
|
+
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
16
18
|
"preversion": "npm run lint",
|
|
19
|
+
"version": "npm run changelog && git add CHANGELOG.md",
|
|
17
20
|
"prepublishOnly": "npm run build"
|
|
18
21
|
},
|
|
19
22
|
"repository": {
|
|
@@ -36,6 +39,7 @@
|
|
|
36
39
|
"@types/node": "^18.14.1",
|
|
37
40
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
|
38
41
|
"@typescript-eslint/parser": "^5.54.0",
|
|
42
|
+
"conventional-changelog-cli": "^3.0.0",
|
|
39
43
|
"eslint": "^8.35.0",
|
|
40
44
|
"typescript": "^4.9.5"
|
|
41
45
|
}
|
|
@@ -26,6 +26,7 @@ export class Work extends Entity {
|
|
|
26
26
|
license: { required: false, multiple: true, format: FORMATS.LICENSE },
|
|
27
27
|
key_type: { required: true, multiple: true, format: FORMATS.KEY_TYPE },
|
|
28
28
|
taxon: { required: true, multiple: true },
|
|
29
|
+
taxon_scope: { required: false, multiple: true },
|
|
29
30
|
scope: { required: false, multiple: true },
|
|
30
31
|
region: { required: true, multiple: true },
|
|
31
32
|
complete: { required: false, multiple: false, format: FORMATS.COMPLETE },
|
|
@@ -31,6 +31,16 @@ const RANKS: Rank[] = [
|
|
|
31
31
|
'stirps' // not ICZN
|
|
32
32
|
]
|
|
33
33
|
|
|
34
|
+
const MAIN_RANKS: Rank[] = [
|
|
35
|
+
'kingdom',
|
|
36
|
+
'phylum',
|
|
37
|
+
'class',
|
|
38
|
+
'order',
|
|
39
|
+
'family',
|
|
40
|
+
'genus',
|
|
41
|
+
'species'
|
|
42
|
+
]
|
|
43
|
+
|
|
34
44
|
const DWC_RANKS: DwcRank[] = [
|
|
35
45
|
'kingdom',
|
|
36
46
|
'phylum',
|
|
@@ -360,11 +370,7 @@ function parseHeader (header: string): ResourceMetadata {
|
|
|
360
370
|
return metadata
|
|
361
371
|
}
|
|
362
372
|
|
|
363
|
-
function
|
|
364
|
-
const [header, _, ...rest] = resource.split(/(\n---\n+)/)
|
|
365
|
-
const config = parseHeader(header)
|
|
366
|
-
const content = rest.join('')
|
|
367
|
-
|
|
373
|
+
function validateResource (config: ResourceMetadata, content: string) {
|
|
368
374
|
// Check for too much indentation
|
|
369
375
|
const longerIndent = new RegExp(`^( ){${config.levels.length - 1}}(?! [+=>] ) `, 'm')
|
|
370
376
|
const longerIndentMatch = content.match(longerIndent)
|
|
@@ -376,6 +382,27 @@ ${content.slice(offset).split('\n', 1)}
|
|
|
376
382
|
^`)
|
|
377
383
|
}
|
|
378
384
|
|
|
385
|
+
// Check for missing leaf taxa
|
|
386
|
+
const leafTaxonRank = config.levels.filter(rank => MAIN_RANKS.includes(rank)).pop() as string
|
|
387
|
+
const leafTaxonParentIndent = config.levels.indexOf(leafTaxonRank) - 1
|
|
388
|
+
if (leafTaxonRank && leafTaxonParentIndent >= 0) {
|
|
389
|
+
const missingLeafTaxa = new RegExp(`^((?: ){0,${leafTaxonParentIndent}})(?![+=> ] ).*\\n(\\1( )+[+=>].*\\n)*(?!\\1 )`, 'm')
|
|
390
|
+
const missingLeafTaxaMatch = content.match(missingLeafTaxa)
|
|
391
|
+
if (missingLeafTaxaMatch !== null) {
|
|
392
|
+
const offset = missingLeafTaxaMatch.index
|
|
393
|
+
const line = (content.slice(0, offset).match(/\n/g) || []).length + 1
|
|
394
|
+
throw new SyntaxError(`Missing leaf taxon at ${line}:0
|
|
395
|
+
${content.slice(offset).split('\n', 1)}
|
|
396
|
+
^`)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function parseResource (resource: string): [ResourceMetadata, string] {
|
|
402
|
+
const [header, _, ...rest] = resource.split(/(\n---\n+)/)
|
|
403
|
+
const config = parseHeader(header)
|
|
404
|
+
const content = rest.join('')
|
|
405
|
+
|
|
379
406
|
return [config, content]
|
|
380
407
|
}
|
|
381
408
|
|
|
@@ -488,6 +515,7 @@ export function parseFile (file: string, id: WorkId, old?: ResourceHistory): Res
|
|
|
488
515
|
const oldResources = old ? splitResources(old.txt) : []
|
|
489
516
|
return splitResources(file).map((resource, index) => {
|
|
490
517
|
const [config, content] = parseResource(resource)
|
|
518
|
+
validateResource(config, content)
|
|
491
519
|
const template: Resource = {
|
|
492
520
|
id: `${id}:${index + 1}`,
|
|
493
521
|
file: `${id}-${index + 1}`,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const test = require('node:test')
|
|
2
|
+
const assert = require('assert')
|
|
3
|
+
|
|
4
|
+
const { resources } = require('../lib')
|
|
5
|
+
|
|
6
|
+
test('resources', async (t) => {
|
|
7
|
+
await t.test('missing leaf taxa', (t) => {
|
|
8
|
+
assert.throws(() => {
|
|
9
|
+
resources.parseTextFile(`---
|
|
10
|
+
levels: [family, genus, species]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Cydnidae
|
|
14
|
+
Cydnidae
|
|
15
|
+
Legnotus
|
|
16
|
+
limbosus`, 'T1')
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
})
|
package/lib/types.d.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
type Value = string[] | string;
|
|
2
|
-
type SingleValue = string;
|
|
3
|
-
interface FieldError {
|
|
4
|
-
field: string;
|
|
5
|
-
error: string;
|
|
6
|
-
}
|
|
7
|
-
interface WorkError extends FieldError {
|
|
8
|
-
entity: WorkId;
|
|
9
|
-
}
|
|
10
|
-
type Rank = string;
|
|
11
|
-
type DwcRank = Rank;
|
|
12
|
-
type TaxonStatus = string;
|
|
13
|
-
type TaxonId = string;
|
|
14
|
-
type ResourceId = string;
|
|
15
|
-
type WorkId = string;
|
|
16
|
-
interface WorkingTaxon {
|
|
17
|
-
scientificNameID?: TaxonId;
|
|
18
|
-
scientificName?: string;
|
|
19
|
-
scientificNameAuthorship?: string;
|
|
20
|
-
genericName?: string;
|
|
21
|
-
infragenericEpithet?: string;
|
|
22
|
-
specificEpithet?: string;
|
|
23
|
-
intraspecificEpithet?: string;
|
|
24
|
-
taxonRank?: Rank;
|
|
25
|
-
taxonRemarks?: string;
|
|
26
|
-
collectionCode?: ResourceId;
|
|
27
|
-
taxonomicStatus?: TaxonStatus;
|
|
28
|
-
acceptedNameUsageID?: TaxonId;
|
|
29
|
-
acceptedNameUsage?: string;
|
|
30
|
-
parentNameUsageID?: TaxonId;
|
|
31
|
-
parentNameUsage?: string;
|
|
32
|
-
kingdom?: string;
|
|
33
|
-
phylum?: string;
|
|
34
|
-
class?: string;
|
|
35
|
-
order?: string;
|
|
36
|
-
family?: string;
|
|
37
|
-
subfamily?: string;
|
|
38
|
-
genus?: string;
|
|
39
|
-
subgenus?: string;
|
|
40
|
-
higherClassification?: string;
|
|
41
|
-
scientificNameOnly?: string;
|
|
42
|
-
incorrect?: WorkingTaxon;
|
|
43
|
-
}
|
|
44
|
-
interface Taxon extends WorkingTaxon {
|
|
45
|
-
scientificNameID: TaxonId;
|
|
46
|
-
scientificName: string;
|
|
47
|
-
taxonRank: Rank;
|
|
48
|
-
collectionCode: ResourceId;
|
|
49
|
-
taxonomicStatus: string;
|
|
50
|
-
}
|
|
51
|
-
interface ResourceMetadata {
|
|
52
|
-
levels: Rank[];
|
|
53
|
-
scope: string[];
|
|
54
|
-
catalog?: object;
|
|
55
|
-
}
|
|
56
|
-
interface Resource {
|
|
57
|
-
id: string;
|
|
58
|
-
file: string;
|
|
59
|
-
workId: string;
|
|
60
|
-
metadata: ResourceMetadata;
|
|
61
|
-
taxa: Record<TaxonId, Taxon>;
|
|
62
|
-
}
|
package/lib/types.js
DELETED
|
File without changes
|