glossarist 0.1.1 → 0.1.2
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/package.json +15 -5
- package/src/concept-collection.js +109 -0
- package/src/concept-parser.js +78 -0
- package/src/concept-reader.js +7 -6
- package/src/concept-serializer.js +60 -0
- package/src/concept-writer.d.ts +7 -0
- package/src/concept-writer.js +42 -0
- package/src/gcr-reader.js +4 -78
- package/src/gcr-writer.d.ts +13 -0
- package/src/gcr-writer.js +38 -0
- package/src/index.d.ts +38 -1
- package/src/index.js +17 -0
- package/src/managed-concept-collection.js +61 -0
- package/src/models/base.js +18 -0
- package/src/models/citation.js +45 -0
- package/src/models/concept-date.js +28 -0
- package/src/models/concept-source.js +27 -0
- package/src/models/concept.js +104 -0
- package/src/models/designation.js +96 -0
- package/src/models/detailed-definition.js +24 -0
- package/src/models/index.d.ts +107 -0
- package/src/models/index.js +10 -0
- package/src/models/localized-concept.js +92 -0
- package/src/models/non-verb-rep.js +27 -0
- package/src/models/related-concept.js +30 -0
- package/src/reference-resolver.js +78 -0
- package/src/uuid.js +28 -0
- package/src/v1-reader.js +63 -0
- package/src/validators/concept-validator.js +119 -0
- package/src/validators/index.d.ts +26 -0
- package/src/validators/index.js +23 -0
- package/src/validators/validation-error.js +11 -0
- package/src/validators/validation-rule.js +16 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class GlossaristModel {
|
|
2
|
+
toJSON() {
|
|
3
|
+
throw new Error(`${this.constructor.name} must implement toJSON()`);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
static fromJSON() {
|
|
7
|
+
throw new Error(`${this.name} must implement fromJSON()`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
equals(other) {
|
|
11
|
+
if (!(other instanceof this.constructor)) return false;
|
|
12
|
+
return JSON.stringify(this.toJSON()) === JSON.stringify(other.toJSON());
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
clone() {
|
|
16
|
+
return this.constructor.fromJSON(JSON.parse(JSON.stringify(this.toJSON())));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export class Citation extends GlossaristModel {
|
|
4
|
+
constructor(data) {
|
|
5
|
+
super();
|
|
6
|
+
if (typeof data === 'string') {
|
|
7
|
+
this.source = data;
|
|
8
|
+
this.ref = null;
|
|
9
|
+
this.id = null;
|
|
10
|
+
this.version = null;
|
|
11
|
+
this.clause = null;
|
|
12
|
+
this.link = null;
|
|
13
|
+
} else {
|
|
14
|
+
const d = data ?? {};
|
|
15
|
+
this.source = d.source ?? null;
|
|
16
|
+
this.ref = d.ref ?? null;
|
|
17
|
+
this.id = d.id ?? null;
|
|
18
|
+
this.version = d.version ?? null;
|
|
19
|
+
this.clause = d.clause ?? null;
|
|
20
|
+
this.link = d.link ?? null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
toString() {
|
|
25
|
+
if (this.ref) return this.ref;
|
|
26
|
+
if (typeof this.source === 'string') return this.source;
|
|
27
|
+
if (typeof this.source === 'object' && this.source !== null) return this.source.ref ?? '';
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
toJSON() {
|
|
32
|
+
const obj = {};
|
|
33
|
+
if (this.source != null) obj.source = this.source;
|
|
34
|
+
if (this.ref != null) obj.ref = this.ref;
|
|
35
|
+
if (this.id != null) obj.id = this.id;
|
|
36
|
+
if (this.version != null) obj.version = this.version;
|
|
37
|
+
if (this.clause != null) obj.clause = this.clause;
|
|
38
|
+
if (this.link != null) obj.link = this.link;
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static fromJSON(data) {
|
|
43
|
+
return new Citation(data);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export const DATE_TYPES = Object.freeze([
|
|
4
|
+
'accepted', 'amended', 'published', 'withdrawn', 'created',
|
|
5
|
+
]);
|
|
6
|
+
|
|
7
|
+
export class ConceptDate extends GlossaristModel {
|
|
8
|
+
constructor(data = {}) {
|
|
9
|
+
super();
|
|
10
|
+
this.date = data.date ?? null;
|
|
11
|
+
this.type = data.type ?? null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get parsedDate() {
|
|
15
|
+
return this.date ? new Date(this.date) : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
toJSON() {
|
|
19
|
+
const obj = {};
|
|
20
|
+
if (this.date != null) obj.date = this.date;
|
|
21
|
+
if (this.type != null) obj.type = this.type;
|
|
22
|
+
return obj;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static fromJSON(data) {
|
|
26
|
+
return new ConceptDate(data);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { Citation } from './citation.js';
|
|
3
|
+
|
|
4
|
+
export class ConceptSource extends GlossaristModel {
|
|
5
|
+
constructor(data = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.status = data.status ?? null;
|
|
8
|
+
this.type = data.type ?? null;
|
|
9
|
+
this.origin = data.origin
|
|
10
|
+
? (data.origin instanceof Citation ? data.origin : new Citation(data.origin))
|
|
11
|
+
: null;
|
|
12
|
+
this.modification = data.modification ?? null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
toJSON() {
|
|
16
|
+
const obj = {};
|
|
17
|
+
if (this.status != null) obj.status = this.status;
|
|
18
|
+
if (this.type != null) obj.type = this.type;
|
|
19
|
+
if (this.origin != null) obj.origin = this.origin.toJSON();
|
|
20
|
+
if (this.modification != null) obj.modification = this.modification;
|
|
21
|
+
return obj;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static fromJSON(data) {
|
|
25
|
+
return new ConceptSource(data);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { LocalizedConcept } from './localized-concept.js';
|
|
3
|
+
import { RelatedConcept } from './related-concept.js';
|
|
4
|
+
import { ConceptDate } from './concept-date.js';
|
|
5
|
+
import { ConceptSource } from './concept-source.js';
|
|
6
|
+
|
|
7
|
+
export class Concept extends GlossaristModel {
|
|
8
|
+
constructor(data = {}) {
|
|
9
|
+
super();
|
|
10
|
+
this.id = String(data.id ?? data.termid ?? '');
|
|
11
|
+
this.term = data.term ?? null;
|
|
12
|
+
this._rawLocalizations = data.localizations ?? {};
|
|
13
|
+
this._cache = {};
|
|
14
|
+
|
|
15
|
+
this.relatedConcepts = _mapInstances(data.relatedConcepts ?? data.related_concepts ?? [], RelatedConcept);
|
|
16
|
+
this.dates = _mapInstances(data.dates ?? [], ConceptDate);
|
|
17
|
+
this.sources = _mapInstances(data.sources ?? [], ConceptSource);
|
|
18
|
+
this.status = data.status ?? null;
|
|
19
|
+
this.raw = data.raw ?? null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get termid() { return this.id; }
|
|
23
|
+
|
|
24
|
+
get languages() {
|
|
25
|
+
return Object.keys(this._rawLocalizations);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get localizations() {
|
|
29
|
+
return this._rawLocalizations;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
localization(lang) {
|
|
33
|
+
if (!(lang in this._rawLocalizations)) return undefined;
|
|
34
|
+
if (!this._cache[lang]) {
|
|
35
|
+
const raw = this._rawLocalizations[lang];
|
|
36
|
+
this._cache[lang] = new LocalizedConcept({ ...raw, language_code: lang });
|
|
37
|
+
}
|
|
38
|
+
return this._cache[lang];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
primaryDesignation(lang) {
|
|
42
|
+
return this.localization(lang)?.primaryDesignation ?? null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
definition(lang) {
|
|
46
|
+
return this.localization(lang)?.primaryDefinition ?? null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setLocalization(lang, lc) {
|
|
50
|
+
if (lc instanceof LocalizedConcept) {
|
|
51
|
+
this._cache[lang] = lc;
|
|
52
|
+
const json = lc.toJSON();
|
|
53
|
+
delete json.language_code;
|
|
54
|
+
this._rawLocalizations[lang] = json;
|
|
55
|
+
} else {
|
|
56
|
+
this._rawLocalizations[lang] = lc;
|
|
57
|
+
delete this._cache[lang];
|
|
58
|
+
}
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
hasLocalization(lang) {
|
|
63
|
+
return lang in this._rawLocalizations;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
toJSON() {
|
|
67
|
+
const obj = { id: this.id };
|
|
68
|
+
if (this.term != null) obj.term = this.term;
|
|
69
|
+
|
|
70
|
+
if (Object.keys(this._rawLocalizations).length > 0) {
|
|
71
|
+
obj.localizations = {};
|
|
72
|
+
for (const lang of this.languages) {
|
|
73
|
+
const lc = this.localization(lang);
|
|
74
|
+
if (lc) {
|
|
75
|
+
const json = lc.toJSON();
|
|
76
|
+
delete json.language_code;
|
|
77
|
+
obj.localizations[lang] = json;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
obj.localizations = {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (this.relatedConcepts.length > 0) {
|
|
85
|
+
obj.relatedConcepts = this.relatedConcepts.map(rc => rc.toJSON());
|
|
86
|
+
}
|
|
87
|
+
if (this.dates.length > 0) {
|
|
88
|
+
obj.dates = this.dates.map(d => d.toJSON());
|
|
89
|
+
}
|
|
90
|
+
if (this.sources.length > 0) {
|
|
91
|
+
obj.sources = this.sources.map(s => s.toJSON());
|
|
92
|
+
}
|
|
93
|
+
if (this.status != null) obj.status = this.status;
|
|
94
|
+
return obj;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static fromJSON(data) {
|
|
98
|
+
return new Concept(data);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function _mapInstances(arr, Cls) {
|
|
103
|
+
return arr.map(item => item instanceof Cls ? item : new Cls(item));
|
|
104
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export class Designation extends GlossaristModel {
|
|
4
|
+
static _registry = new Map();
|
|
5
|
+
|
|
6
|
+
static register(type, cls) {
|
|
7
|
+
Designation._registry.set(type, cls);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static fromData(data) {
|
|
11
|
+
if (data instanceof Designation) return data;
|
|
12
|
+
const Cls = Designation._registry.get(data?.type) ?? Designation;
|
|
13
|
+
return new Cls(data);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
constructor(data = {}) {
|
|
17
|
+
super();
|
|
18
|
+
this.designation = data.designation ?? '';
|
|
19
|
+
this.type = data.type ?? 'expression';
|
|
20
|
+
this.normativeStatus = data.normative_status ?? null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
toJSON() {
|
|
24
|
+
const obj = { type: this.type, designation: this.designation };
|
|
25
|
+
if (this.normativeStatus != null) obj.normative_status = this.normativeStatus;
|
|
26
|
+
return obj;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static fromJSON(data) {
|
|
30
|
+
return Designation.fromData(data);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class Expression extends Designation {
|
|
35
|
+
constructor(data = {}) {
|
|
36
|
+
super(data);
|
|
37
|
+
this.gender = data.gender ?? null;
|
|
38
|
+
this.plurality = data.plurality ?? null;
|
|
39
|
+
this.partOfSpeech = data.part_of_speech ?? null;
|
|
40
|
+
this.geographicalArea = data.geographical_area ?? null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toJSON() {
|
|
44
|
+
const obj = super.toJSON();
|
|
45
|
+
if (this.gender != null) obj.gender = this.gender;
|
|
46
|
+
if (this.plurality != null) obj.plurality = this.plurality;
|
|
47
|
+
if (this.partOfSpeech != null) obj.part_of_speech = this.partOfSpeech;
|
|
48
|
+
if (this.geographicalArea != null) obj.geographical_area = this.geographicalArea;
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static fromJSON(data) { return new Expression(data); }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Designation.register('expression', Expression);
|
|
56
|
+
|
|
57
|
+
export class Abbreviation extends Designation {
|
|
58
|
+
static fromJSON(data) { return new Abbreviation(data); }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Designation.register('abbreviation', Abbreviation);
|
|
62
|
+
|
|
63
|
+
export class Symbol extends Designation {
|
|
64
|
+
constructor(data = {}) {
|
|
65
|
+
super(data);
|
|
66
|
+
this.international = data.international ?? null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
toJSON() {
|
|
70
|
+
const obj = super.toJSON();
|
|
71
|
+
if (this.international != null) obj.international = this.international;
|
|
72
|
+
return obj;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static fromJSON(data) { return new Symbol(data); }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Designation.register('symbol', Symbol);
|
|
79
|
+
|
|
80
|
+
export class GraphicalSymbol extends Designation {
|
|
81
|
+
constructor(data = {}) {
|
|
82
|
+
super(data);
|
|
83
|
+
this.image = data.image ?? null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
toJSON() {
|
|
87
|
+
const obj = super.toJSON();
|
|
88
|
+
if (this.image != null) obj.image = this.image;
|
|
89
|
+
return obj;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static fromJSON(data) { return new GraphicalSymbol(data); }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
Designation.register('graphical symbol', GraphicalSymbol);
|
|
96
|
+
Designation.register('graphical_symbol', GraphicalSymbol);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { Citation } from './citation.js';
|
|
3
|
+
|
|
4
|
+
export class DetailedDefinition extends GlossaristModel {
|
|
5
|
+
constructor(data = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.content = data.content ?? '';
|
|
8
|
+
this.sources = (data.sources ?? []).map(
|
|
9
|
+
s => s instanceof Citation ? s : new Citation(s)
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
toJSON() {
|
|
14
|
+
const obj = { content: this.content };
|
|
15
|
+
if (this.sources.length > 0) {
|
|
16
|
+
obj.sources = this.sources.map(s => s.toJSON());
|
|
17
|
+
}
|
|
18
|
+
return obj;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static fromJSON(data) {
|
|
22
|
+
return new DetailedDefinition(data);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
export class GlossaristModel {
|
|
2
|
+
toJSON(): Record<string, unknown>;
|
|
3
|
+
static fromJSON(data: Record<string, unknown>): GlossaristModel;
|
|
4
|
+
equals(other: GlossaristModel): boolean;
|
|
5
|
+
clone(): GlossaristModel;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class Concept extends GlossaristModel {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly term: string | null;
|
|
11
|
+
readonly termid: string;
|
|
12
|
+
readonly languages: string[];
|
|
13
|
+
readonly localizations: Record<string, any>;
|
|
14
|
+
readonly raw: Record<string, unknown> | null;
|
|
15
|
+
readonly relatedConcepts: RelatedConcept[];
|
|
16
|
+
readonly dates: ConceptDate[];
|
|
17
|
+
readonly sources: ConceptSource[];
|
|
18
|
+
readonly status: string | null;
|
|
19
|
+
|
|
20
|
+
localization(lang: string): LocalizedConcept | undefined;
|
|
21
|
+
primaryDesignation(lang: string): string | null;
|
|
22
|
+
definition(lang: string): string | null;
|
|
23
|
+
setLocalization(lang: string, lc: LocalizedConcept | Record<string, unknown>): this;
|
|
24
|
+
hasLocalization(lang: string): boolean;
|
|
25
|
+
static fromJSON(data: Record<string, unknown>): Concept;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class LocalizedConcept extends GlossaristModel {
|
|
29
|
+
readonly languageCode: string | null;
|
|
30
|
+
readonly terms: Designation[];
|
|
31
|
+
readonly definitions: DetailedDefinition[];
|
|
32
|
+
readonly definition: DetailedDefinition[];
|
|
33
|
+
readonly notes: { content: string }[];
|
|
34
|
+
readonly examples: { content: string }[];
|
|
35
|
+
readonly sources: ConceptSource[];
|
|
36
|
+
readonly entryStatus: string | null;
|
|
37
|
+
readonly primaryDesignation: string | null;
|
|
38
|
+
readonly primaryDefinition: string | null;
|
|
39
|
+
static fromJSON(data: Record<string, unknown>): LocalizedConcept;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class Designation extends GlossaristModel {
|
|
43
|
+
readonly designation: string;
|
|
44
|
+
readonly type: string;
|
|
45
|
+
readonly normativeStatus: string | null;
|
|
46
|
+
static register(type: string, cls: typeof Designation): void;
|
|
47
|
+
static fromData(data: Record<string, unknown>): Designation;
|
|
48
|
+
static fromJSON(data: Record<string, unknown>): Designation;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class Expression extends Designation {
|
|
52
|
+
readonly gender: string | null;
|
|
53
|
+
readonly plurality: string | null;
|
|
54
|
+
readonly partOfSpeech: string | null;
|
|
55
|
+
readonly geographicalArea: string | null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class Abbreviation extends Designation {}
|
|
59
|
+
export class Symbol extends Designation {
|
|
60
|
+
readonly international: string | null;
|
|
61
|
+
}
|
|
62
|
+
export class GraphicalSymbol extends Designation {
|
|
63
|
+
readonly image: string | null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class Citation extends GlossaristModel {
|
|
67
|
+
readonly source: string | Record<string, unknown> | null;
|
|
68
|
+
readonly ref: string | null;
|
|
69
|
+
readonly id: string | null;
|
|
70
|
+
readonly version: string | null;
|
|
71
|
+
readonly clause: string | null;
|
|
72
|
+
readonly link: string | null;
|
|
73
|
+
toString(): string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class ConceptSource extends GlossaristModel {
|
|
77
|
+
readonly status: string | null;
|
|
78
|
+
readonly type: string | null;
|
|
79
|
+
readonly origin: Citation | null;
|
|
80
|
+
readonly modification: string | null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const RELATIONSHIP_TYPES: readonly string[];
|
|
84
|
+
export class RelatedConcept extends GlossaristModel {
|
|
85
|
+
readonly type: string;
|
|
86
|
+
readonly content: string | null;
|
|
87
|
+
readonly ref: Citation | null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const DATE_TYPES: readonly string[];
|
|
91
|
+
export class ConceptDate extends GlossaristModel {
|
|
92
|
+
readonly date: string | null;
|
|
93
|
+
readonly type: string | null;
|
|
94
|
+
readonly parsedDate: Date | null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class DetailedDefinition extends GlossaristModel {
|
|
98
|
+
readonly content: string;
|
|
99
|
+
readonly sources: Citation[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class NonVerbRep extends GlossaristModel {
|
|
103
|
+
readonly image: string | null;
|
|
104
|
+
readonly table: string | null;
|
|
105
|
+
readonly formula: string | null;
|
|
106
|
+
readonly sources: Citation[];
|
|
107
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { GlossaristModel } from './base.js';
|
|
2
|
+
export { Concept } from './concept.js';
|
|
3
|
+
export { LocalizedConcept } from './localized-concept.js';
|
|
4
|
+
export { Designation, Expression, Abbreviation, Symbol, GraphicalSymbol } from './designation.js';
|
|
5
|
+
export { Citation } from './citation.js';
|
|
6
|
+
export { ConceptSource } from './concept-source.js';
|
|
7
|
+
export { RelatedConcept, RELATIONSHIP_TYPES } from './related-concept.js';
|
|
8
|
+
export { ConceptDate, DATE_TYPES } from './concept-date.js';
|
|
9
|
+
export { DetailedDefinition } from './detailed-definition.js';
|
|
10
|
+
export { NonVerbRep } from './non-verb-rep.js';
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { Designation } from './designation.js';
|
|
3
|
+
import { DetailedDefinition } from './detailed-definition.js';
|
|
4
|
+
import { ConceptSource } from './concept-source.js';
|
|
5
|
+
|
|
6
|
+
export class LocalizedConcept extends GlossaristModel {
|
|
7
|
+
constructor(data = {}) {
|
|
8
|
+
super();
|
|
9
|
+
this.languageCode = data.language_code ?? data.languageCode ?? null;
|
|
10
|
+
this._rawTerms = data.terms ?? [];
|
|
11
|
+
this._rawDefinition = data.definition ?? [];
|
|
12
|
+
this._rawSources = data.sources ?? [];
|
|
13
|
+
this.notes = data.notes ?? [];
|
|
14
|
+
this.examples = data.examples ?? [];
|
|
15
|
+
this.entryStatus = data.entry_status ?? data.entryStatus ?? null;
|
|
16
|
+
this.reviewType = data.review_type ?? data.reviewType ?? null;
|
|
17
|
+
this.classification = data.classification ?? null;
|
|
18
|
+
|
|
19
|
+
this._terms = null;
|
|
20
|
+
this._definitions = null;
|
|
21
|
+
this._sources = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get terms() {
|
|
25
|
+
if (this._terms === null) {
|
|
26
|
+
this._terms = this._rawTerms.map(t => Designation.fromData(t));
|
|
27
|
+
}
|
|
28
|
+
return this._terms;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get definitions() {
|
|
32
|
+
if (this._definitions === null) {
|
|
33
|
+
this._definitions = this._rawDefinition.map(
|
|
34
|
+
d => d instanceof DetailedDefinition ? d : new DetailedDefinition(d)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return this._definitions;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get definition() {
|
|
41
|
+
return this.definitions;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get sources() {
|
|
45
|
+
if (this._sources === null) {
|
|
46
|
+
this._sources = this._rawSources.map(
|
|
47
|
+
s => s instanceof ConceptSource ? s : new ConceptSource(s)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return this._sources;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get primaryDesignation() {
|
|
54
|
+
return this.terms[0]?.designation ?? null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get primaryDefinition() {
|
|
58
|
+
return this.definitions[0]?.content ?? null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
toJSON() {
|
|
62
|
+
const obj = {};
|
|
63
|
+
if (this.languageCode) obj.language_code = this.languageCode;
|
|
64
|
+
|
|
65
|
+
const terms = this._terms ?? this._rawTerms;
|
|
66
|
+
if (terms.length > 0) {
|
|
67
|
+
obj.terms = terms.map(t => (typeof t.toJSON === 'function') ? t.toJSON() : t);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const defs = this._definitions ?? (this._rawDefinition.length > 0 ? this._rawDefinition : []);
|
|
71
|
+
if (defs.length > 0) {
|
|
72
|
+
obj.definition = defs.map(d => (typeof d.toJSON === 'function') ? d.toJSON() : d);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.notes.length > 0) obj.notes = this.notes;
|
|
76
|
+
if (this.examples.length > 0) obj.examples = this.examples;
|
|
77
|
+
|
|
78
|
+
const sources = this._sources ?? (this._rawSources.length > 0 ? this._rawSources : []);
|
|
79
|
+
if (sources.length > 0) {
|
|
80
|
+
obj.sources = sources.map(s => (typeof s.toJSON === 'function') ? s.toJSON() : s);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (this.entryStatus != null) obj.entry_status = this.entryStatus;
|
|
84
|
+
if (this.reviewType != null) obj.review_type = this.reviewType;
|
|
85
|
+
if (this.classification != null) obj.classification = this.classification;
|
|
86
|
+
return obj;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static fromJSON(data) {
|
|
90
|
+
return new LocalizedConcept(data);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { Citation } from './citation.js';
|
|
3
|
+
|
|
4
|
+
export class NonVerbRep extends GlossaristModel {
|
|
5
|
+
constructor(data = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.image = data.image ?? null;
|
|
8
|
+
this.table = data.table ?? null;
|
|
9
|
+
this.formula = data.formula ?? null;
|
|
10
|
+
this.sources = (data.sources ?? []).map(
|
|
11
|
+
s => s instanceof Citation ? s : new Citation(s)
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
toJSON() {
|
|
16
|
+
const obj = {};
|
|
17
|
+
if (this.image != null) obj.image = this.image;
|
|
18
|
+
if (this.table != null) obj.table = this.table;
|
|
19
|
+
if (this.formula != null) obj.formula = this.formula;
|
|
20
|
+
if (this.sources.length > 0) obj.sources = this.sources.map(s => s.toJSON());
|
|
21
|
+
return obj;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static fromJSON(data) {
|
|
25
|
+
return new NonVerbRep(data);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
import { Citation } from './citation.js';
|
|
3
|
+
|
|
4
|
+
export const RELATIONSHIP_TYPES = Object.freeze([
|
|
5
|
+
'supersedes', 'superseded_by', 'extends', 'extended_by',
|
|
6
|
+
'narrower', 'broader', 'equivalent', 'compare', 'contrast',
|
|
7
|
+
'derived', 'deprecated', 'related',
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
export class RelatedConcept extends GlossaristModel {
|
|
11
|
+
constructor(data = {}) {
|
|
12
|
+
super();
|
|
13
|
+
this.type = data.type ?? 'related';
|
|
14
|
+
this.content = data.content ?? null;
|
|
15
|
+
this.ref = data.ref
|
|
16
|
+
? (data.ref instanceof Citation ? data.ref : new Citation(data.ref))
|
|
17
|
+
: null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toJSON() {
|
|
21
|
+
const obj = { type: this.type };
|
|
22
|
+
if (this.content != null) obj.content = this.content;
|
|
23
|
+
if (this.ref != null) obj.ref = this.ref.toJSON();
|
|
24
|
+
return obj;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static fromJSON(data) {
|
|
28
|
+
return new RelatedConcept(data);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export class Reference {
|
|
2
|
+
constructor(type, target, relationship, source) {
|
|
3
|
+
this.type = type;
|
|
4
|
+
this.target = target;
|
|
5
|
+
this.relationship = relationship ?? null;
|
|
6
|
+
this.source = source ?? null;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ReferenceResolver {
|
|
11
|
+
extractReferences(concept) {
|
|
12
|
+
const refs = [];
|
|
13
|
+
|
|
14
|
+
for (const rc of concept.relatedConcepts) {
|
|
15
|
+
const target = rc.content ?? rc.ref?.toString() ?? '';
|
|
16
|
+
if (target) {
|
|
17
|
+
refs.push(new Reference('concept', target, rc.type, 'relatedConcepts'));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const lang of concept.languages) {
|
|
22
|
+
const lc = concept.localization(lang);
|
|
23
|
+
if (!lc) continue;
|
|
24
|
+
|
|
25
|
+
if (lc.sources) {
|
|
26
|
+
for (let i = 0; i < lc.sources.length; i++) {
|
|
27
|
+
const src = lc.sources[i];
|
|
28
|
+
const ref = src.origin?.toString() ?? '';
|
|
29
|
+
if (ref) {
|
|
30
|
+
refs.push(new Reference('standard', ref, src.type, `localizations.${lang}.sources[${i}]`));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const texts = [
|
|
36
|
+
...(lc.definitions?.map(d => d.content ?? '') ?? []),
|
|
37
|
+
...(lc.notes?.map(n => typeof n === 'object' ? (n.content ?? '') : String(n)) ?? []),
|
|
38
|
+
];
|
|
39
|
+
for (const text of texts) {
|
|
40
|
+
refs.push(..._extractEmbedded(text));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return refs;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
resolveReference(ref, collection) {
|
|
48
|
+
if (ref.type !== 'concept') return null;
|
|
49
|
+
return collection.byId(ref.target);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
resolveAll(concept, collection) {
|
|
53
|
+
const resolved = new Map();
|
|
54
|
+
for (const ref of this.extractReferences(concept)) {
|
|
55
|
+
if (ref.type === 'concept') {
|
|
56
|
+
resolved.set(ref.target, this.resolveReference(ref, collection));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return resolved;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const CONCEPT_REF_RE = /\{\{([^}]+)\}\}|\b(\d+(?:\.\d+)+)\b/g;
|
|
64
|
+
|
|
65
|
+
function _extractEmbedded(text) {
|
|
66
|
+
const refs = [];
|
|
67
|
+
let m;
|
|
68
|
+
CONCEPT_REF_RE.lastIndex = 0;
|
|
69
|
+
while ((m = CONCEPT_REF_RE.exec(text)) !== null) {
|
|
70
|
+
const target = m[1] ?? m[2];
|
|
71
|
+
if (target && /^\d+(\.\d+)+$/.test(target)) {
|
|
72
|
+
refs.push(new Reference('concept', target, 'embedded', null));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return refs;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const referenceResolver = new ReferenceResolver();
|