glossarist 0.3.8 → 0.4.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/package.json +1 -1
- package/src/concept-collection.js +3 -11
- package/src/concept-parser.js +7 -1
- package/src/dataset-asset.js +3 -0
- package/src/entity-directory.js +43 -0
- package/src/gcr-reader.js +53 -5
- package/src/gcr-writer.js +3 -1
- package/src/index.d.ts +40 -7
- package/src/index.js +19 -2
- package/src/managed-concept-collection.js +11 -2
- package/src/models/bibliography-data.js +43 -0
- package/src/models/bibliography-entry.js +26 -0
- package/src/models/concept.js +44 -0
- package/src/models/designation.js +2 -14
- package/src/models/detailed-definition.js +30 -6
- package/src/models/figure.js +71 -0
- package/src/models/formula.js +21 -0
- package/src/models/index.d.ts +5 -0
- package/src/models/index.js +12 -1
- package/src/models/localized-concept.js +21 -0
- package/src/models/localized-string.js +19 -0
- package/src/models/non-verb-rep.js +15 -13
- package/src/models/non-verbal-entity.js +39 -0
- package/src/models/non-verbal-reference.js +35 -0
- package/src/models/non-verbal-references.js +16 -0
- package/src/models/registrable.js +25 -0
- package/src/models/shared-non-verbal-entity.js +28 -0
- package/src/models/table.js +21 -0
- package/src/reference-mention.js +19 -3
- package/src/reference-resolver.js +77 -31
- package/src/render-classification.js +10 -1
- package/src/validators/asset-index.js +66 -0
- package/src/validators/index.js +5 -1
- package/src/validators/v3-rules.js +132 -24
package/package.json
CHANGED
|
@@ -86,22 +86,14 @@ export class ConceptCollection {
|
|
|
86
86
|
for (const t of lc.terms) {
|
|
87
87
|
if ((t.designation ?? '').toLowerCase().includes(q)) return true;
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (
|
|
92
|
-
if (this._searchDefs(lc.annotations, q)) return true;
|
|
89
|
+
}
|
|
90
|
+
for (const { text } of c.walkTexts()) {
|
|
91
|
+
if (text.toLowerCase().includes(q)) return true;
|
|
93
92
|
}
|
|
94
93
|
return false;
|
|
95
94
|
}));
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
_searchDefs(arr, q) {
|
|
99
|
-
for (const d of arr) {
|
|
100
|
-
if ((d.content ?? '').toLowerCase().includes(q)) return true;
|
|
101
|
-
}
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
97
|
allLanguages() {
|
|
106
98
|
const set = new Set();
|
|
107
99
|
for (const c of this[_items]) {
|
package/src/concept-parser.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Concept } from './models/concept.js';
|
|
|
3
3
|
import { RelatedConcept } from './models/related-concept.js';
|
|
4
4
|
import { InvalidInputError, YamlParseError } from './errors.js';
|
|
5
5
|
|
|
6
|
-
const STRUCTURAL_KEYS = new Set(['termid', 'term']);
|
|
6
|
+
const STRUCTURAL_KEYS = new Set(['termid', 'term', 'figures', 'tables', 'formulas']);
|
|
7
7
|
|
|
8
8
|
export class ConceptParser {
|
|
9
9
|
parse(raw, context) {
|
|
@@ -51,6 +51,9 @@ export class ConceptParser {
|
|
|
51
51
|
id: String(doc.termid),
|
|
52
52
|
term: doc.term || null,
|
|
53
53
|
localizations,
|
|
54
|
+
figures: doc.figures,
|
|
55
|
+
tables: doc.tables,
|
|
56
|
+
formulas: doc.formulas,
|
|
54
57
|
raw: doc,
|
|
55
58
|
});
|
|
56
59
|
}
|
|
@@ -76,6 +79,9 @@ export class ConceptParser {
|
|
|
76
79
|
groups: mc.data.groups,
|
|
77
80
|
dates: mc.dates ?? mc.data?.dates,
|
|
78
81
|
sources: mc.sources ?? mc.data?.sources,
|
|
82
|
+
figures: mc.data?.figures,
|
|
83
|
+
tables: mc.data?.tables,
|
|
84
|
+
formulas: mc.data?.formulas,
|
|
79
85
|
status: mc.status,
|
|
80
86
|
schemaVersion: mc.schema_version,
|
|
81
87
|
raw: mc,
|
package/src/dataset-asset.js
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
const DATASET_ASSETS = Object.freeze([
|
|
13
13
|
{ path: 'bibliography.yaml', type: 'file' },
|
|
14
14
|
{ path: 'images', type: 'directory' },
|
|
15
|
+
{ path: 'figures', type: 'directory' },
|
|
16
|
+
{ path: 'tables', type: 'directory' },
|
|
17
|
+
{ path: 'formulas', type: 'directory' },
|
|
15
18
|
]);
|
|
16
19
|
|
|
17
20
|
const FILE_ASSETS = Object.freeze(
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const ENTITY_DIRECTORIES = Object.freeze(new Map([
|
|
2
|
+
['figure', 'figures'],
|
|
3
|
+
['table', 'tables'],
|
|
4
|
+
['formula', 'formulas'],
|
|
5
|
+
]));
|
|
6
|
+
|
|
7
|
+
const ENTITY_TYPES = Object.freeze([...ENTITY_DIRECTORIES.keys()]);
|
|
8
|
+
|
|
9
|
+
function entityDir(type) {
|
|
10
|
+
const dir = ENTITY_DIRECTORIES.get(type);
|
|
11
|
+
if (!dir) throw new RangeError(`Unknown entity type: ${type}`);
|
|
12
|
+
return dir;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function entityPath(type, id) {
|
|
16
|
+
return `${entityDir(type)}/${id}.yaml`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isKnownEntityType(type) {
|
|
20
|
+
return ENTITY_DIRECTORIES.has(type);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function parseEntityPath(zipPath) {
|
|
24
|
+
for (const [type, dir] of ENTITY_DIRECTORIES) {
|
|
25
|
+
const prefix = `${dir}/`;
|
|
26
|
+
if (!zipPath.startsWith(prefix)) continue;
|
|
27
|
+
const filename = zipPath.slice(prefix.length);
|
|
28
|
+
if (!filename.endsWith('.yaml')) continue;
|
|
29
|
+
const id = filename.slice(0, -'.yaml'.length);
|
|
30
|
+
if (!id) continue;
|
|
31
|
+
return { type, id };
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
ENTITY_DIRECTORIES,
|
|
38
|
+
ENTITY_TYPES,
|
|
39
|
+
entityDir,
|
|
40
|
+
entityPath,
|
|
41
|
+
isKnownEntityType,
|
|
42
|
+
parseEntityPath,
|
|
43
|
+
};
|
package/src/gcr-reader.js
CHANGED
|
@@ -6,6 +6,9 @@ import { COMPILED_FORMATS, parseCompiledPath, compiledPath } from './compiled-fo
|
|
|
6
6
|
import { DATASET_ASSETS, findFileAsset, findDirectoryAssetPath } from './dataset-asset.js';
|
|
7
7
|
import { GcrMetadata } from './models/gcr-metadata.js';
|
|
8
8
|
import { naturalSort } from './sort.js';
|
|
9
|
+
import { NonVerbalEntity } from './models/non-verbal-entity.js';
|
|
10
|
+
import { BibliographyData } from './models/bibliography-data.js';
|
|
11
|
+
import { entityDir, entityPath, ENTITY_TYPES, parseEntityPath } from './entity-directory.js';
|
|
9
12
|
|
|
10
13
|
export { naturalSort } from './sort.js';
|
|
11
14
|
|
|
@@ -34,7 +37,7 @@ const BASE64_RE = /^[A-Za-z0-9+/]{100,}={0,2}$/;
|
|
|
34
37
|
* @property {Term[]} terms - term designations
|
|
35
38
|
* @property {Definition[]} [definition] - definition content
|
|
36
39
|
* @property {{ content: string }[]} [notes] - editorial notes
|
|
37
|
-
* @property {{ content: string
|
|
40
|
+
* @property {Array<{ content: string, examples?: object[], sources?: object[] }>} [examples] - usage examples (may themselves nest examples)
|
|
38
41
|
* @property {Source[]} [sources] - bibliographic sources
|
|
39
42
|
* @property {string} [entry_status] - e.g. 'valid', 'draft'
|
|
40
43
|
* @property {string} [normative_status] - e.g. 'preferred', 'admitted'
|
|
@@ -283,12 +286,13 @@ export class GcrPackage {
|
|
|
283
286
|
}
|
|
284
287
|
|
|
285
288
|
/**
|
|
286
|
-
* Read bibliography.yaml from the package as a
|
|
287
|
-
* @returns {Promise<
|
|
289
|
+
* Read and parse bibliography.yaml from the package as a BibliographyData instance.
|
|
290
|
+
* @returns {Promise<BibliographyData | null>}
|
|
288
291
|
*/
|
|
289
292
|
async bibliography() {
|
|
290
|
-
const
|
|
291
|
-
|
|
293
|
+
const raw = await this._readText('bibliography.yaml');
|
|
294
|
+
if (raw === null) return null;
|
|
295
|
+
return BibliographyData.fromYAML(raw);
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
/**
|
|
@@ -403,6 +407,50 @@ export class GcrPackage {
|
|
|
403
407
|
async _readText(filePath) {
|
|
404
408
|
return this.readText(filePath);
|
|
405
409
|
}
|
|
410
|
+
|
|
411
|
+
// --- Non-verbal entity directories (figures/, tables/, formulas/) ---
|
|
412
|
+
|
|
413
|
+
async entityIds(type) {
|
|
414
|
+
const prefix = `${entityDir(type)}/`;
|
|
415
|
+
const ids = [];
|
|
416
|
+
this._zip.forEach((relativePath, entry) => {
|
|
417
|
+
if (!entry.dir && relativePath.startsWith(prefix) && relativePath.endsWith('.yaml')) {
|
|
418
|
+
ids.push(relativePath.slice(prefix.length, -'.yaml'.length));
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
return ids.sort(naturalSort);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async entity(type, id) {
|
|
425
|
+
const raw = await this.readText(entityPath(type, id));
|
|
426
|
+
if (raw === null) return null;
|
|
427
|
+
const yamlData = yaml.load(raw);
|
|
428
|
+
return NonVerbalEntity.fromData({ ...yamlData, type });
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async eachEntity(type, callback) {
|
|
432
|
+
for (const id of await this.entityIds(type)) {
|
|
433
|
+
const entity = await this.entity(type, id);
|
|
434
|
+
if (entity) await callback(entity, id);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async allEntities(type) {
|
|
439
|
+
const entities = [];
|
|
440
|
+
await this.eachEntity(type, (e) => { entities.push(e); });
|
|
441
|
+
return entities;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async entityTypes() {
|
|
445
|
+
const seen = new Set();
|
|
446
|
+
this._zip.forEach((relativePath, entry) => {
|
|
447
|
+
if (!entry.dir) {
|
|
448
|
+
const parsed = parseEntityPath(relativePath);
|
|
449
|
+
if (parsed) seen.add(parsed.type);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
return ENTITY_TYPES.filter((t) => seen.has(t));
|
|
453
|
+
}
|
|
406
454
|
}
|
|
407
455
|
|
|
408
456
|
// --- Concept YAML parsing ---
|
package/src/gcr-writer.js
CHANGED
|
@@ -38,7 +38,9 @@ export class GcrWriter {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if (options.bibliography) {
|
|
41
|
-
|
|
41
|
+
const bib = options.bibliography;
|
|
42
|
+
const yamlStr = bib.toYAML ? bib.toYAML() : String(bib);
|
|
43
|
+
zip.file('bibliography.yaml', yamlStr);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
if (options.images) {
|
package/src/index.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
// Models
|
|
2
2
|
export {
|
|
3
3
|
GlossaristModel,
|
|
4
|
+
RegistrableModel,
|
|
4
5
|
Concept, LocalizedConcept,
|
|
5
|
-
Designation, Expression, Abbreviation, Symbol, GraphicalSymbol,
|
|
6
|
-
Citation, ConceptRef, ConceptSource, RelatedConcept,
|
|
7
|
-
|
|
6
|
+
Designation, Expression, Abbreviation, Symbol, LetterSymbol, GraphicalSymbol,
|
|
7
|
+
Citation, ConceptRef, ConceptSource, RelatedConcept,
|
|
8
|
+
DesignationRelationship, ConceptReference, ConceptDate,
|
|
9
|
+
DetailedDefinition, NonVerbRep, NON_VERBAL_TYPES,
|
|
10
|
+
NonVerbalEntity, SharedNonVerbalEntity,
|
|
11
|
+
Figure, FigureImage, Table, Formula,
|
|
12
|
+
NonVerbalReference, FigureReference, TableReference, FormulaReference,
|
|
13
|
+
BibliographyEntry, BibliographyData,
|
|
8
14
|
GcrMetadata, GcrStatistics,
|
|
9
|
-
RELATIONSHIP_TYPES, DATE_TYPES,
|
|
15
|
+
RELATIONSHIP_TYPES, DESIGNATION_RELATIONSHIP_TYPES, DATE_TYPES,
|
|
10
16
|
} from './models/index';
|
|
11
17
|
|
|
12
18
|
// GCR reader
|
|
@@ -26,16 +32,27 @@ export { ConceptCollection } from './concept-collection';
|
|
|
26
32
|
export { ManagedConceptCollection } from './managed-concept-collection';
|
|
27
33
|
|
|
28
34
|
// Validators
|
|
29
|
-
export {
|
|
35
|
+
export {
|
|
36
|
+
validateConcept, validateRegister, validateGcrPackage,
|
|
37
|
+
createConceptValidator,
|
|
38
|
+
ValidationError, ValidationRule, ValidationResult,
|
|
39
|
+
RegisterValidator, GcrValidator,
|
|
40
|
+
NonVerbalRefIntegrityRule, OrphanedImagesRule,
|
|
41
|
+
} from './validators/index';
|
|
42
|
+
export { AssetIndex } from './validators/asset-index';
|
|
30
43
|
|
|
31
44
|
// UUID
|
|
32
45
|
export { conceptUuid, localizedConceptUuid, uuidV5 } from './uuid';
|
|
33
46
|
|
|
34
47
|
// Reference resolution
|
|
35
|
-
export {
|
|
48
|
+
export {
|
|
49
|
+
ReferenceResolver, Reference, referenceResolver,
|
|
50
|
+
resolveBibliographyRecord, findNonVerbalEntity,
|
|
51
|
+
} from './reference-resolver';
|
|
36
52
|
|
|
37
53
|
export type MentionParseResult = {
|
|
38
|
-
kind: 'cite-ref' | 'urn-ref' | '
|
|
54
|
+
kind: 'cite-ref' | 'urn-ref' | 'fig-ref' | 'table-ref' | 'formula-ref'
|
|
55
|
+
| 'numeric' | 'designation' | 'unresolved';
|
|
39
56
|
key?: string;
|
|
40
57
|
uri?: string;
|
|
41
58
|
label?: string | null;
|
|
@@ -45,6 +62,14 @@ export type MentionParseResult = {
|
|
|
45
62
|
|
|
46
63
|
export function parseMention(raw: string): MentionParseResult;
|
|
47
64
|
|
|
65
|
+
export function fetchLocalizedString(
|
|
66
|
+
hash: Record<string, string> | null,
|
|
67
|
+
lang: string,
|
|
68
|
+
fallback?: string,
|
|
69
|
+
): string | null;
|
|
70
|
+
export function localizedStringIsEmpty(hash: Record<string, string> | null): boolean;
|
|
71
|
+
export function localizedStringIsPresent(hash: Record<string, string> | null): boolean;
|
|
72
|
+
|
|
48
73
|
// V1 support
|
|
49
74
|
export { V1Reader, migrateV1ToV2 } from './v1-reader';
|
|
50
75
|
|
|
@@ -66,3 +91,11 @@ export const DIRECTORY_ASSETS: readonly { path: string; type: string }[];
|
|
|
66
91
|
export function findFileAsset(path: string): { path: string; type: string } | undefined;
|
|
67
92
|
export function findDirectoryAssetPath(zipPath: string): { path: string; type: string } | undefined;
|
|
68
93
|
export function isDatasetAssetPath(zipPath: string): boolean;
|
|
94
|
+
|
|
95
|
+
// Entity directory registry
|
|
96
|
+
export const ENTITY_DIRECTORIES: ReadonlyMap<string, string>;
|
|
97
|
+
export const ENTITY_TYPES: readonly string[];
|
|
98
|
+
export function entityDir(type: string): string;
|
|
99
|
+
export function entityPath(type: string, id: string): string;
|
|
100
|
+
export function isKnownEntityType(type: string): boolean;
|
|
101
|
+
export function parseEntityPath(zipPath: string): { type: string; id: string } | null;
|
package/src/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { ConceptCollection } from './concept-collection.js';
|
|
|
7
7
|
export { ManagedConceptCollection } from './managed-concept-collection.js';
|
|
8
8
|
export { validateConcept, validateRegister, validateGcrPackage, createConceptValidator, ValidationError, ValidationRule, ValidationResult, RegisterValidator, GcrValidator } from './validators/index.js';
|
|
9
9
|
export { conceptUuid, localizedConceptUuid, uuidV5 } from './uuid.js';
|
|
10
|
-
export { ReferenceResolver, Reference, referenceResolver, resolveBibliographyRecord } from './reference-resolver.js';
|
|
10
|
+
export { ReferenceResolver, Reference, referenceResolver, resolveBibliographyRecord, findNonVerbalEntity } from './reference-resolver.js';
|
|
11
11
|
export { parseMention } from './reference-mention.js';
|
|
12
12
|
export { ReferenceClassifier } from './render-classification.js';
|
|
13
13
|
export { V1Reader, migrateV1ToV2 } from './v1-reader.js';
|
|
@@ -30,12 +30,29 @@ export {
|
|
|
30
30
|
|
|
31
31
|
export {
|
|
32
32
|
GlossaristModel,
|
|
33
|
+
RegistrableModel,
|
|
33
34
|
Register, Section,
|
|
34
35
|
REGISTER_STATUSES, ORDERING_METHODS,
|
|
35
36
|
Concept, LocalizedConcept,
|
|
36
37
|
Designation, Expression, Abbreviation, Symbol, GraphicalSymbol,
|
|
37
38
|
Citation, ConceptRef, ConceptSource, RelatedConcept, DesignationRelationship, ConceptReference, ConceptDate,
|
|
38
|
-
DetailedDefinition, NonVerbRep,
|
|
39
|
+
DetailedDefinition, NonVerbRep, NON_VERBAL_TYPES,
|
|
40
|
+
NonVerbalEntity, SharedNonVerbalEntity,
|
|
41
|
+
Figure, FigureImage, Table, Formula,
|
|
42
|
+
NonVerbalReference, FigureReference, TableReference, FormulaReference,
|
|
43
|
+
BibliographyEntry, BibliographyData,
|
|
44
|
+
fetchLocalizedString, localizedStringIsEmpty, localizedStringIsPresent,
|
|
39
45
|
GcrMetadata, GcrStatistics,
|
|
40
46
|
RELATIONSHIP_TYPES, DESIGNATION_RELATIONSHIP_TYPES, DATE_TYPES,
|
|
41
47
|
} from './models/index.js';
|
|
48
|
+
|
|
49
|
+
export { AssetIndex } from './validators/asset-index.js';
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
ENTITY_DIRECTORIES,
|
|
53
|
+
ENTITY_TYPES,
|
|
54
|
+
entityDir,
|
|
55
|
+
entityPath,
|
|
56
|
+
isKnownEntityType,
|
|
57
|
+
parseEntityPath,
|
|
58
|
+
} from './entity-directory.js';
|
|
@@ -3,6 +3,7 @@ import { readConcepts, readRegister } from './concept-reader.js';
|
|
|
3
3
|
import { writeConcepts } from './concept-writer.js';
|
|
4
4
|
import { loadGcr } from './gcr-reader.js';
|
|
5
5
|
import { GcrWriter } from './gcr-writer.js';
|
|
6
|
+
import { BibliographyData } from './models/bibliography-data.js';
|
|
6
7
|
|
|
7
8
|
export class ManagedConceptCollection {
|
|
8
9
|
constructor() {
|
|
@@ -73,8 +74,16 @@ export class ManagedConceptCollection {
|
|
|
73
74
|
return this;
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
setBibliography(
|
|
77
|
-
|
|
77
|
+
setBibliography(bib) {
|
|
78
|
+
if (bib instanceof BibliographyData) {
|
|
79
|
+
this._bibliography = bib;
|
|
80
|
+
} else if (typeof bib === 'string') {
|
|
81
|
+
this._bibliography = BibliographyData.fromYAML(bib);
|
|
82
|
+
} else if (bib == null) {
|
|
83
|
+
this._bibliography = null;
|
|
84
|
+
} else {
|
|
85
|
+
this._bibliography = new BibliographyData(bib);
|
|
86
|
+
}
|
|
78
87
|
return this;
|
|
79
88
|
}
|
|
80
89
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import yaml from 'js-yaml';
|
|
2
|
+
import { GlossaristModel } from './base.js';
|
|
3
|
+
import { BibliographyEntry } from './bibliography-entry.js';
|
|
4
|
+
|
|
5
|
+
export class BibliographyData extends GlossaristModel {
|
|
6
|
+
constructor(data = {}) {
|
|
7
|
+
super();
|
|
8
|
+
const entriesData = data.bibliography ?? data.entries ?? [];
|
|
9
|
+
this._rawEntries = Array.isArray(entriesData) ? entriesData : [];
|
|
10
|
+
this._entries = null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get entries() {
|
|
14
|
+
return this._lazy('_entries', '_rawEntries',
|
|
15
|
+
e => e instanceof BibliographyEntry ? e : new BibliographyEntry(e));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
find(id) {
|
|
19
|
+
return this.entries.find(e => e.id === id) ?? null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get keys() {
|
|
23
|
+
return this.entries.map(e => e.id);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toJSON() {
|
|
27
|
+
if (this.entries.length === 0) return { bibliography: [] };
|
|
28
|
+
return { bibliography: this.entries.map(e => e.toJSON()) };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
toYAML() {
|
|
32
|
+
return yaml.dump(this.toJSON());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static fromYAML(yamlString) {
|
|
36
|
+
const parsed = yaml.load(yamlString);
|
|
37
|
+
return new BibliographyData(parsed ?? {});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static fromJSON(data) {
|
|
41
|
+
return new BibliographyData(data);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { GlossaristModel } from './base.js';
|
|
2
|
+
|
|
3
|
+
export class BibliographyEntry extends GlossaristModel {
|
|
4
|
+
constructor(data = {}) {
|
|
5
|
+
super();
|
|
6
|
+
this.id = data.id ?? null;
|
|
7
|
+
this.reference = data.reference ?? null;
|
|
8
|
+
this.title = data.title ?? null;
|
|
9
|
+
this.link = data.link ?? null;
|
|
10
|
+
this.type = data.type ?? null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
toJSON() {
|
|
14
|
+
const obj = {};
|
|
15
|
+
if (this.id != null) obj.id = this.id;
|
|
16
|
+
if (this.reference != null) obj.reference = this.reference;
|
|
17
|
+
if (this.title != null) obj.title = this.title;
|
|
18
|
+
if (this.link != null) obj.link = this.link;
|
|
19
|
+
if (this.type != null) obj.type = this.type;
|
|
20
|
+
return obj;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static fromJSON(data) {
|
|
24
|
+
return new BibliographyEntry(data);
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/models/concept.js
CHANGED
|
@@ -4,6 +4,9 @@ import { RelatedConcept } from './related-concept.js';
|
|
|
4
4
|
import { ConceptReference } from './concept-reference.js';
|
|
5
5
|
import { ConceptDate } from './concept-date.js';
|
|
6
6
|
import { ConceptSource } from './concept-source.js';
|
|
7
|
+
import { FigureReference } from './non-verbal-references.js';
|
|
8
|
+
import { TableReference } from './non-verbal-references.js';
|
|
9
|
+
import { FormulaReference } from './non-verbal-references.js';
|
|
7
10
|
|
|
8
11
|
export class Concept extends GlossaristModel {
|
|
9
12
|
constructor(data = {}) {
|
|
@@ -19,6 +22,12 @@ export class Concept extends GlossaristModel {
|
|
|
19
22
|
this.tags = Array.isArray(data.tags) ? [...data.tags] : [];
|
|
20
23
|
this.dates = _mapInstances(data.dates ?? [], ConceptDate);
|
|
21
24
|
this.sources = _mapInstances(data.sources ?? [], ConceptSource);
|
|
25
|
+
this._rawFigures = data.figures ?? [];
|
|
26
|
+
this._rawTables = data.tables ?? [];
|
|
27
|
+
this._rawFormulas = data.formulas ?? [];
|
|
28
|
+
this._figures = null;
|
|
29
|
+
this._tables = null;
|
|
30
|
+
this._formulas = null;
|
|
22
31
|
this.status = data.status ?? null;
|
|
23
32
|
this.schemaVersion = data.schemaVersion ?? data.schema_version ?? '3';
|
|
24
33
|
this.raw = data.raw ?? null;
|
|
@@ -107,6 +116,38 @@ export class Concept extends GlossaristModel {
|
|
|
107
116
|
return null;
|
|
108
117
|
}
|
|
109
118
|
|
|
119
|
+
get figures() {
|
|
120
|
+
return this._lazy('_figures', '_rawFigures',
|
|
121
|
+
r => FigureReference.fromJSON(r));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get tables() {
|
|
125
|
+
return this._lazy('_tables', '_rawTables',
|
|
126
|
+
r => TableReference.fromJSON(r));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get formulas() {
|
|
130
|
+
return this._lazy('_formulas', '_rawFormulas',
|
|
131
|
+
r => FormulaReference.fromJSON(r));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Yield every content-text fragment in this concept across all
|
|
136
|
+
* localizations, recursing through nested examples. Each yielded
|
|
137
|
+
* `{ text, source }` carries a dotted path rooted at
|
|
138
|
+
* `localizations.<lang>.<slot>[i]...content`.
|
|
139
|
+
*
|
|
140
|
+
* Designations are not included; they live on `LocalizedConcept.terms`
|
|
141
|
+
* and have a different shape.
|
|
142
|
+
*/
|
|
143
|
+
*walkTexts() {
|
|
144
|
+
for (const lang of this.languages) {
|
|
145
|
+
const lc = this.localization(lang);
|
|
146
|
+
if (!lc) continue;
|
|
147
|
+
yield* lc.walkTexts(`localizations.${lang}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
110
151
|
toJSON() {
|
|
111
152
|
const obj = { id: this.id };
|
|
112
153
|
if (this.term != null) obj.term = this.term;
|
|
@@ -141,6 +182,9 @@ export class Concept extends GlossaristModel {
|
|
|
141
182
|
if (this.sources.length > 0) {
|
|
142
183
|
obj.sources = this.sources.map(s => s.toJSON());
|
|
143
184
|
}
|
|
185
|
+
this._serialize(obj, 'figures', '_figures', '_rawFigures');
|
|
186
|
+
this._serialize(obj, 'tables', '_tables', '_rawTables');
|
|
187
|
+
this._serialize(obj, 'formulas', '_formulas', '_rawFormulas');
|
|
144
188
|
if (this.status != null) obj.status = this.status;
|
|
145
189
|
obj.schema_version = this.schemaVersion;
|
|
146
190
|
return obj;
|
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RegistrableModel } from './registrable.js';
|
|
2
2
|
import { ConceptSource } from './concept-source.js';
|
|
3
3
|
import { Pronunciation } from './pronunciation.js';
|
|
4
4
|
import { GrammarInfo } from './grammar-info.js';
|
|
5
5
|
import { RelatedConcept } from './related-concept.js';
|
|
6
6
|
import { DesignationRelationship, DESIGNATION_RELATIONSHIP_TYPES } from './designation-relationship.js';
|
|
7
7
|
|
|
8
|
-
export class Designation extends
|
|
9
|
-
static _registry = new Map();
|
|
10
|
-
|
|
11
|
-
static register(type, cls) {
|
|
12
|
-
Designation._registry.set(type, cls);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static fromData(data) {
|
|
16
|
-
if (data instanceof Designation) return data;
|
|
17
|
-
const Cls = Designation._registry.get(data?.type) ?? Designation;
|
|
18
|
-
return new Cls(data);
|
|
19
|
-
}
|
|
20
|
-
|
|
8
|
+
export class Designation extends RegistrableModel {
|
|
21
9
|
constructor(data = {}) {
|
|
22
10
|
super();
|
|
23
11
|
this.designation = data.designation ?? '';
|
|
@@ -5,19 +5,43 @@ export class DetailedDefinition extends GlossaristModel {
|
|
|
5
5
|
constructor(data = {}) {
|
|
6
6
|
super();
|
|
7
7
|
this.content = data.content ?? '';
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
this._rawSources = data.sources ?? [];
|
|
9
|
+
this._rawExamples = data.examples ?? [];
|
|
10
|
+
this._sources = null;
|
|
11
|
+
this._examples = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get sources() {
|
|
15
|
+
return this._lazy('_sources', '_rawSources',
|
|
16
|
+
s => s instanceof Citation ? s : new Citation(s));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get examples() {
|
|
20
|
+
return this._lazy('_examples', '_rawExamples',
|
|
21
|
+
e => e instanceof DetailedDefinition ? e : new DetailedDefinition(e));
|
|
11
22
|
}
|
|
12
23
|
|
|
13
24
|
toJSON() {
|
|
14
25
|
const obj = { content: this.content };
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
26
|
+
this._serialize(obj, 'sources', '_sources', '_rawSources');
|
|
27
|
+
this._serialize(obj, 'examples', '_examples', '_rawExamples');
|
|
18
28
|
return obj;
|
|
19
29
|
}
|
|
20
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Yield this definition's content and the content of every nested
|
|
33
|
+
* example (recursively). Each item carries `{ text, source }` where
|
|
34
|
+
* `source` is `<path>.content` rooted at the `path` argument.
|
|
35
|
+
*/
|
|
36
|
+
*walkTexts(path) {
|
|
37
|
+
if (typeof this.content === 'string' && this.content.length > 0) {
|
|
38
|
+
yield { text: this.content, source: `${path}.content` };
|
|
39
|
+
}
|
|
40
|
+
for (let i = 0; i < this.examples.length; i++) {
|
|
41
|
+
yield* this.examples[i].walkTexts(`${path}.examples[${i}]`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
21
45
|
static fromJSON(data) {
|
|
22
46
|
return new DetailedDefinition(data);
|
|
23
47
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { SharedNonVerbalEntity } from './shared-non-verbal-entity.js';
|
|
2
|
+
import { NonVerbalEntity } from './non-verbal-entity.js';
|
|
3
|
+
|
|
4
|
+
export class FigureImage {
|
|
5
|
+
constructor(data = {}) {
|
|
6
|
+
this.src = data.src ?? null;
|
|
7
|
+
this.format = data.format ?? null;
|
|
8
|
+
this.role = data.role ?? null;
|
|
9
|
+
this.width = data.width ?? null;
|
|
10
|
+
this.height = data.height ?? null;
|
|
11
|
+
this.scale = data.scale ?? null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
toJSON() {
|
|
15
|
+
const obj = {};
|
|
16
|
+
if (this.src != null) obj.src = this.src;
|
|
17
|
+
if (this.format != null) obj.format = this.format;
|
|
18
|
+
if (this.role != null) obj.role = this.role;
|
|
19
|
+
if (this.width != null) obj.width = this.width;
|
|
20
|
+
if (this.height != null) obj.height = this.height;
|
|
21
|
+
if (this.scale != null) obj.scale = this.scale;
|
|
22
|
+
return obj;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static fromJSON(data) { return new FigureImage(data); }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Figure extends SharedNonVerbalEntity {
|
|
29
|
+
constructor(data = {}) {
|
|
30
|
+
super(data);
|
|
31
|
+
this._rawImages = data.images ?? [];
|
|
32
|
+
this._rawSubfigures = data.subfigures ?? [];
|
|
33
|
+
this._images = null;
|
|
34
|
+
this._subfigures = null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get images() {
|
|
38
|
+
return this._lazy('_images', '_rawImages',
|
|
39
|
+
i => i instanceof FigureImage ? i : new FigureImage(i));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get subfigures() {
|
|
43
|
+
return this._lazy('_subfigures', '_rawSubfigures',
|
|
44
|
+
s => s instanceof Figure ? s : new Figure(s));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
findById(targetId) {
|
|
48
|
+
if (this.id === targetId) return this;
|
|
49
|
+
for (const sub of this.subfigures) {
|
|
50
|
+
const found = sub.findById(targetId);
|
|
51
|
+
if (found) return found;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
allIds() {
|
|
57
|
+
const ids = this.id != null ? [this.id] : [];
|
|
58
|
+
return [...ids, ...this.subfigures.flatMap(s => s.allIds())];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
toJSON() {
|
|
62
|
+
const obj = super.toJSON();
|
|
63
|
+
this._serialize(obj, 'images', '_images', '_rawImages');
|
|
64
|
+
this._serialize(obj, 'subfigures', '_subfigures', '_rawSubfigures');
|
|
65
|
+
return obj;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static fromJSON(data) { return new Figure(data); }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
NonVerbalEntity.register('figure', Figure);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SharedNonVerbalEntity } from './shared-non-verbal-entity.js';
|
|
2
|
+
import { NonVerbalEntity } from './non-verbal-entity.js';
|
|
3
|
+
|
|
4
|
+
export class Formula extends SharedNonVerbalEntity {
|
|
5
|
+
constructor(data = {}) {
|
|
6
|
+
super(data);
|
|
7
|
+
this.expression = data.expression ?? null;
|
|
8
|
+
this.notation = data.notation ?? null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
toJSON() {
|
|
12
|
+
const obj = super.toJSON();
|
|
13
|
+
if (this.expression != null) obj.expression = this.expression;
|
|
14
|
+
if (this.notation != null) obj.notation = this.notation;
|
|
15
|
+
return obj;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static fromJSON(data) { return new Formula(data); }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
NonVerbalEntity.register('formula', Formula);
|