glossarist 0.2.2 → 0.3.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.
- package/README.md +4 -2
- package/package.json +1 -1
- package/src/concept-parser.js +25 -0
- package/src/concept-serializer.js +12 -0
- package/src/gcr-reader.js +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/models/citation.js +48 -29
- package/src/models/concept-date.js +1 -1
- package/src/models/concept-ref.js +25 -0
- package/src/models/concept.js +6 -2
- package/src/models/designation.js +69 -14
- package/src/models/grammar-info.js +40 -0
- package/src/models/index.d.ts +105 -23
- package/src/models/index.js +6 -2
- package/src/models/locality.js +22 -0
- package/src/models/localized-concept.js +113 -12
- package/src/models/non-verb-rep.js +8 -8
- package/src/models/pronunciation.js +26 -0
- package/src/models/related-concept.js +25 -6
- package/src/reference-resolver.js +11 -1
- package/src/validators/index.js +26 -1
- package/src/validators/v3-rules.js +216 -0
package/README.md
CHANGED
|
@@ -308,8 +308,10 @@ import 'glossarist/validators'; // validation framework
|
|
|
308
308
|
|
|
309
309
|
```
|
|
310
310
|
Public API (index.js)
|
|
311
|
-
├── Domain models → Concept, LocalizedConcept, Designation (Expression,
|
|
312
|
-
│
|
|
311
|
+
├── Domain models → Concept, LocalizedConcept, Designation (Expression, Abbreviation, Symbol,
|
|
312
|
+
│ LetterSymbol, GraphicalSymbol), GrammarInfo, Pronunciation, Locality,
|
|
313
|
+
│ Citation, ConceptSource, RelatedConcept, ConceptReference, ConceptDate,
|
|
314
|
+
│ DetailedDefinition, NonVerbRep
|
|
313
315
|
├── Parsing → ConceptParser (canonical + managed format detection)
|
|
314
316
|
├── Serialization → ConceptSerializer (canonical + managed YAML output)
|
|
315
317
|
├── I/O → loadGcr, readConcepts, createGcr, writeConcepts
|
package/package.json
CHANGED
package/src/concept-parser.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import yaml from 'js-yaml';
|
|
2
2
|
import { Concept } from './models/concept.js';
|
|
3
|
+
import { ConceptRef } from './models/concept-ref.js';
|
|
4
|
+
import { RelatedConcept } from './models/related-concept.js';
|
|
3
5
|
import { InvalidInputError, YamlParseError } from './errors.js';
|
|
4
6
|
|
|
5
7
|
const STRUCTURAL_KEYS = new Set(['termid', 'term']);
|
|
@@ -70,11 +72,34 @@ export class ConceptParser {
|
|
|
70
72
|
id: String(mc.data.identifier),
|
|
71
73
|
term: null,
|
|
72
74
|
localizations,
|
|
75
|
+
related: _normalizeRelated(mc.related ?? mc.data?.related),
|
|
73
76
|
domains: mc.data.domains,
|
|
74
77
|
groups: mc.data.groups,
|
|
78
|
+
dates: mc.dates ?? mc.data?.dates,
|
|
79
|
+
sources: mc.sources ?? mc.data?.sources,
|
|
80
|
+
status: mc.status,
|
|
81
|
+
schemaVersion: mc.schema_version,
|
|
75
82
|
raw: mc,
|
|
76
83
|
});
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
|
|
87
|
+
function _normalizeRelated(arr) {
|
|
88
|
+
if (!arr || !Array.isArray(arr)) return [];
|
|
89
|
+
return arr.map(r => {
|
|
90
|
+
if (r instanceof RelatedConcept) return r;
|
|
91
|
+
const data = { ...r };
|
|
92
|
+
if (data.ref) {
|
|
93
|
+
if (typeof data.ref !== 'object' || data.ref === null) {
|
|
94
|
+
throw new InvalidInputError(
|
|
95
|
+
`RelatedConcept.ref must be an object { source, id }, got: ${typeof data.ref}`,
|
|
96
|
+
'object',
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
data.ref = new ConceptRef(data.ref);
|
|
100
|
+
}
|
|
101
|
+
return new RelatedConcept(data);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
80
105
|
export const conceptParser = new ConceptParser();
|
|
@@ -43,6 +43,18 @@ export class ConceptSerializer {
|
|
|
43
43
|
mainDoc.data.domains = concept.domains.map(d => d.toJSON());
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
if (concept.relatedConcepts.length > 0) {
|
|
47
|
+
mainDoc.related = concept.relatedConcepts.map(rc => rc.toJSON());
|
|
48
|
+
}
|
|
49
|
+
if (concept.sources.length > 0) {
|
|
50
|
+
mainDoc.sources = concept.sources.map(s => s.toJSON());
|
|
51
|
+
}
|
|
52
|
+
if (concept.dates.length > 0) {
|
|
53
|
+
mainDoc.dates = concept.dates.map(d => d.toJSON());
|
|
54
|
+
}
|
|
55
|
+
if (concept.status) mainDoc.status = concept.status;
|
|
56
|
+
if (concept.schemaVersion) mainDoc.schema_version = concept.schemaVersion;
|
|
57
|
+
|
|
46
58
|
const parts = [
|
|
47
59
|
'---\n' + yaml.dump(mainDoc, DUMP_OPTS),
|
|
48
60
|
...langDocs.map(d => '---\n' + yaml.dump(d, DUMP_OPTS)),
|
package/src/gcr-reader.js
CHANGED
|
@@ -26,7 +26,7 @@ const BASE64_RE = /^[A-Za-z0-9+/]{100,}={0,2}$/;
|
|
|
26
26
|
/**
|
|
27
27
|
* @typedef {Object} Source
|
|
28
28
|
* @property {string} type - e.g. 'authoritative', 'adapted'
|
|
29
|
-
* @property {{ ref: string }} [origin] - reference to the source standard
|
|
29
|
+
* @property {{ ref: { source: string, id?: string, version?: string } }} [origin] - reference to the source standard
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
/**
|
package/src/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export {
|
|
|
3
3
|
GlossaristModel,
|
|
4
4
|
Concept, LocalizedConcept,
|
|
5
5
|
Designation, Expression, Abbreviation, Symbol, GraphicalSymbol,
|
|
6
|
-
Citation, ConceptSource, RelatedConcept, ConceptDate,
|
|
6
|
+
Citation, ConceptRef, ConceptSource, RelatedConcept, ConceptDate,
|
|
7
7
|
DetailedDefinition, NonVerbRep,
|
|
8
8
|
GcrMetadata, GcrStatistics,
|
|
9
9
|
RELATIONSHIP_TYPES, DATE_TYPES,
|
package/src/index.js
CHANGED
|
@@ -30,7 +30,7 @@ export {
|
|
|
30
30
|
GlossaristModel,
|
|
31
31
|
Concept, LocalizedConcept,
|
|
32
32
|
Designation, Expression, Abbreviation, Symbol, GraphicalSymbol,
|
|
33
|
-
Citation, ConceptSource, RelatedConcept, ConceptReference, ConceptDate,
|
|
33
|
+
Citation, ConceptRef, ConceptSource, RelatedConcept, ConceptReference, ConceptDate,
|
|
34
34
|
DetailedDefinition, NonVerbRep,
|
|
35
35
|
GcrMetadata, GcrStatistics,
|
|
36
36
|
RELATIONSHIP_TYPES, DATE_TYPES,
|
package/src/models/citation.js
CHANGED
|
@@ -1,45 +1,35 @@
|
|
|
1
1
|
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { Locality } from './locality.js';
|
|
2
3
|
|
|
3
4
|
export class Citation extends GlossaristModel {
|
|
4
|
-
constructor(data) {
|
|
5
|
+
constructor(data = {}) {
|
|
5
6
|
super();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.version = d.version ?? null;
|
|
19
|
-
this.clause = d.clause ?? null;
|
|
20
|
-
this.link = d.link ?? null;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get isStructured() {
|
|
25
|
-
return typeof this.source === 'object' && this.source !== null;
|
|
7
|
+
const d = data ?? {};
|
|
8
|
+
|
|
9
|
+
this.ref = d.ref
|
|
10
|
+
? (d.ref instanceof Citation.Ref ? d.ref : new Citation.Ref(d.ref))
|
|
11
|
+
: null;
|
|
12
|
+
|
|
13
|
+
this.locality = d.locality
|
|
14
|
+
? (d.locality instanceof Locality ? d.locality : new Locality(d.locality))
|
|
15
|
+
: null;
|
|
16
|
+
this.link = d.link ?? null;
|
|
17
|
+
this.original = d.original ?? null;
|
|
18
|
+
this.customLocality = d.custom_locality ?? d.customLocality ?? null;
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
toString() {
|
|
29
|
-
if (this.ref) return this.ref;
|
|
30
|
-
if (typeof this.source === 'string') return this.source;
|
|
31
|
-
if (typeof this.source === 'object' && this.source !== null) return this.source.ref ?? '';
|
|
22
|
+
if (this.ref) return this.ref.toString();
|
|
32
23
|
return '';
|
|
33
24
|
}
|
|
34
25
|
|
|
35
26
|
toJSON() {
|
|
36
27
|
const obj = {};
|
|
37
|
-
if (this.
|
|
38
|
-
if (this.
|
|
39
|
-
if (this.id != null) obj.id = this.id;
|
|
40
|
-
if (this.version != null) obj.version = this.version;
|
|
41
|
-
if (this.clause != null) obj.clause = this.clause;
|
|
28
|
+
if (this.ref != null) obj.ref = this.ref.toJSON();
|
|
29
|
+
if (this.locality != null) obj.locality = this.locality.toJSON();
|
|
42
30
|
if (this.link != null) obj.link = this.link;
|
|
31
|
+
if (this.original != null) obj.original = this.original;
|
|
32
|
+
if (this.customLocality != null) obj.custom_locality = this.customLocality;
|
|
43
33
|
return obj;
|
|
44
34
|
}
|
|
45
35
|
|
|
@@ -47,3 +37,32 @@ export class Citation extends GlossaristModel {
|
|
|
47
37
|
return new Citation(data);
|
|
48
38
|
}
|
|
49
39
|
}
|
|
40
|
+
|
|
41
|
+
Citation.Ref = class Ref extends GlossaristModel {
|
|
42
|
+
constructor(data = {}) {
|
|
43
|
+
super();
|
|
44
|
+
const d = data ?? {};
|
|
45
|
+
this.source = d.source ?? null;
|
|
46
|
+
this.id = d.id ?? null;
|
|
47
|
+
this.version = d.version ?? null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
toString() {
|
|
51
|
+
const parts = [];
|
|
52
|
+
if (this.source) parts.push(this.source);
|
|
53
|
+
if (this.id) parts.push(this.id);
|
|
54
|
+
return parts.join(' ');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
toJSON() {
|
|
58
|
+
const obj = {};
|
|
59
|
+
if (this.source != null) obj.source = this.source;
|
|
60
|
+
if (this.id != null) obj.id = this.id;
|
|
61
|
+
if (this.version != null) obj.version = this.version;
|
|
62
|
+
return obj;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static fromJSON(data) {
|
|
66
|
+
return new Citation.Ref(data);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export class ConceptRef extends GlossaristModel {
|
|
4
|
+
constructor(data = {}) {
|
|
5
|
+
super();
|
|
6
|
+
this.source = data.source ?? null;
|
|
7
|
+
this.id = data.id ?? null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
toString() {
|
|
11
|
+
if (this.source && this.id) return `${this.source} ${this.id}`;
|
|
12
|
+
return this.source ?? this.id ?? '';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
toJSON() {
|
|
16
|
+
const obj = {};
|
|
17
|
+
if (this.source != null) obj.source = this.source;
|
|
18
|
+
if (this.id != null) obj.id = this.id;
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static fromJSON(data) {
|
|
23
|
+
return new ConceptRef(data);
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/models/concept.js
CHANGED
|
@@ -10,14 +10,16 @@ export class Concept extends GlossaristModel {
|
|
|
10
10
|
super();
|
|
11
11
|
this.id = String(data.id ?? data.termid ?? '');
|
|
12
12
|
this.term = data.term ?? null;
|
|
13
|
+
this.uri = data.uri ?? null;
|
|
13
14
|
this._rawLocalizations = data.localizations ?? {};
|
|
14
15
|
this._cache = {};
|
|
15
16
|
|
|
16
|
-
this.relatedConcepts = _mapInstances(data.relatedConcepts ?? data.related_concepts ?? [], RelatedConcept);
|
|
17
|
+
this.relatedConcepts = _mapInstances(data.relatedConcepts ?? data.related ?? data.related_concepts ?? [], RelatedConcept);
|
|
17
18
|
this.domains = _normalizeDomains(data.domains, data.groups);
|
|
18
19
|
this.dates = _mapInstances(data.dates ?? [], ConceptDate);
|
|
19
20
|
this.sources = _mapInstances(data.sources ?? [], ConceptSource);
|
|
20
21
|
this.status = data.status ?? null;
|
|
22
|
+
this.schemaVersion = data.schemaVersion ?? data.schema_version ?? '3';
|
|
21
23
|
this.raw = data.raw ?? null;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -68,6 +70,7 @@ export class Concept extends GlossaristModel {
|
|
|
68
70
|
toJSON() {
|
|
69
71
|
const obj = { id: this.id };
|
|
70
72
|
if (this.term != null) obj.term = this.term;
|
|
73
|
+
if (this.uri != null) obj.uri = this.uri;
|
|
71
74
|
|
|
72
75
|
if (Object.keys(this._rawLocalizations).length > 0) {
|
|
73
76
|
obj.localizations = {};
|
|
@@ -84,7 +87,7 @@ export class Concept extends GlossaristModel {
|
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
if (this.relatedConcepts.length > 0) {
|
|
87
|
-
obj.
|
|
90
|
+
obj.related = this.relatedConcepts.map(rc => rc.toJSON());
|
|
88
91
|
}
|
|
89
92
|
if (this.domains.length > 0) {
|
|
90
93
|
obj.domains = this.domains.map(d => d.toJSON());
|
|
@@ -96,6 +99,7 @@ export class Concept extends GlossaristModel {
|
|
|
96
99
|
obj.sources = this.sources.map(s => s.toJSON());
|
|
97
100
|
}
|
|
98
101
|
if (this.status != null) obj.status = this.status;
|
|
102
|
+
obj.schema_version = this.schemaVersion;
|
|
99
103
|
return obj;
|
|
100
104
|
}
|
|
101
105
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { ConceptSource } from './concept-source.js';
|
|
3
|
+
import { Pronunciation } from './pronunciation.js';
|
|
4
|
+
import { GrammarInfo } from './grammar-info.js';
|
|
5
|
+
import { RelatedConcept } from './related-concept.js';
|
|
2
6
|
|
|
3
7
|
export class Designation extends GlossaristModel {
|
|
4
8
|
static _registry = new Map();
|
|
@@ -18,11 +22,41 @@ export class Designation extends GlossaristModel {
|
|
|
18
22
|
this.designation = data.designation ?? '';
|
|
19
23
|
this.type = data.type ?? 'expression';
|
|
20
24
|
this.normativeStatus = data.normative_status ?? null;
|
|
25
|
+
this.absent = data.absent ?? null;
|
|
26
|
+
this.fieldOfApplication = data.field_of_application ?? null;
|
|
27
|
+
this.usageInfo = data.usage_info ?? null;
|
|
28
|
+
this.geographicalArea = data.geographical_area ?? null;
|
|
29
|
+
this.language = data.language ?? null;
|
|
30
|
+
this.script = data.script ?? null;
|
|
31
|
+
this.system = data.system ?? null;
|
|
32
|
+
this.international = data.international ?? null;
|
|
33
|
+
this.termType = data.term_type ?? null;
|
|
34
|
+
this.pronunciations = (data.pronunciation ?? []).map(
|
|
35
|
+
p => p instanceof Pronunciation ? p : new Pronunciation(p)
|
|
36
|
+
);
|
|
37
|
+
this.sources = (data.sources ?? []).map(
|
|
38
|
+
s => s instanceof ConceptSource ? s : new ConceptSource(s)
|
|
39
|
+
);
|
|
40
|
+
this.related = (data.related ?? []).map(
|
|
41
|
+
r => r instanceof RelatedConcept ? r : new RelatedConcept(r)
|
|
42
|
+
);
|
|
21
43
|
}
|
|
22
44
|
|
|
23
45
|
toJSON() {
|
|
24
46
|
const obj = { type: this.type, designation: this.designation };
|
|
25
47
|
if (this.normativeStatus != null) obj.normative_status = this.normativeStatus;
|
|
48
|
+
if (this.absent != null) obj.absent = this.absent;
|
|
49
|
+
if (this.fieldOfApplication != null) obj.field_of_application = this.fieldOfApplication;
|
|
50
|
+
if (this.usageInfo != null) obj.usage_info = this.usageInfo;
|
|
51
|
+
if (this.geographicalArea != null) obj.geographical_area = this.geographicalArea;
|
|
52
|
+
if (this.language != null) obj.language = this.language;
|
|
53
|
+
if (this.script != null) obj.script = this.script;
|
|
54
|
+
if (this.system != null) obj.system = this.system;
|
|
55
|
+
if (this.international != null) obj.international = this.international;
|
|
56
|
+
if (this.termType != null) obj.term_type = this.termType;
|
|
57
|
+
if (this.pronunciations.length > 0) obj.pronunciation = this.pronunciations.map(p => p.toJSON());
|
|
58
|
+
if (this.sources.length > 0) obj.sources = this.sources.map(s => s.toJSON());
|
|
59
|
+
if (this.related.length > 0) obj.related = this.related.map(r => r.toJSON());
|
|
26
60
|
return obj;
|
|
27
61
|
}
|
|
28
62
|
|
|
@@ -34,18 +68,16 @@ export class Designation extends GlossaristModel {
|
|
|
34
68
|
export class Expression extends Designation {
|
|
35
69
|
constructor(data = {}) {
|
|
36
70
|
super(data);
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
39
|
-
|
|
40
|
-
|
|
71
|
+
this.prefix = data.prefix ?? null;
|
|
72
|
+
this.grammarInfo = (data.grammar_info ?? []).map(
|
|
73
|
+
g => g instanceof GrammarInfo ? g : new GrammarInfo(g)
|
|
74
|
+
);
|
|
41
75
|
}
|
|
42
76
|
|
|
43
77
|
toJSON() {
|
|
44
78
|
const obj = super.toJSON();
|
|
45
|
-
if (this.
|
|
46
|
-
if (this.
|
|
47
|
-
if (this.partOfSpeech != null) obj.part_of_speech = this.partOfSpeech;
|
|
48
|
-
if (this.geographicalArea != null) obj.geographical_area = this.geographicalArea;
|
|
79
|
+
if (this.prefix != null) obj.prefix = this.prefix;
|
|
80
|
+
if (this.grammarInfo.length > 0) obj.grammar_info = this.grammarInfo.map(g => g.toJSON());
|
|
49
81
|
return obj;
|
|
50
82
|
}
|
|
51
83
|
|
|
@@ -54,37 +86,60 @@ export class Expression extends Designation {
|
|
|
54
86
|
|
|
55
87
|
Designation.register('expression', Expression);
|
|
56
88
|
|
|
57
|
-
export class Abbreviation extends
|
|
89
|
+
export class Abbreviation extends Expression {
|
|
90
|
+
constructor(data = {}) {
|
|
91
|
+
super(data);
|
|
92
|
+
this.acronym = data.acronym ?? false;
|
|
93
|
+
this.initialism = data.initialism ?? false;
|
|
94
|
+
this.truncation = data.truncation ?? false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
toJSON() {
|
|
98
|
+
const obj = super.toJSON();
|
|
99
|
+
if (this.acronym) obj.acronym = true;
|
|
100
|
+
if (this.initialism) obj.initialism = true;
|
|
101
|
+
if (this.truncation) obj.truncation = true;
|
|
102
|
+
return obj;
|
|
103
|
+
}
|
|
104
|
+
|
|
58
105
|
static fromJSON(data) { return new Abbreviation(data); }
|
|
59
106
|
}
|
|
60
107
|
|
|
61
108
|
Designation.register('abbreviation', Abbreviation);
|
|
62
109
|
|
|
63
110
|
export class Symbol extends Designation {
|
|
111
|
+
static fromJSON(data) { return new Symbol(data); }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Designation.register('symbol', Symbol);
|
|
115
|
+
|
|
116
|
+
export class LetterSymbol extends Symbol {
|
|
64
117
|
constructor(data = {}) {
|
|
65
118
|
super(data);
|
|
66
|
-
this.
|
|
119
|
+
this.text = data.text ?? null;
|
|
67
120
|
}
|
|
68
121
|
|
|
69
122
|
toJSON() {
|
|
70
123
|
const obj = super.toJSON();
|
|
71
|
-
if (this.
|
|
124
|
+
if (this.text != null) obj.text = this.text;
|
|
72
125
|
return obj;
|
|
73
126
|
}
|
|
74
127
|
|
|
75
|
-
static fromJSON(data) { return new
|
|
128
|
+
static fromJSON(data) { return new LetterSymbol(data); }
|
|
76
129
|
}
|
|
77
130
|
|
|
78
|
-
Designation.register('
|
|
131
|
+
Designation.register('letter_symbol', LetterSymbol);
|
|
79
132
|
|
|
80
|
-
export class GraphicalSymbol extends
|
|
133
|
+
export class GraphicalSymbol extends Symbol {
|
|
81
134
|
constructor(data = {}) {
|
|
82
135
|
super(data);
|
|
136
|
+
this.text = data.text ?? null;
|
|
83
137
|
this.image = data.image ?? null;
|
|
84
138
|
}
|
|
85
139
|
|
|
86
140
|
toJSON() {
|
|
87
141
|
const obj = super.toJSON();
|
|
142
|
+
if (this.text != null) obj.text = this.text;
|
|
88
143
|
if (this.image != null) obj.image = this.image;
|
|
89
144
|
return obj;
|
|
90
145
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export const GRAMMAR_GENDERS = Object.freeze(['m', 'f', 'n', 'c']);
|
|
4
|
+
export const GRAMMAR_NUMBERS = Object.freeze(['singular', 'dual', 'plural']);
|
|
5
|
+
export const GRAMMAR_PARTS_OF_SPEECH = Object.freeze([
|
|
6
|
+
'noun', 'verb', 'adj', 'adverb', 'preposition', 'participle',
|
|
7
|
+
]);
|
|
8
|
+
|
|
9
|
+
export class GrammarInfo extends GlossaristModel {
|
|
10
|
+
constructor(data = {}) {
|
|
11
|
+
super();
|
|
12
|
+
this.gender = data.gender ?? null;
|
|
13
|
+
this.number = data.number ?? null;
|
|
14
|
+
this.partOfSpeech = data.part_of_speech ?? data.partOfSpeech ?? null;
|
|
15
|
+
this.noun = data.noun ?? false;
|
|
16
|
+
this.verb = data.verb ?? false;
|
|
17
|
+
this.adj = data.adj ?? false;
|
|
18
|
+
this.adverb = data.adverb ?? false;
|
|
19
|
+
this.preposition = data.preposition ?? false;
|
|
20
|
+
this.participle = data.participle ?? false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
toJSON() {
|
|
24
|
+
const obj = {};
|
|
25
|
+
if (this.gender != null) obj.gender = this.gender;
|
|
26
|
+
if (this.number != null) obj.number = this.number;
|
|
27
|
+
if (this.partOfSpeech != null) obj.part_of_speech = this.partOfSpeech;
|
|
28
|
+
if (this.noun) obj.noun = true;
|
|
29
|
+
if (this.verb) obj.verb = true;
|
|
30
|
+
if (this.adj) obj.adj = true;
|
|
31
|
+
if (this.adverb) obj.adverb = true;
|
|
32
|
+
if (this.preposition) obj.preposition = true;
|
|
33
|
+
if (this.participle) obj.participle = true;
|
|
34
|
+
return obj;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static fromJSON(data) {
|
|
38
|
+
return new GrammarInfo(data);
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/models/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export class GlossaristModel {
|
|
|
8
8
|
export class Concept extends GlossaristModel {
|
|
9
9
|
readonly id: string;
|
|
10
10
|
readonly term: string | null;
|
|
11
|
+
readonly uri: string | null;
|
|
11
12
|
readonly termid: string;
|
|
12
13
|
readonly languages: string[];
|
|
13
14
|
readonly localizations: Record<string, any>;
|
|
@@ -17,6 +18,7 @@ export class Concept extends GlossaristModel {
|
|
|
17
18
|
readonly dates: ConceptDate[];
|
|
18
19
|
readonly sources: ConceptSource[];
|
|
19
20
|
readonly status: string | null;
|
|
21
|
+
readonly schemaVersion: string | null;
|
|
20
22
|
|
|
21
23
|
localization(lang: string): LocalizedConcept | undefined;
|
|
22
24
|
primaryDesignation(lang: string): string | null;
|
|
@@ -28,14 +30,29 @@ export class Concept extends GlossaristModel {
|
|
|
28
30
|
|
|
29
31
|
export class LocalizedConcept extends GlossaristModel {
|
|
30
32
|
readonly languageCode: string | null;
|
|
33
|
+
readonly script: string | null;
|
|
34
|
+
readonly system: string | null;
|
|
35
|
+
readonly entryStatus: string | null;
|
|
36
|
+
readonly classification: string | null;
|
|
37
|
+
readonly reviewType: string | null;
|
|
38
|
+
readonly domain: string | null;
|
|
39
|
+
readonly release: string | null;
|
|
40
|
+
readonly lineageSourceSimilarity: number | null;
|
|
41
|
+
readonly reviewDate: string | null;
|
|
42
|
+
readonly reviewDecisionDate: string | null;
|
|
43
|
+
readonly reviewDecisionEvent: string | null;
|
|
44
|
+
readonly reviewStatus: string | null;
|
|
45
|
+
readonly reviewDecision: string | null;
|
|
46
|
+
readonly reviewDecisionNotes: string | null;
|
|
31
47
|
readonly terms: Designation[];
|
|
32
48
|
readonly definitions: DetailedDefinition[];
|
|
33
49
|
readonly definition: DetailedDefinition[];
|
|
34
|
-
readonly notes:
|
|
35
|
-
readonly examples:
|
|
50
|
+
readonly notes: DetailedDefinition[];
|
|
51
|
+
readonly examples: DetailedDefinition[];
|
|
36
52
|
readonly sources: ConceptSource[];
|
|
37
|
-
readonly
|
|
38
|
-
readonly
|
|
53
|
+
readonly dates: ConceptDate[];
|
|
54
|
+
readonly nonVerbalRep: NonVerbRep[];
|
|
55
|
+
readonly related: RelatedConcept[];
|
|
39
56
|
readonly primaryDesignation: string | null;
|
|
40
57
|
readonly primaryDefinition: string | null;
|
|
41
58
|
static fromJSON(data: Record<string, unknown>): LocalizedConcept;
|
|
@@ -45,35 +62,100 @@ export class Designation extends GlossaristModel {
|
|
|
45
62
|
readonly designation: string;
|
|
46
63
|
readonly type: string;
|
|
47
64
|
readonly normativeStatus: string | null;
|
|
65
|
+
readonly absent: boolean | null;
|
|
66
|
+
readonly fieldOfApplication: string | null;
|
|
67
|
+
readonly usageInfo: string | null;
|
|
68
|
+
readonly geographicalArea: string | null;
|
|
69
|
+
readonly language: string | null;
|
|
70
|
+
readonly script: string | null;
|
|
71
|
+
readonly system: string | null;
|
|
72
|
+
readonly international: boolean | null;
|
|
73
|
+
readonly termType: string | null;
|
|
74
|
+
readonly pronunciations: Pronunciation[];
|
|
75
|
+
readonly sources: ConceptSource[];
|
|
76
|
+
readonly related: RelatedConcept[];
|
|
48
77
|
static register(type: string, cls: typeof Designation): void;
|
|
49
78
|
static fromData(data: Record<string, unknown>): Designation;
|
|
50
79
|
static fromJSON(data: Record<string, unknown>): Designation;
|
|
51
80
|
}
|
|
52
81
|
|
|
53
82
|
export class Expression extends Designation {
|
|
83
|
+
readonly prefix: string | null;
|
|
84
|
+
readonly grammarInfo: GrammarInfo[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export class Abbreviation extends Expression {
|
|
88
|
+
readonly acronym: boolean;
|
|
89
|
+
readonly initialism: boolean;
|
|
90
|
+
readonly truncation: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class Symbol extends Designation {}
|
|
94
|
+
|
|
95
|
+
export class LetterSymbol extends Symbol {
|
|
96
|
+
readonly text: string | null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export class GraphicalSymbol extends Symbol {
|
|
100
|
+
readonly text: string | null;
|
|
101
|
+
readonly image: string | null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const GRAMMAR_GENDERS: readonly string[];
|
|
105
|
+
export const GRAMMAR_NUMBERS: readonly string[];
|
|
106
|
+
export const GRAMMAR_PARTS_OF_SPEECH: readonly string[];
|
|
107
|
+
|
|
108
|
+
export class GrammarInfo extends GlossaristModel {
|
|
54
109
|
readonly gender: string | null;
|
|
55
|
-
readonly
|
|
110
|
+
readonly number: string | null;
|
|
56
111
|
readonly partOfSpeech: string | null;
|
|
57
|
-
readonly
|
|
112
|
+
readonly noun: boolean;
|
|
113
|
+
readonly verb: boolean;
|
|
114
|
+
readonly adj: boolean;
|
|
115
|
+
readonly adverb: boolean;
|
|
116
|
+
readonly preposition: boolean;
|
|
117
|
+
readonly participle: boolean;
|
|
58
118
|
}
|
|
59
119
|
|
|
60
|
-
export class
|
|
61
|
-
|
|
62
|
-
readonly
|
|
120
|
+
export class Pronunciation extends GlossaristModel {
|
|
121
|
+
readonly content: string | null;
|
|
122
|
+
readonly language: string | null;
|
|
123
|
+
readonly script: string | null;
|
|
124
|
+
readonly country: string | null;
|
|
125
|
+
readonly system: string | null;
|
|
63
126
|
}
|
|
64
|
-
|
|
65
|
-
|
|
127
|
+
|
|
128
|
+
export class Locality extends GlossaristModel {
|
|
129
|
+
readonly type: string | null;
|
|
130
|
+
readonly referenceFrom: string | null;
|
|
131
|
+
readonly referenceTo: string | null;
|
|
66
132
|
}
|
|
67
133
|
|
|
68
134
|
export class Citation extends GlossaristModel {
|
|
69
|
-
readonly
|
|
70
|
-
readonly
|
|
71
|
-
readonly id: string | null;
|
|
72
|
-
readonly version: string | null;
|
|
73
|
-
readonly clause: string | null;
|
|
135
|
+
readonly ref: Citation.Ref | null;
|
|
136
|
+
readonly locality: Locality | null;
|
|
74
137
|
readonly link: string | null;
|
|
75
|
-
readonly
|
|
138
|
+
readonly original: string | null;
|
|
139
|
+
readonly customLocality: unknown;
|
|
76
140
|
toString(): string;
|
|
141
|
+
static fromJSON(data: Record<string, unknown>): Citation;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export namespace Citation {
|
|
145
|
+
class Ref extends GlossaristModel {
|
|
146
|
+
readonly source: string | null;
|
|
147
|
+
readonly id: string | null;
|
|
148
|
+
readonly version: string | null;
|
|
149
|
+
toString(): string;
|
|
150
|
+
static fromJSON(data: Record<string, unknown>): Ref;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export class ConceptRef extends GlossaristModel {
|
|
155
|
+
readonly source: string | null;
|
|
156
|
+
readonly id: string | null;
|
|
157
|
+
toString(): string;
|
|
158
|
+
static fromJSON(data: Record<string, unknown>): ConceptRef;
|
|
77
159
|
}
|
|
78
160
|
|
|
79
161
|
export class ConceptSource extends GlossaristModel {
|
|
@@ -87,7 +169,7 @@ export const RELATIONSHIP_TYPES: readonly string[];
|
|
|
87
169
|
export class RelatedConcept extends GlossaristModel {
|
|
88
170
|
readonly type: string;
|
|
89
171
|
readonly content: string | null;
|
|
90
|
-
readonly ref:
|
|
172
|
+
readonly ref: ConceptRef | null;
|
|
91
173
|
}
|
|
92
174
|
|
|
93
175
|
export class ConceptReference extends GlossaristModel {
|
|
@@ -110,14 +192,14 @@ export class ConceptDate extends GlossaristModel {
|
|
|
110
192
|
|
|
111
193
|
export class DetailedDefinition extends GlossaristModel {
|
|
112
194
|
readonly content: string;
|
|
113
|
-
readonly sources:
|
|
195
|
+
readonly sources: ConceptSource[];
|
|
114
196
|
}
|
|
115
197
|
|
|
116
198
|
export class NonVerbRep extends GlossaristModel {
|
|
117
|
-
readonly
|
|
118
|
-
readonly
|
|
119
|
-
readonly
|
|
120
|
-
readonly sources:
|
|
199
|
+
readonly type: string | null;
|
|
200
|
+
readonly ref: string | null;
|
|
201
|
+
readonly text: string | null;
|
|
202
|
+
readonly sources: ConceptSource[];
|
|
121
203
|
}
|
|
122
204
|
|
|
123
205
|
export class GcrStatistics extends GlossaristModel {
|
package/src/models/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
export { GlossaristModel } from './base.js';
|
|
2
2
|
export { Concept } from './concept.js';
|
|
3
3
|
export { LocalizedConcept } from './localized-concept.js';
|
|
4
|
-
export { Designation, Expression, Abbreviation, Symbol, GraphicalSymbol } from './designation.js';
|
|
4
|
+
export { Designation, Expression, Abbreviation, Symbol, LetterSymbol, GraphicalSymbol } from './designation.js';
|
|
5
5
|
export { Citation } from './citation.js';
|
|
6
|
+
export { ConceptRef } from './concept-ref.js';
|
|
6
7
|
export { ConceptSource } from './concept-source.js';
|
|
7
8
|
export { RelatedConcept, RELATIONSHIP_TYPES } from './related-concept.js';
|
|
8
9
|
export { ConceptReference } from './concept-reference.js';
|
|
9
10
|
export { ConceptDate, DATE_TYPES } from './concept-date.js';
|
|
10
11
|
export { DetailedDefinition } from './detailed-definition.js';
|
|
11
12
|
export { NonVerbRep } from './non-verb-rep.js';
|
|
13
|
+
export { Pronunciation } from './pronunciation.js';
|
|
14
|
+
export { GrammarInfo, GRAMMAR_GENDERS, GRAMMAR_NUMBERS, GRAMMAR_PARTS_OF_SPEECH } from './grammar-info.js';
|
|
15
|
+
export { Locality } from './locality.js';
|
|
12
16
|
export { GcrMetadata } from './gcr-metadata.js';
|
|
13
|
-
export { GcrStatistics } from './gcr-statistics.js'
|
|
17
|
+
export { GcrStatistics } from './gcr-statistics.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export class Locality extends GlossaristModel {
|
|
4
|
+
constructor(data = {}) {
|
|
5
|
+
super();
|
|
6
|
+
this.type = data.type ?? null;
|
|
7
|
+
this.referenceFrom = data.reference_from ?? data.referenceFrom ?? null;
|
|
8
|
+
this.referenceTo = data.reference_to ?? data.referenceTo ?? null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
toJSON() {
|
|
12
|
+
const obj = {};
|
|
13
|
+
if (this.type != null) obj.type = this.type;
|
|
14
|
+
if (this.referenceFrom != null) obj.reference_from = this.referenceFrom;
|
|
15
|
+
if (this.referenceTo != null) obj.reference_to = this.referenceTo;
|
|
16
|
+
return obj;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static fromJSON(data) {
|
|
20
|
+
return new Locality(data);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -2,24 +2,47 @@ import { GlossaristModel } from './base.js';
|
|
|
2
2
|
import { Designation } from './designation.js';
|
|
3
3
|
import { DetailedDefinition } from './detailed-definition.js';
|
|
4
4
|
import { ConceptSource } from './concept-source.js';
|
|
5
|
+
import { ConceptDate } from './concept-date.js';
|
|
6
|
+
import { NonVerbRep } from './non-verb-rep.js';
|
|
7
|
+
import { RelatedConcept } from './related-concept.js';
|
|
5
8
|
|
|
6
9
|
export class LocalizedConcept extends GlossaristModel {
|
|
7
10
|
constructor(data = {}) {
|
|
8
11
|
super();
|
|
9
12
|
this.languageCode = data.language_code ?? data.languageCode ?? null;
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
12
|
-
this._rawSources = data.sources ?? [];
|
|
13
|
-
this.notes = data.notes ?? [];
|
|
14
|
-
this.examples = data.examples ?? [];
|
|
13
|
+
this.script = data.script ?? null;
|
|
14
|
+
this.system = data.system ?? null;
|
|
15
15
|
this.entryStatus = data.entry_status ?? data.entryStatus ?? null;
|
|
16
|
-
this.reviewType = data.review_type ?? data.reviewType ?? null;
|
|
17
16
|
this.classification = data.classification ?? null;
|
|
17
|
+
this.reviewType = data.review_type ?? data.reviewType ?? null;
|
|
18
18
|
this.domain = data.domain ?? null;
|
|
19
|
+
this.release = data.release ?? null;
|
|
20
|
+
this.lineageSourceSimilarity = data.lineage_source_similarity ?? data.lineageSourceSimilarity ?? null;
|
|
21
|
+
|
|
22
|
+
this.reviewDate = data.review_date ?? data.reviewDate ?? null;
|
|
23
|
+
this.reviewDecisionDate = data.review_decision_date ?? data.reviewDecisionDate ?? null;
|
|
24
|
+
this.reviewDecisionEvent = data.review_decision_event ?? data.reviewDecisionEvent ?? null;
|
|
25
|
+
this.reviewStatus = data.review_status ?? data.reviewStatus ?? null;
|
|
26
|
+
this.reviewDecision = data.review_decision ?? data.reviewDecision ?? null;
|
|
27
|
+
this.reviewDecisionNotes = data.review_decision_notes ?? data.reviewDecisionNotes ?? null;
|
|
28
|
+
|
|
29
|
+
this._rawTerms = data.terms ?? [];
|
|
30
|
+
this._rawDefinition = data.definition ?? [];
|
|
31
|
+
this._rawSources = data.sources ?? [];
|
|
32
|
+
this._rawNotes = data.notes ?? [];
|
|
33
|
+
this._rawExamples = data.examples ?? [];
|
|
34
|
+
this._rawDates = data.dates ?? [];
|
|
35
|
+
this._rawNonVerbal = data.non_verbal_rep ?? data.non_verb ?? [];
|
|
36
|
+
this._rawRelated = data.related ?? [];
|
|
19
37
|
|
|
20
38
|
this._terms = null;
|
|
21
39
|
this._definitions = null;
|
|
22
40
|
this._sources = null;
|
|
41
|
+
this._notes = null;
|
|
42
|
+
this._examples = null;
|
|
43
|
+
this._dates = null;
|
|
44
|
+
this._nonVerbal = null;
|
|
45
|
+
this._related = null;
|
|
23
46
|
}
|
|
24
47
|
|
|
25
48
|
get terms() {
|
|
@@ -51,6 +74,51 @@ export class LocalizedConcept extends GlossaristModel {
|
|
|
51
74
|
return this._sources;
|
|
52
75
|
}
|
|
53
76
|
|
|
77
|
+
get notes() {
|
|
78
|
+
if (this._notes === null) {
|
|
79
|
+
this._notes = this._rawNotes.map(
|
|
80
|
+
n => n instanceof DetailedDefinition ? n : new DetailedDefinition(n)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return this._notes;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get examples() {
|
|
87
|
+
if (this._examples === null) {
|
|
88
|
+
this._examples = this._rawExamples.map(
|
|
89
|
+
e => e instanceof DetailedDefinition ? e : new DetailedDefinition(e)
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return this._examples;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get dates() {
|
|
96
|
+
if (this._dates === null) {
|
|
97
|
+
this._dates = this._rawDates.map(
|
|
98
|
+
d => d instanceof ConceptDate ? d : new ConceptDate(d)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return this._dates;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get nonVerbalRep() {
|
|
105
|
+
if (this._nonVerbal === null) {
|
|
106
|
+
this._nonVerbal = this._rawNonVerbal.map(
|
|
107
|
+
n => n instanceof NonVerbRep ? n : new NonVerbRep(n)
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return this._nonVerbal;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get related() {
|
|
114
|
+
if (this._related === null) {
|
|
115
|
+
this._related = this._rawRelated.map(
|
|
116
|
+
r => r instanceof RelatedConcept ? r : new RelatedConcept(r)
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return this._related;
|
|
120
|
+
}
|
|
121
|
+
|
|
54
122
|
get primaryDesignation() {
|
|
55
123
|
return this.terms[0]?.designation ?? null;
|
|
56
124
|
}
|
|
@@ -62,6 +130,21 @@ export class LocalizedConcept extends GlossaristModel {
|
|
|
62
130
|
toJSON() {
|
|
63
131
|
const obj = {};
|
|
64
132
|
if (this.languageCode) obj.language_code = this.languageCode;
|
|
133
|
+
if (this.script) obj.script = this.script;
|
|
134
|
+
if (this.system) obj.system = this.system;
|
|
135
|
+
if (this.entryStatus) obj.entry_status = this.entryStatus;
|
|
136
|
+
if (this.classification) obj.classification = this.classification;
|
|
137
|
+
if (this.reviewType) obj.review_type = this.reviewType;
|
|
138
|
+
if (this.domain) obj.domain = this.domain;
|
|
139
|
+
if (this.release) obj.release = this.release;
|
|
140
|
+
if (this.lineageSourceSimilarity != null) obj.lineage_source_similarity = this.lineageSourceSimilarity;
|
|
141
|
+
|
|
142
|
+
if (this.reviewDate) obj.review_date = this.reviewDate;
|
|
143
|
+
if (this.reviewDecisionDate) obj.review_decision_date = this.reviewDecisionDate;
|
|
144
|
+
if (this.reviewDecisionEvent) obj.review_decision_event = this.reviewDecisionEvent;
|
|
145
|
+
if (this.reviewStatus) obj.review_status = this.reviewStatus;
|
|
146
|
+
if (this.reviewDecision) obj.review_decision = this.reviewDecision;
|
|
147
|
+
if (this.reviewDecisionNotes) obj.review_decision_notes = this.reviewDecisionNotes;
|
|
65
148
|
|
|
66
149
|
const terms = this._terms ?? this._rawTerms;
|
|
67
150
|
if (terms.length > 0) {
|
|
@@ -73,18 +156,36 @@ export class LocalizedConcept extends GlossaristModel {
|
|
|
73
156
|
obj.definition = defs.map(d => (typeof d.toJSON === 'function') ? d.toJSON() : d);
|
|
74
157
|
}
|
|
75
158
|
|
|
76
|
-
|
|
77
|
-
if (
|
|
159
|
+
const notes = this._notes ?? (this._rawNotes.length > 0 ? this._rawNotes : []);
|
|
160
|
+
if (notes.length > 0) {
|
|
161
|
+
obj.notes = notes.map(n => (typeof n.toJSON === 'function') ? n.toJSON() : n);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const examples = this._examples ?? (this._rawExamples.length > 0 ? this._rawExamples : []);
|
|
165
|
+
if (examples.length > 0) {
|
|
166
|
+
obj.examples = examples.map(e => (typeof e.toJSON === 'function') ? e.toJSON() : e);
|
|
167
|
+
}
|
|
78
168
|
|
|
79
169
|
const sources = this._sources ?? (this._rawSources.length > 0 ? this._rawSources : []);
|
|
80
170
|
if (sources.length > 0) {
|
|
81
171
|
obj.sources = sources.map(s => (typeof s.toJSON === 'function') ? s.toJSON() : s);
|
|
82
172
|
}
|
|
83
173
|
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
174
|
+
const dates = this._dates ?? (this._rawDates.length > 0 ? this._rawDates : []);
|
|
175
|
+
if (dates.length > 0) {
|
|
176
|
+
obj.dates = dates.map(d => (typeof d.toJSON === 'function') ? d.toJSON() : d);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const nonVerbal = this._nonVerbal ?? (this._rawNonVerbal.length > 0 ? this._rawNonVerbal : []);
|
|
180
|
+
if (nonVerbal.length > 0) {
|
|
181
|
+
obj.non_verbal_rep = nonVerbal.map(n => (typeof n.toJSON === 'function') ? n.toJSON() : n);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const related = this._related ?? (this._rawRelated.length > 0 ? this._rawRelated : []);
|
|
185
|
+
if (related.length > 0) {
|
|
186
|
+
obj.related = related.map(r => (typeof r.toJSON === 'function') ? r.toJSON() : r);
|
|
187
|
+
}
|
|
188
|
+
|
|
88
189
|
return obj;
|
|
89
190
|
}
|
|
90
191
|
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { GlossaristModel } from './base.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ConceptSource } from './concept-source.js';
|
|
3
3
|
|
|
4
4
|
export class NonVerbRep extends GlossaristModel {
|
|
5
5
|
constructor(data = {}) {
|
|
6
6
|
super();
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
7
|
+
this.type = data.type ?? null;
|
|
8
|
+
this.ref = data.ref ?? null;
|
|
9
|
+
this.text = data.text ?? null;
|
|
10
10
|
this.sources = (data.sources ?? []).map(
|
|
11
|
-
s => s instanceof
|
|
11
|
+
s => s instanceof ConceptSource ? s : new ConceptSource(s)
|
|
12
12
|
);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
toJSON() {
|
|
16
16
|
const obj = {};
|
|
17
|
-
if (this.
|
|
18
|
-
if (this.
|
|
19
|
-
if (this.
|
|
17
|
+
if (this.type != null) obj.type = this.type;
|
|
18
|
+
if (this.ref != null) obj.ref = this.ref;
|
|
19
|
+
if (this.text != null) obj.text = this.text;
|
|
20
20
|
if (this.sources.length > 0) obj.sources = this.sources.map(s => s.toJSON());
|
|
21
21
|
return obj;
|
|
22
22
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export class Pronunciation extends GlossaristModel {
|
|
4
|
+
constructor(data = {}) {
|
|
5
|
+
super();
|
|
6
|
+
this.content = data.content ?? null;
|
|
7
|
+
this.language = data.language ?? null;
|
|
8
|
+
this.script = data.script ?? null;
|
|
9
|
+
this.system = data.system ?? null;
|
|
10
|
+
this.country = data.country ?? null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
toJSON() {
|
|
14
|
+
const obj = {};
|
|
15
|
+
if (this.content != null) obj.content = this.content;
|
|
16
|
+
if (this.language != null) obj.language = this.language;
|
|
17
|
+
if (this.script != null) obj.script = this.script;
|
|
18
|
+
if (this.system != null) obj.system = this.system;
|
|
19
|
+
if (this.country != null) obj.country = this.country;
|
|
20
|
+
return obj;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static fromJSON(data) {
|
|
24
|
+
return new Pronunciation(data);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
import { GlossaristModel } from './base.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ConceptRef } from './concept-ref.js';
|
|
3
3
|
|
|
4
4
|
export const RELATIONSHIP_TYPES = Object.freeze([
|
|
5
|
-
|
|
6
|
-
'
|
|
7
|
-
|
|
5
|
+
// Lifecycle (ISO 10241-1)
|
|
6
|
+
'deprecates', 'supersedes', 'superseded_by',
|
|
7
|
+
// Hierarchical (SKOS)
|
|
8
|
+
'broader', 'narrower',
|
|
9
|
+
// ISO 25964 generic
|
|
10
|
+
'broader_generic', 'narrower_generic',
|
|
11
|
+
// ISO 25964 partitive
|
|
12
|
+
'broader_partitive', 'narrower_partitive',
|
|
13
|
+
// ISO 25964 instantial
|
|
14
|
+
'broader_instantial', 'narrower_instantial',
|
|
15
|
+
// SKOS mapping
|
|
16
|
+
'equivalent', 'close_match', 'broad_match', 'narrow_match', 'related_match',
|
|
17
|
+
// Associative (ISO 10241-1 / ISO 25964)
|
|
18
|
+
'see', 'related_concept', 'related_concept_broader', 'related_concept_narrower',
|
|
19
|
+
// Comparative (ISO 10241-1)
|
|
20
|
+
'compare', 'contrast',
|
|
21
|
+
// Spatiotemporal (ISO 25964 / TBX)
|
|
22
|
+
'sequentially_related_concept', 'spatially_related_concept', 'temporally_related_concept',
|
|
23
|
+
// Lexical (ISO 12620 / TBX)
|
|
24
|
+
'homograph', 'false_friend',
|
|
25
|
+
// Designation-level
|
|
26
|
+
'abbreviated_form_for', 'short_form_for',
|
|
8
27
|
]);
|
|
9
28
|
|
|
10
29
|
export class RelatedConcept extends GlossaristModel {
|
|
11
30
|
constructor(data = {}) {
|
|
12
31
|
super();
|
|
13
|
-
this.type = data.type ?? '
|
|
32
|
+
this.type = data.type ?? 'see';
|
|
14
33
|
this.content = data.content ?? null;
|
|
15
34
|
this.ref = data.ref
|
|
16
|
-
? (data.ref instanceof
|
|
35
|
+
? (data.ref instanceof ConceptRef ? data.ref : new ConceptRef(data.ref))
|
|
17
36
|
: null;
|
|
18
37
|
}
|
|
19
38
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ConceptRef } from './models/concept-ref.js';
|
|
2
|
+
|
|
1
3
|
export class Reference {
|
|
2
4
|
constructor(type, target, relationship, source) {
|
|
3
5
|
this.type = type;
|
|
@@ -7,12 +9,20 @@ export class Reference {
|
|
|
7
9
|
}
|
|
8
10
|
}
|
|
9
11
|
|
|
12
|
+
function refTarget(rc) {
|
|
13
|
+
if (rc.content) return rc.content;
|
|
14
|
+
if (rc.ref instanceof ConceptRef) {
|
|
15
|
+
return rc.ref.id ?? rc.ref.source ?? '';
|
|
16
|
+
}
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
export class ReferenceResolver {
|
|
11
21
|
extractReferences(concept) {
|
|
12
22
|
const refs = [];
|
|
13
23
|
|
|
14
24
|
for (const rc of concept.relatedConcepts) {
|
|
15
|
-
const target = rc
|
|
25
|
+
const target = refTarget(rc);
|
|
16
26
|
if (target) {
|
|
17
27
|
refs.push(new Reference('concept', target, rc.type, 'relatedConcepts'));
|
|
18
28
|
}
|
package/src/validators/index.js
CHANGED
|
@@ -4,15 +4,40 @@ export { ValidationResult } from './validation-result.js';
|
|
|
4
4
|
export { ConceptValidator, LanguageCodeRule, DesignationTypeRule, EntryStatusRule } from './concept-validator.js';
|
|
5
5
|
export { RegisterValidator } from './register-validator.js';
|
|
6
6
|
export { GcrValidator } from './gcr-validator.js';
|
|
7
|
+
export {
|
|
8
|
+
RefShapeRule,
|
|
9
|
+
LocalityCompletenessRule,
|
|
10
|
+
LocalizationConsistencyRule,
|
|
11
|
+
SchemaVersionRule,
|
|
12
|
+
DomainRefRule,
|
|
13
|
+
UuidFormatRule,
|
|
14
|
+
SourceUrnFormatRule,
|
|
15
|
+
} from './v3-rules.js';
|
|
7
16
|
|
|
8
17
|
import { ConceptValidator, LanguageCodeRule, DesignationTypeRule, EntryStatusRule } from './concept-validator.js';
|
|
9
18
|
import { RegisterValidator } from './register-validator.js';
|
|
10
19
|
import { GcrValidator } from './gcr-validator.js';
|
|
20
|
+
import {
|
|
21
|
+
RefShapeRule,
|
|
22
|
+
LocalityCompletenessRule,
|
|
23
|
+
LocalizationConsistencyRule,
|
|
24
|
+
SchemaVersionRule,
|
|
25
|
+
DomainRefRule,
|
|
26
|
+
UuidFormatRule,
|
|
27
|
+
SourceUrnFormatRule,
|
|
28
|
+
} from './v3-rules.js';
|
|
11
29
|
|
|
12
30
|
const _default = new ConceptValidator()
|
|
13
31
|
.addRule(new LanguageCodeRule())
|
|
14
32
|
.addRule(new DesignationTypeRule())
|
|
15
|
-
.addRule(new EntryStatusRule())
|
|
33
|
+
.addRule(new EntryStatusRule())
|
|
34
|
+
.addRule(new RefShapeRule())
|
|
35
|
+
.addRule(new LocalityCompletenessRule())
|
|
36
|
+
.addRule(new LocalizationConsistencyRule())
|
|
37
|
+
.addRule(new SchemaVersionRule())
|
|
38
|
+
.addRule(new DomainRefRule())
|
|
39
|
+
.addRule(new UuidFormatRule())
|
|
40
|
+
.addRule(new SourceUrnFormatRule());
|
|
16
41
|
|
|
17
42
|
export function validateConcept(concept) {
|
|
18
43
|
return _default.validate(concept);
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { ValidationRule } from './validation-rule.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GLS-305: Enforces Citation#ref is a proper Citation.Ref object
|
|
5
|
+
* and RelatedConcept#ref has at least source or id.
|
|
6
|
+
*/
|
|
7
|
+
export class RefShapeRule extends ValidationRule {
|
|
8
|
+
constructor() { super('ref-shape'); }
|
|
9
|
+
|
|
10
|
+
validate(value, path) {
|
|
11
|
+
const errors = [];
|
|
12
|
+
|
|
13
|
+
// Check sources in localizations
|
|
14
|
+
const localizations = value.localizations || {};
|
|
15
|
+
let sourceIdx = 0;
|
|
16
|
+
for (const [lang, lc] of Object.entries(localizations)) {
|
|
17
|
+
const sources = lc.sources || [];
|
|
18
|
+
for (let i = 0; i < sources.length; i++) {
|
|
19
|
+
sourceIdx++;
|
|
20
|
+
const origin = sources[i].origin;
|
|
21
|
+
if (!origin) continue;
|
|
22
|
+
|
|
23
|
+
const ref = origin.ref;
|
|
24
|
+
if (!ref) {
|
|
25
|
+
errors.push(...this.error(
|
|
26
|
+
`${path}localizations.${lang}.sources[${i}].origin.ref`,
|
|
27
|
+
`source ${sourceIdx} origin has nil ref (expected Citation.Ref hash)`,
|
|
28
|
+
));
|
|
29
|
+
} else if (!ref.source && !ref.id) {
|
|
30
|
+
errors.push(...this.error(
|
|
31
|
+
`${path}localizations.${lang}.sources[${i}].origin.ref`,
|
|
32
|
+
`source ${sourceIdx} origin.ref has neither source nor id`,
|
|
33
|
+
));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check related concepts
|
|
39
|
+
const related = value.related || [];
|
|
40
|
+
for (let i = 0; i < related.length; i++) {
|
|
41
|
+
const ref = related[i].ref;
|
|
42
|
+
if (!ref) continue;
|
|
43
|
+
if (!ref.source && !ref.id) {
|
|
44
|
+
errors.push(...this.error(
|
|
45
|
+
`${path}related[${i}].ref`,
|
|
46
|
+
`related concept ${i + 1} has empty ref (no source or id)`,
|
|
47
|
+
));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return errors;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* GLS-308: Locality must have type and reference_from when present.
|
|
57
|
+
*/
|
|
58
|
+
export class LocalityCompletenessRule extends ValidationRule {
|
|
59
|
+
constructor() { super('locality-completeness', 'warning'); }
|
|
60
|
+
|
|
61
|
+
validate(value, path) {
|
|
62
|
+
const errors = [];
|
|
63
|
+
const localizations = value.localizations || {};
|
|
64
|
+
|
|
65
|
+
for (const [lang, lc] of Object.entries(localizations)) {
|
|
66
|
+
const sources = lc.sources || [];
|
|
67
|
+
for (let i = 0; i < sources.length; i++) {
|
|
68
|
+
const origin = sources[i].origin;
|
|
69
|
+
if (!origin || !origin.locality) continue;
|
|
70
|
+
|
|
71
|
+
const loc = origin.locality;
|
|
72
|
+
if (!loc.type) {
|
|
73
|
+
errors.push(...this.error(
|
|
74
|
+
`${path}localizations.${lang}.sources[${i}].origin.locality.type`,
|
|
75
|
+
`source locality has no type`,
|
|
76
|
+
));
|
|
77
|
+
}
|
|
78
|
+
if (!loc.reference_from) {
|
|
79
|
+
errors.push(...this.error(
|
|
80
|
+
`${path}localizations.${lang}.sources[${i}].origin.locality.reference_from`,
|
|
81
|
+
`source locality has no reference_from`,
|
|
82
|
+
));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return errors;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* GLS-017: Localization map consistency.
|
|
93
|
+
*/
|
|
94
|
+
export class LocalizationConsistencyRule extends ValidationRule {
|
|
95
|
+
constructor() { super('localization-consistency'); }
|
|
96
|
+
|
|
97
|
+
validate(value, path) {
|
|
98
|
+
const errors = [];
|
|
99
|
+
const localizations = value.localizations || {};
|
|
100
|
+
const data = value.raw?.data || value;
|
|
101
|
+
|
|
102
|
+
const declaredLangs = data.localized_concepts
|
|
103
|
+
? Object.keys(data.localized_concepts)
|
|
104
|
+
: Object.keys(localizations);
|
|
105
|
+
|
|
106
|
+
for (const lang of declaredLangs) {
|
|
107
|
+
if (!localizations[lang]) {
|
|
108
|
+
errors.push(...this.error(
|
|
109
|
+
`${path}localizations.${lang}`,
|
|
110
|
+
`localized_concepts map has '${lang}' but no localization loaded`,
|
|
111
|
+
));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return errors;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* GLS-010: Schema version should be 3.
|
|
121
|
+
*/
|
|
122
|
+
export class SchemaVersionRule extends ValidationRule {
|
|
123
|
+
constructor() { super('schema-version', 'warning'); }
|
|
124
|
+
|
|
125
|
+
validate(value, path) {
|
|
126
|
+
const errors = [];
|
|
127
|
+
const version = value.schemaVersion || value.schema_version;
|
|
128
|
+
|
|
129
|
+
if (version && String(version) !== '3') {
|
|
130
|
+
errors.push(...this.error(
|
|
131
|
+
`${path}schema_version`,
|
|
132
|
+
`schema_version is '${version}', expected '3'`,
|
|
133
|
+
));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return errors;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* GLS-309: Domain references need concept_id or urn.
|
|
142
|
+
*/
|
|
143
|
+
export class DomainRefRule extends ValidationRule {
|
|
144
|
+
constructor() { super('domain-ref', 'warning'); }
|
|
145
|
+
|
|
146
|
+
validate(value, path) {
|
|
147
|
+
const errors = [];
|
|
148
|
+
const domains = value.domains || [];
|
|
149
|
+
|
|
150
|
+
for (let i = 0; i < domains.length; i++) {
|
|
151
|
+
const domain = domains[i];
|
|
152
|
+
if (!domain.concept_id && !domain.urn) {
|
|
153
|
+
errors.push(...this.error(
|
|
154
|
+
`${path}domains[${i}]`,
|
|
155
|
+
`domain ${i + 1} has neither concept_id nor urn`,
|
|
156
|
+
));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return errors;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* GLS-016: UUID format validation.
|
|
166
|
+
*/
|
|
167
|
+
export class UuidFormatRule extends ValidationRule {
|
|
168
|
+
constructor() { super('uuid-format'); }
|
|
169
|
+
|
|
170
|
+
validate(value, path) {
|
|
171
|
+
const errors = [];
|
|
172
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
173
|
+
const id = value.id || value.uuid;
|
|
174
|
+
|
|
175
|
+
if (id && !UUID_RE.test(String(id))) {
|
|
176
|
+
// Only flag if it looks like it's supposed to be a UUID
|
|
177
|
+
if (String(id).includes('-') && String(id).length > 20) {
|
|
178
|
+
errors.push(...this.error(
|
|
179
|
+
`${path}id`,
|
|
180
|
+
`concept ID '${id}' is not valid UUID format`,
|
|
181
|
+
));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return errors;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* GLS-310: URN format validation for sources.
|
|
191
|
+
*/
|
|
192
|
+
export class SourceUrnFormatRule extends ValidationRule {
|
|
193
|
+
constructor() { super('source-urn-format', 'warning'); }
|
|
194
|
+
|
|
195
|
+
validate(value, path) {
|
|
196
|
+
const errors = [];
|
|
197
|
+
const URN_RE = /^urn:[a-z0-9][a-z0-9-]{0,31}:[a-z0-9()+,\-.:=@;$_!*'%/?#]+$/i;
|
|
198
|
+
|
|
199
|
+
const localizations = value.localizations || {};
|
|
200
|
+
for (const [lang, lc] of Object.entries(localizations)) {
|
|
201
|
+
const sources = lc.sources || [];
|
|
202
|
+
for (let i = 0; i < sources.length; i++) {
|
|
203
|
+
const source = sources[i].origin?.ref?.source;
|
|
204
|
+
if (!source || !source.startsWith('urn:')) continue;
|
|
205
|
+
if (!URN_RE.test(source)) {
|
|
206
|
+
errors.push(...this.error(
|
|
207
|
+
`${path}localizations.${lang}.sources[${i}].origin.ref.source`,
|
|
208
|
+
`malformed URN '${source}'`,
|
|
209
|
+
));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return errors;
|
|
215
|
+
}
|
|
216
|
+
}
|