glossarist 0.4.5 → 0.4.6
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/data/concept-model/shapes/glossarist.shacl.ttl +114 -3
- package/package.json +1 -1
- package/src/models/figure.js +4 -0
- package/src/models/formula.js +4 -0
- package/src/models/non-verb-rep.js +4 -0
- package/src/models/non-verbal-entity.js +7 -0
- package/src/models/table.js +4 -0
- package/src/rdf/gloss-concept.js +29 -0
- package/src/rdf/gloss-localized-concept.js +7 -0
- package/src/rdf/gloss-non-verbal-rep.js +191 -0
- package/src/rdf/index.d.ts +24 -2
- package/src/rdf/index.js +6 -1
- package/src/rdf/predicates.d.ts +32 -0
- package/src/rdf/predicates.js +16 -0
- package/src/rdf/shacl.js +4 -3
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
@prefix gloss: <https://www.glossarist.org/ontologies/> .
|
|
9
9
|
@prefix sh: <http://www.w3.org/ns/shacl#> .
|
|
10
10
|
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
|
|
11
|
-
@prefix
|
|
11
|
+
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .
|
|
12
12
|
@prefix dcterms: <http://purl.org/dc/terms/> .
|
|
13
13
|
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
14
14
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
15
15
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
16
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
17
|
+
@prefix prov: <http://www.w3.org/ns/prov#> .
|
|
18
|
+
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
|
19
|
+
@prefix dcat: <http://www.w3.org/ns/dcat#> .
|
|
16
20
|
|
|
17
21
|
# ══════════════════════════════════════════════════════════════════════════
|
|
18
22
|
# Concept shapes
|
|
@@ -175,9 +179,9 @@ gloss:ConceptCollectionShape a sh:NodeShape ;
|
|
|
175
179
|
|
|
176
180
|
gloss:DesignationShape a sh:NodeShape ;
|
|
177
181
|
sh:targetClass gloss:Designation ;
|
|
178
|
-
sh:class
|
|
182
|
+
sh:class skosxl:Label ;
|
|
179
183
|
sh:property [
|
|
180
|
-
sh:path
|
|
184
|
+
sh:path skosxl:literalForm ;
|
|
181
185
|
sh:minCount 1 ;
|
|
182
186
|
sh:maxCount 1 ;
|
|
183
187
|
] ;
|
|
@@ -430,6 +434,108 @@ gloss:NonVerbalRepresentationShape a sh:NodeShape ;
|
|
|
430
434
|
sh:class gloss:ConceptSource ;
|
|
431
435
|
] .
|
|
432
436
|
|
|
437
|
+
# === K1: Non-verbal entity shapes ===
|
|
438
|
+
# Class declarations (NonVerbalEntity, Figure, Table, Formula, SharedNonVerbalEntity)
|
|
439
|
+
# live in glossarist.ttl — this file contains validation shapes only.
|
|
440
|
+
|
|
441
|
+
gloss:FigureShape a sh:NodeShape ;
|
|
442
|
+
sh:targetClass gloss:Figure ;
|
|
443
|
+
sh:property [
|
|
444
|
+
sh:path gloss:image ;
|
|
445
|
+
sh:datatype xsd:anyURI ;
|
|
446
|
+
sh:minCount 1 ;
|
|
447
|
+
] ;
|
|
448
|
+
sh:property [
|
|
449
|
+
sh:path gloss:caption ;
|
|
450
|
+
sh:datatype xsd:string ;
|
|
451
|
+
sh:maxCount 1 ;
|
|
452
|
+
] ;
|
|
453
|
+
sh:property [
|
|
454
|
+
sh:path dcterms:description ;
|
|
455
|
+
sh:datatype xsd:string ;
|
|
456
|
+
sh:maxCount 1 ;
|
|
457
|
+
] .
|
|
458
|
+
|
|
459
|
+
gloss:TableShape a sh:NodeShape ;
|
|
460
|
+
sh:targetClass gloss:Table ;
|
|
461
|
+
sh:property [
|
|
462
|
+
sh:path gloss:content ;
|
|
463
|
+
sh:datatype xsd:string ;
|
|
464
|
+
sh:minCount 1 ;
|
|
465
|
+
] ;
|
|
466
|
+
sh:property [
|
|
467
|
+
sh:path gloss:caption ;
|
|
468
|
+
sh:datatype xsd:string ;
|
|
469
|
+
sh:maxCount 1 ;
|
|
470
|
+
] ;
|
|
471
|
+
sh:property [
|
|
472
|
+
sh:path dcterms:title ;
|
|
473
|
+
sh:datatype xsd:string ;
|
|
474
|
+
sh:maxCount 1 ;
|
|
475
|
+
] .
|
|
476
|
+
|
|
477
|
+
gloss:FormulaShape a sh:NodeShape ;
|
|
478
|
+
sh:targetClass gloss:Formula ;
|
|
479
|
+
sh:property [
|
|
480
|
+
sh:path gloss:expression ;
|
|
481
|
+
sh:datatype xsd:string ;
|
|
482
|
+
sh:minCount 1 ;
|
|
483
|
+
] ;
|
|
484
|
+
sh:property [
|
|
485
|
+
sh:path gloss:latexForm ;
|
|
486
|
+
sh:datatype xsd:string ;
|
|
487
|
+
sh:maxCount 1 ;
|
|
488
|
+
] ;
|
|
489
|
+
sh:property [
|
|
490
|
+
sh:path dcterms:description ;
|
|
491
|
+
sh:datatype xsd:string ;
|
|
492
|
+
sh:maxCount 1 ;
|
|
493
|
+
] .
|
|
494
|
+
|
|
495
|
+
# === K2: Image binary references ===
|
|
496
|
+
|
|
497
|
+
gloss:ImageShape a sh:NodeShape ;
|
|
498
|
+
sh:targetClass foaf:Image ;
|
|
499
|
+
sh:property [
|
|
500
|
+
sh:path dcterms:format ;
|
|
501
|
+
sh:datatype xsd:string ;
|
|
502
|
+
sh:minCount 1 ;
|
|
503
|
+
] ;
|
|
504
|
+
sh:property [
|
|
505
|
+
sh:path dcterms:language ;
|
|
506
|
+
sh:datatype xsd:string ;
|
|
507
|
+
sh:maxCount 1 ;
|
|
508
|
+
] ;
|
|
509
|
+
sh:property [
|
|
510
|
+
sh:path dcat:byteSize ;
|
|
511
|
+
sh:datatype xsd:integer ;
|
|
512
|
+
sh:maxCount 1 ;
|
|
513
|
+
] .
|
|
514
|
+
|
|
515
|
+
# === K4: NonVerbalRepresentation (concept-level NVR) ===
|
|
516
|
+
# Class declaration lives in glossarist.ttl as gloss:NonVerbalRepresentation.
|
|
517
|
+
|
|
518
|
+
gloss:NonVerbalRepresentationShape a sh:NodeShape ;
|
|
519
|
+
sh:targetClass gloss:NonVerbalRepresentation ;
|
|
520
|
+
sh:property [
|
|
521
|
+
sh:path skosxl:prefLabel ;
|
|
522
|
+
sh:minCount 1 ;
|
|
523
|
+
] ;
|
|
524
|
+
sh:property [
|
|
525
|
+
sh:path gloss:image ;
|
|
526
|
+
sh:datatype xsd:anyURI ;
|
|
527
|
+
sh:maxCount 1 ;
|
|
528
|
+
] ;
|
|
529
|
+
sh:property [
|
|
530
|
+
sh:path dcterms:description ;
|
|
531
|
+
sh:maxCount 1 ;
|
|
532
|
+
] ;
|
|
533
|
+
sh:property [
|
|
534
|
+
sh:path prov:wasDerivedFrom ;
|
|
535
|
+
sh:class prov:Entity ;
|
|
536
|
+
sh:maxCount 1 ;
|
|
537
|
+
] .
|
|
538
|
+
|
|
433
539
|
gloss:ReferenceShape a sh:NodeShape ;
|
|
434
540
|
sh:targetClass gloss:Reference ;
|
|
435
541
|
sh:or (
|
|
@@ -696,6 +802,11 @@ gloss:SectionShape a sh:NodeShape ;
|
|
|
696
802
|
sh:path gloss:hasChildSection ;
|
|
697
803
|
sh:class gloss:Section ;
|
|
698
804
|
] ;
|
|
805
|
+
sh:property [
|
|
806
|
+
sh:path gloss:hasParentSection ;
|
|
807
|
+
sh:class gloss:Section ;
|
|
808
|
+
sh:maxCount 1 ;
|
|
809
|
+
] ;
|
|
699
810
|
sh:property [
|
|
700
811
|
sh:path gloss:sectionOrdering ;
|
|
701
812
|
sh:class skos:Concept ;
|
package/package.json
CHANGED
package/src/models/figure.js
CHANGED
|
@@ -34,6 +34,10 @@ export class Figure extends SharedNonVerbalEntity {
|
|
|
34
34
|
this._subfigures = null;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
rdfClass() {
|
|
38
|
+
return 'Figure';
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
get images() {
|
|
38
42
|
return this._lazy('_images', '_rawImages',
|
|
39
43
|
i => i instanceof FigureImage ? i : new FigureImage(i));
|
package/src/models/formula.js
CHANGED
|
@@ -11,6 +11,10 @@ export class NonVerbRep extends NonVerbalEntity {
|
|
|
11
11
|
this._images = null;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
rdfClass() {
|
|
15
|
+
return 'NonVerbalRepresentation';
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
get images() {
|
|
15
19
|
return this._lazy('_images', '_rawImages',
|
|
16
20
|
i => i instanceof FigureImage ? i : new FigureImage(i));
|
|
@@ -16,6 +16,13 @@ export class NonVerbalEntity extends RegistrableModel {
|
|
|
16
16
|
s => s instanceof ConceptSource ? s : new ConceptSource(s));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
// Ontology class local-name. Subtypes override to return their specific
|
|
20
|
+
// class (Figure/Table/Formula). Used by the RDF emitter so a new subtype
|
|
21
|
+
// registers without editing the emitter (OCP).
|
|
22
|
+
rdfClass() {
|
|
23
|
+
return 'NonVerbalEntity';
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
findById(_targetId) {
|
|
20
27
|
return null;
|
|
21
28
|
}
|
package/src/models/table.js
CHANGED
package/src/rdf/gloss-concept.js
CHANGED
|
@@ -2,12 +2,31 @@
|
|
|
2
2
|
//
|
|
3
3
|
// URI shape: `<uriBase>/<registerId>/concept/<conceptId>`.
|
|
4
4
|
// Localized concepts: `<uriBase>/<registerId>/concept/<conceptId>/<lang>`.
|
|
5
|
+
// Figure/Table/Formula references: `<uriBase>/<registerId>/<kind>/<entityId>`.
|
|
5
6
|
import { PRED } from './predicates.js';
|
|
6
7
|
import { WELL_KNOWN } from './prefixes.js';
|
|
7
8
|
import { localizedConceptToQuads } from './gloss-localized-concept.js';
|
|
8
9
|
import { conceptSourceToQuads } from './gloss-source.js';
|
|
9
10
|
import { namedNode, literal, quad } from './terms.js';
|
|
10
11
|
|
|
12
|
+
// Kind tag → URI segment. Each NonVerbalReference subtype has a
|
|
13
|
+
// predictable URL path so the same entity is reachable from any
|
|
14
|
+
// concept that references it.
|
|
15
|
+
const NVR_KIND_SEGMENT = {
|
|
16
|
+
FigureReference: 'figure',
|
|
17
|
+
TableReference: 'table',
|
|
18
|
+
FormulaReference: 'formula',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Builds the URI for a NonVerbalReference target entity. Returns null
|
|
22
|
+
// when the reference has no entityId (e.g., inline display-only refs).
|
|
23
|
+
function nonVerbalReferenceUri(ref, options) {
|
|
24
|
+
const kind = NVR_KIND_SEGMENT[ref.constructor.name];
|
|
25
|
+
if (!kind || !ref.entityId) return null;
|
|
26
|
+
const base = String(options.uriBase ?? '').replace(/\/+$/, '');
|
|
27
|
+
return `${base}/${options.registerId}/${kind}/${ref.entityId}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
export function conceptUri(concept, { registerId, uriBase }) {
|
|
12
31
|
const id = String(concept.id ?? concept.termid ?? '');
|
|
13
32
|
const base = String(uriBase ?? '').replace(/\/+$/, '');
|
|
@@ -27,6 +46,16 @@ export function* conceptToQuads(concept, options) {
|
|
|
27
46
|
yield quad(s, namedNode(PRED.gloss.hasStatus), namedNode(`${PRED.gloss.$ns}status/${concept.status}`));
|
|
28
47
|
}
|
|
29
48
|
|
|
49
|
+
// NonVerbal references — emit the link quad only. The actual
|
|
50
|
+
// Figure/Table/Formula entity quads are emitted by `nonVerbalEntityToQuads`
|
|
51
|
+
// when the dataset's NVR collection is iterated.
|
|
52
|
+
for (const ref of [...(concept.figures ?? []), ...(concept.tables ?? []), ...(concept.formulas ?? [])]) {
|
|
53
|
+
const targetUri = nonVerbalReferenceUri(ref, options);
|
|
54
|
+
if (targetUri) {
|
|
55
|
+
yield quad(s, namedNode(PRED.gloss.hasNonVerbalRep), namedNode(targetUri));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
30
59
|
for (const lang of concept.languages) {
|
|
31
60
|
const lc = concept.localization(lang);
|
|
32
61
|
if (!lc) continue;
|
|
@@ -10,6 +10,7 @@ import { WELL_KNOWN } from './prefixes.js';
|
|
|
10
10
|
import { designationToQuads, skosLabelPredicate } from './gloss-designation.js';
|
|
11
11
|
import { detailedDefinitionToQuads } from './gloss-detailed-definition.js';
|
|
12
12
|
import { conceptSourceToQuads } from './gloss-source.js';
|
|
13
|
+
import { nonVerbalRepToQuads } from './gloss-non-verbal-rep.js';
|
|
13
14
|
import { namedNode, literal, quad } from './terms.js';
|
|
14
15
|
const DCTERMS_LANGUAGE = `${PREFIXES.dcterms}language`;
|
|
15
16
|
|
|
@@ -55,6 +56,12 @@ export function* localizedConceptToQuads(localizedConcept, { parentUri, language
|
|
|
55
56
|
yield* definitionsToQuads(localizedConcept.examples, { subjectUri, language, role: 'hasExample' });
|
|
56
57
|
yield* definitionsToQuads(localizedConcept.annotations, { subjectUri, language, role: 'hasAnnotation' });
|
|
57
58
|
|
|
59
|
+
let nvrIndex = 0;
|
|
60
|
+
for (const nvr of localizedConcept.nonVerbalRep ?? []) {
|
|
61
|
+
yield* nonVerbalRepToQuads(nvr, { parentUri: subjectUri, index: nvrIndex, language });
|
|
62
|
+
nvrIndex += 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
58
65
|
let srcIndex = 0;
|
|
59
66
|
for (const source of localizedConcept.sources ?? []) {
|
|
60
67
|
yield* conceptSourceToQuads(source, { subjectUri, index: srcIndex });
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// NonVerbal entity → RDF quads. Mirrors the v3.1.0 concept-model
|
|
2
|
+
// NonVerbal class hierarchy. Two distinct shapes:
|
|
3
|
+
//
|
|
4
|
+
// 1. Legacy `gloss:NonVerbalRepresentation` (NonVerbRep) — a child of
|
|
5
|
+
// LocalizedConcept with a positional bnode subject. Carries
|
|
6
|
+
// `representationType`, `representationRef`, `representationText`.
|
|
7
|
+
//
|
|
8
|
+
// 2. Dataset-level `gloss:Figure` / `gloss:Table` / `gloss:Formula`
|
|
9
|
+
// (SharedNonVerbalEntity subtypes) — first-class resources with
|
|
10
|
+
// their own URIs. Carries caption, description, altText, sources,
|
|
11
|
+
// plus subtype-specific fields (Figure: images + subfigures;
|
|
12
|
+
// Table: content + format; Formula: expression + notation +
|
|
13
|
+
// latexForm).
|
|
14
|
+
//
|
|
15
|
+
// The dispatch on the entity's `rdfClass()` follows the same OCP
|
|
16
|
+
// pattern as Designation — a new subtype registers without editing
|
|
17
|
+
// this emitter.
|
|
18
|
+
import { PRED, PREFIXES } from './predicates.js';
|
|
19
|
+
import { WELL_KNOWN } from './prefixes.js';
|
|
20
|
+
import { deterministicBnode } from './deterministic-id.js';
|
|
21
|
+
import { namedNode, literal, quad } from './terms.js';
|
|
22
|
+
import { conceptSourceToQuads } from './gloss-source.js';
|
|
23
|
+
|
|
24
|
+
const DCTERMS_DESCRIPTION = `${PREFIXES.dcterms}description`;
|
|
25
|
+
const DCTERMS_FORMAT = `${PREFIXES.dcterms}format`;
|
|
26
|
+
const XSD_STRING = `${PREFIXES.xsd}string`;
|
|
27
|
+
|
|
28
|
+
// ── Legacy NonVerbRep (concept-local, positional) ──────────────────────
|
|
29
|
+
|
|
30
|
+
// Emits a `gloss:NonVerbalRepresentation` blank node linked from the
|
|
31
|
+
// parent localized concept via `gloss:hasNonVerbalRep`. Mirrors the
|
|
32
|
+
// Ruby `Rdf::GlossNonVerbalRep` shape: type/ref/text plus sources.
|
|
33
|
+
export function* nonVerbalRepToQuads(nvr, { parentUri, index, language = null }) {
|
|
34
|
+
const subject = deterministicBnode(parentUri, 'nvr', index);
|
|
35
|
+
|
|
36
|
+
yield quad(namedNode(parentUri), namedNode(PRED.gloss.hasNonVerbalRep), namedNode(subject));
|
|
37
|
+
yield quad(namedNode(subject), namedNode(WELL_KNOWN.rdfType), namedNode(`${PRED.gloss.$ns}${nvr.rdfClass()}`));
|
|
38
|
+
|
|
39
|
+
if (nvr.type) {
|
|
40
|
+
yield quad(namedNode(subject), namedNode(PRED.gloss.representationType), literal(nvr.type, XSD_STRING));
|
|
41
|
+
}
|
|
42
|
+
for (const image of nvr.images ?? []) {
|
|
43
|
+
if (image.src) {
|
|
44
|
+
yield quad(namedNode(subject), namedNode(PRED.gloss.image), literal(image.src, XSD_STRING));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (nvr.caption) {
|
|
48
|
+
yield quad(namedNode(subject), namedNode(PRED.gloss.caption), literal(nvr.caption, language));
|
|
49
|
+
}
|
|
50
|
+
if (nvr.description) {
|
|
51
|
+
yield quad(namedNode(subject), namedNode(DCTERMS_DESCRIPTION), literal(nvr.description, language));
|
|
52
|
+
}
|
|
53
|
+
if (nvr.alt) {
|
|
54
|
+
yield quad(namedNode(subject), namedNode(PRED.gloss.altText), literal(nvr.alt, language));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let srcIndex = 0;
|
|
58
|
+
for (const source of nvr.sources ?? []) {
|
|
59
|
+
yield* conceptSourceToQuads(source, { subjectUri: subject, index: srcIndex });
|
|
60
|
+
srcIndex += 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── Dataset-level Figure / Table / Formula ────────────────────────────
|
|
65
|
+
|
|
66
|
+
// URI scheme: `<uriBase>/<registerId>/<kind>/<id>` where `kind` is the
|
|
67
|
+
// entity's rdfClass() lowercased (figure/table/formula). Stable across
|
|
68
|
+
// runs and consumers.
|
|
69
|
+
export function nonVerbalEntityUri(entity, { registerId, uriBase }) {
|
|
70
|
+
const id = String(entity.id ?? entity.identifier ?? '');
|
|
71
|
+
const kind = String(entity.rdfClass() ?? 'NonVerbalEntity').toLowerCase();
|
|
72
|
+
const base = String(uriBase ?? '').replace(/\/+$/, '');
|
|
73
|
+
return `${base}/${registerId}/${kind}/${id}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Emits a dataset-level NonVerbalEntity (Figure/Table/Formula) as a
|
|
77
|
+
// first-class resource. Calls into subtype-specific emitters via the
|
|
78
|
+
// entity's class identity — OCP: a new subtype adds a branch in
|
|
79
|
+
// `subtypeQuadsFor` without changing the public entry point.
|
|
80
|
+
export function* nonVerbalEntityToQuads(entity, options) {
|
|
81
|
+
const subjectUri = nonVerbalEntityUri(entity, options);
|
|
82
|
+
const s = namedNode(subjectUri);
|
|
83
|
+
|
|
84
|
+
yield quad(s, namedNode(WELL_KNOWN.rdfType), namedNode(`${PRED.gloss.$ns}${entity.rdfClass()}`));
|
|
85
|
+
|
|
86
|
+
if (entity.caption) {
|
|
87
|
+
yield quad(s, namedNode(PRED.gloss.caption), literal(entity.caption, null));
|
|
88
|
+
}
|
|
89
|
+
if (entity.description) {
|
|
90
|
+
yield quad(s, namedNode(DCTERMS_DESCRIPTION), literal(entity.description, null));
|
|
91
|
+
}
|
|
92
|
+
if (entity.alt) {
|
|
93
|
+
yield quad(s, namedNode(PRED.gloss.altText), literal(entity.alt, null));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
yield* subtypeQuadsFor(entity, s, options);
|
|
97
|
+
|
|
98
|
+
let srcIndex = 0;
|
|
99
|
+
for (const source of entity.sources ?? []) {
|
|
100
|
+
yield* conceptSourceToQuads(source, { subjectUri, index: srcIndex });
|
|
101
|
+
srcIndex += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Dispatch table: maps the entity's rdfClass() local name to a
|
|
106
|
+
// subtype-specific quad generator. Adding a new subtype = adding a
|
|
107
|
+
// branch here + an rdfClass() override on the model class.
|
|
108
|
+
function* subtypeQuadsFor(entity, s, options) {
|
|
109
|
+
switch (entity.rdfClass()) {
|
|
110
|
+
case 'Figure': yield* figureQuads(entity, s, options); break;
|
|
111
|
+
case 'Table': yield* tableQuads(entity, s); break;
|
|
112
|
+
case 'Formula': yield* formulaQuads(entity, s); break;
|
|
113
|
+
// NonVerbalEntity base or unknown — no subtype-specific quads.
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function* figureQuads(figure, s, options) {
|
|
118
|
+
let imgIndex = 0;
|
|
119
|
+
for (const image of figure.images ?? []) {
|
|
120
|
+
const imgSubject = deterministicBnode(s.value, 'image', imgIndex);
|
|
121
|
+
yield quad(s, namedNode(PRED.gloss.image), namedNode(imgSubject));
|
|
122
|
+
yield quad(namedNode(imgSubject), namedNode(WELL_KNOWN.rdfType), namedNode(PRED.gloss.FigureImage));
|
|
123
|
+
if (image.src) {
|
|
124
|
+
yield quad(namedNode(imgSubject), namedNode(PRED.gloss.src), literal(image.src, XSD_STRING));
|
|
125
|
+
}
|
|
126
|
+
if (image.format) {
|
|
127
|
+
yield quad(namedNode(imgSubject), namedNode(DCTERMS_FORMAT), literal(image.format, XSD_STRING));
|
|
128
|
+
}
|
|
129
|
+
if (image.role) {
|
|
130
|
+
yield quad(namedNode(imgSubject), namedNode(PRED.gloss.role), literal(image.role, XSD_STRING));
|
|
131
|
+
}
|
|
132
|
+
imgIndex += 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let subIndex = 0;
|
|
136
|
+
for (const sub of figure.subfigures ?? []) {
|
|
137
|
+
const subSubject = deterministicBnode(s.value, 'subfig', subIndex);
|
|
138
|
+
yield quad(s, namedNode(PRED.gloss.hasSubfigure), namedNode(subSubject));
|
|
139
|
+
// Subfigures recurse as their own Figure bnodes — same shape,
|
|
140
|
+
// different subject. We inline the base + subtype quads so the
|
|
141
|
+
// subfigure's images also resolve.
|
|
142
|
+
yield* subfigureQuads(sub, subSubject, options);
|
|
143
|
+
subIndex += 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Sub-figure emitter — mirrors `nonVerbalEntityToQuads` but with a
|
|
148
|
+
// pre-assigned bnode subject (subfigures don't get their own URI).
|
|
149
|
+
function* subfigureQuads(figure, subjectUri, _options) {
|
|
150
|
+
const s = namedNode(subjectUri);
|
|
151
|
+
yield quad(s, namedNode(WELL_KNOWN.rdfType), namedNode(`${PRED.gloss.$ns}${figure.rdfClass()}`));
|
|
152
|
+
|
|
153
|
+
if (figure.caption) {
|
|
154
|
+
yield quad(s, namedNode(PRED.gloss.caption), literal(figure.caption, null));
|
|
155
|
+
}
|
|
156
|
+
if (figure.description) {
|
|
157
|
+
yield quad(s, namedNode(DCTERMS_DESCRIPTION), literal(figure.description, null));
|
|
158
|
+
}
|
|
159
|
+
if (figure.alt) {
|
|
160
|
+
yield quad(s, namedNode(PRED.gloss.altText), literal(figure.alt, null));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let imgIndex = 0;
|
|
164
|
+
for (const image of figure.images ?? []) {
|
|
165
|
+
const imgSubject = deterministicBnode(s.value, 'image', imgIndex);
|
|
166
|
+
yield quad(s, namedNode(PRED.gloss.image), namedNode(imgSubject));
|
|
167
|
+
yield quad(namedNode(imgSubject), namedNode(WELL_KNOWN.rdfType), namedNode(PRED.gloss.FigureImage));
|
|
168
|
+
if (image.src) {
|
|
169
|
+
yield quad(namedNode(imgSubject), namedNode(PRED.gloss.src), literal(image.src, XSD_STRING));
|
|
170
|
+
}
|
|
171
|
+
imgIndex += 1;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function* tableQuads(table, s) {
|
|
176
|
+
if (table.content) {
|
|
177
|
+
yield quad(s, namedNode(PRED.gloss.content), literal(table.content, null));
|
|
178
|
+
}
|
|
179
|
+
if (table.format) {
|
|
180
|
+
yield quad(s, namedNode(PRED.gloss.format), literal(table.format, XSD_STRING));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function* formulaQuads(formula, s) {
|
|
185
|
+
if (formula.expression) {
|
|
186
|
+
yield quad(s, namedNode(PRED.gloss.expression), literal(formula.expression, null));
|
|
187
|
+
}
|
|
188
|
+
if (formula.notation) {
|
|
189
|
+
yield quad(s, namedNode(PRED.gloss.latexForm), literal(formula.notation, XSD_STRING));
|
|
190
|
+
}
|
|
191
|
+
}
|
package/src/rdf/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { LocalizedConcept } from '../models/index';
|
|
|
10
10
|
import type { Designation } from '../models/index';
|
|
11
11
|
import type { DetailedDefinition } from '../models/index';
|
|
12
12
|
import type { ConceptSource } from '../models/index';
|
|
13
|
+
import type { NonVerbRep, Figure, Table, Formula } from '../models/index';
|
|
13
14
|
|
|
14
15
|
export { PRED, PREFIXES } from './predicates';
|
|
15
16
|
export type PredicateMap = typeof PRED;
|
|
@@ -76,6 +77,26 @@ export interface ConceptSourceEmitOptions {
|
|
|
76
77
|
|
|
77
78
|
export declare function conceptSourceToQuads(source: ConceptSource, options: ConceptSourceEmitOptions): Generator<Quad, void, unknown>;
|
|
78
79
|
|
|
80
|
+
// ── Non-verbal representation emitters ─────────────────────────────────
|
|
81
|
+
|
|
82
|
+
export interface NonVerbalRepEmitOptions {
|
|
83
|
+
parentUri: string;
|
|
84
|
+
index: number;
|
|
85
|
+
language?: string | null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export declare function nonVerbalRepToQuads(nvr: NonVerbRep, options: NonVerbalRepEmitOptions): Generator<Quad, void, unknown>;
|
|
89
|
+
|
|
90
|
+
export interface NonVerbalEntityEmitOptions {
|
|
91
|
+
registerId: string;
|
|
92
|
+
uriBase?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type NonVerbalEntity = Figure | Table | Formula;
|
|
96
|
+
|
|
97
|
+
export declare function nonVerbalEntityUri(entity: NonVerbalEntity, options: NonVerbalEntityEmitOptions): string;
|
|
98
|
+
export declare function nonVerbalEntityToQuads(entity: NonVerbalEntity, options: NonVerbalEntityEmitOptions): Generator<Quad, void, unknown>;
|
|
99
|
+
|
|
79
100
|
export declare function collectQuads(quadsIterable: Iterable<Quad>): Quad[];
|
|
80
101
|
|
|
81
102
|
export interface WriteTurtleOptions {
|
|
@@ -102,6 +123,7 @@ export interface ValidationReport {
|
|
|
102
123
|
}>;
|
|
103
124
|
}
|
|
104
125
|
|
|
105
|
-
export declare function loadShapes(): Promise<Dataset>;
|
|
106
|
-
export declare function validateShacl(dataDataset: Dataset, options?: { shapes?: Dataset }): Promise<ValidationReport>;
|
|
126
|
+
export declare function loadShapes(options?: { shapesPath?: string }): Promise<Dataset>;
|
|
127
|
+
export declare function validateShacl(dataDataset: Dataset, options?: { shapes?: Dataset; shapesPath?: string }): Promise<ValidationReport>;
|
|
128
|
+
export declare function clearShapesCache(): void;
|
|
107
129
|
export declare function quadsToDataset(quads: Iterable<Quad>): Dataset;
|
package/src/rdf/index.js
CHANGED
|
@@ -17,6 +17,11 @@ export {
|
|
|
17
17
|
} from './gloss-designation.js';
|
|
18
18
|
export { detailedDefinitionToQuads } from './gloss-detailed-definition.js';
|
|
19
19
|
export { conceptSourceToQuads } from './gloss-source.js';
|
|
20
|
+
export {
|
|
21
|
+
nonVerbalRepToQuads,
|
|
22
|
+
nonVerbalEntityToQuads,
|
|
23
|
+
nonVerbalEntityUri,
|
|
24
|
+
} from './gloss-non-verbal-rep.js';
|
|
20
25
|
export {
|
|
21
26
|
collectQuads,
|
|
22
27
|
writeTurtle,
|
|
@@ -24,4 +29,4 @@ export {
|
|
|
24
29
|
writeJsonld,
|
|
25
30
|
sortQuads,
|
|
26
31
|
} from './document-writer.js';
|
|
27
|
-
export { validateShacl, loadShapes, quadsToDataset } from './shacl.js';
|
|
32
|
+
export { validateShacl, loadShapes, clearShapesCache, quadsToDataset } from './shacl.js';
|
package/src/rdf/predicates.d.ts
CHANGED
|
@@ -26,6 +26,12 @@ export declare const PRED = {
|
|
|
26
26
|
"DesignationRelationship": "https://www.glossarist.org/ontologies/DesignationRelationship",
|
|
27
27
|
"ConceptDate": "https://www.glossarist.org/ontologies/ConceptDate",
|
|
28
28
|
"NonVerbalRepresentation": "https://www.glossarist.org/ontologies/NonVerbalRepresentation",
|
|
29
|
+
"NonVerbalEntity": "https://www.glossarist.org/ontologies/NonVerbalEntity",
|
|
30
|
+
"SharedNonVerbalEntity": "https://www.glossarist.org/ontologies/SharedNonVerbalEntity",
|
|
31
|
+
"Figure": "https://www.glossarist.org/ontologies/Figure",
|
|
32
|
+
"Table": "https://www.glossarist.org/ontologies/Table",
|
|
33
|
+
"Formula": "https://www.glossarist.org/ontologies/Formula",
|
|
34
|
+
"FigureImage": "https://www.glossarist.org/ontologies/FigureImage",
|
|
29
35
|
"CustomLocality": "https://www.glossarist.org/ontologies/CustomLocality",
|
|
30
36
|
"Locality": "https://www.glossarist.org/ontologies/Locality",
|
|
31
37
|
"DatasetRegister": "https://www.glossarist.org/ontologies/DatasetRegister",
|
|
@@ -69,6 +75,16 @@ export declare const PRED = {
|
|
|
69
75
|
"isTruncation": "https://www.glossarist.org/ontologies/isTruncation",
|
|
70
76
|
"text": "https://www.glossarist.org/ontologies/text",
|
|
71
77
|
"image": "https://www.glossarist.org/ontologies/image",
|
|
78
|
+
"caption": "https://www.glossarist.org/ontologies/caption",
|
|
79
|
+
"altText": "https://www.glossarist.org/ontologies/altText",
|
|
80
|
+
"description": "https://www.glossarist.org/ontologies/description",
|
|
81
|
+
"expression": "https://www.glossarist.org/ontologies/expression",
|
|
82
|
+
"latexForm": "https://www.glossarist.org/ontologies/latexForm",
|
|
83
|
+
"content": "https://www.glossarist.org/ontologies/content",
|
|
84
|
+
"hasSubfigure": "https://www.glossarist.org/ontologies/hasSubfigure",
|
|
85
|
+
"src": "https://www.glossarist.org/ontologies/src",
|
|
86
|
+
"format": "https://www.glossarist.org/ontologies/format",
|
|
87
|
+
"role": "https://www.glossarist.org/ontologies/role",
|
|
72
88
|
"pronunciationContent": "https://www.glossarist.org/ontologies/pronunciationContent",
|
|
73
89
|
"pronunciationLanguage": "https://www.glossarist.org/ontologies/pronunciationLanguage",
|
|
74
90
|
"pronunciationScript": "https://www.glossarist.org/ontologies/pronunciationScript",
|
|
@@ -268,6 +284,12 @@ export type Predicate =
|
|
|
268
284
|
| "https://www.glossarist.org/ontologies/DesignationRelationship"
|
|
269
285
|
| "https://www.glossarist.org/ontologies/ConceptDate"
|
|
270
286
|
| "https://www.glossarist.org/ontologies/NonVerbalRepresentation"
|
|
287
|
+
| "https://www.glossarist.org/ontologies/NonVerbalEntity"
|
|
288
|
+
| "https://www.glossarist.org/ontologies/SharedNonVerbalEntity"
|
|
289
|
+
| "https://www.glossarist.org/ontologies/Figure"
|
|
290
|
+
| "https://www.glossarist.org/ontologies/Table"
|
|
291
|
+
| "https://www.glossarist.org/ontologies/Formula"
|
|
292
|
+
| "https://www.glossarist.org/ontologies/FigureImage"
|
|
271
293
|
| "https://www.glossarist.org/ontologies/CustomLocality"
|
|
272
294
|
| "https://www.glossarist.org/ontologies/Locality"
|
|
273
295
|
| "https://www.glossarist.org/ontologies/DatasetRegister"
|
|
@@ -311,6 +333,16 @@ export type Predicate =
|
|
|
311
333
|
| "https://www.glossarist.org/ontologies/isTruncation"
|
|
312
334
|
| "https://www.glossarist.org/ontologies/text"
|
|
313
335
|
| "https://www.glossarist.org/ontologies/image"
|
|
336
|
+
| "https://www.glossarist.org/ontologies/caption"
|
|
337
|
+
| "https://www.glossarist.org/ontologies/altText"
|
|
338
|
+
| "https://www.glossarist.org/ontologies/description"
|
|
339
|
+
| "https://www.glossarist.org/ontologies/expression"
|
|
340
|
+
| "https://www.glossarist.org/ontologies/latexForm"
|
|
341
|
+
| "https://www.glossarist.org/ontologies/content"
|
|
342
|
+
| "https://www.glossarist.org/ontologies/hasSubfigure"
|
|
343
|
+
| "https://www.glossarist.org/ontologies/src"
|
|
344
|
+
| "https://www.glossarist.org/ontologies/format"
|
|
345
|
+
| "https://www.glossarist.org/ontologies/role"
|
|
314
346
|
| "https://www.glossarist.org/ontologies/pronunciationContent"
|
|
315
347
|
| "https://www.glossarist.org/ontologies/pronunciationLanguage"
|
|
316
348
|
| "https://www.glossarist.org/ontologies/pronunciationScript"
|
package/src/rdf/predicates.js
CHANGED
|
@@ -26,6 +26,12 @@ export const PRED = {
|
|
|
26
26
|
"DesignationRelationship": "https://www.glossarist.org/ontologies/DesignationRelationship",
|
|
27
27
|
"ConceptDate": "https://www.glossarist.org/ontologies/ConceptDate",
|
|
28
28
|
"NonVerbalRepresentation": "https://www.glossarist.org/ontologies/NonVerbalRepresentation",
|
|
29
|
+
"NonVerbalEntity": "https://www.glossarist.org/ontologies/NonVerbalEntity",
|
|
30
|
+
"SharedNonVerbalEntity": "https://www.glossarist.org/ontologies/SharedNonVerbalEntity",
|
|
31
|
+
"Figure": "https://www.glossarist.org/ontologies/Figure",
|
|
32
|
+
"Table": "https://www.glossarist.org/ontologies/Table",
|
|
33
|
+
"Formula": "https://www.glossarist.org/ontologies/Formula",
|
|
34
|
+
"FigureImage": "https://www.glossarist.org/ontologies/FigureImage",
|
|
29
35
|
"CustomLocality": "https://www.glossarist.org/ontologies/CustomLocality",
|
|
30
36
|
"Locality": "https://www.glossarist.org/ontologies/Locality",
|
|
31
37
|
"DatasetRegister": "https://www.glossarist.org/ontologies/DatasetRegister",
|
|
@@ -69,6 +75,16 @@ export const PRED = {
|
|
|
69
75
|
"isTruncation": "https://www.glossarist.org/ontologies/isTruncation",
|
|
70
76
|
"text": "https://www.glossarist.org/ontologies/text",
|
|
71
77
|
"image": "https://www.glossarist.org/ontologies/image",
|
|
78
|
+
"caption": "https://www.glossarist.org/ontologies/caption",
|
|
79
|
+
"altText": "https://www.glossarist.org/ontologies/altText",
|
|
80
|
+
"description": "https://www.glossarist.org/ontologies/description",
|
|
81
|
+
"expression": "https://www.glossarist.org/ontologies/expression",
|
|
82
|
+
"latexForm": "https://www.glossarist.org/ontologies/latexForm",
|
|
83
|
+
"content": "https://www.glossarist.org/ontologies/content",
|
|
84
|
+
"hasSubfigure": "https://www.glossarist.org/ontologies/hasSubfigure",
|
|
85
|
+
"src": "https://www.glossarist.org/ontologies/src",
|
|
86
|
+
"format": "https://www.glossarist.org/ontologies/format",
|
|
87
|
+
"role": "https://www.glossarist.org/ontologies/role",
|
|
72
88
|
"pronunciationContent": "https://www.glossarist.org/ontologies/pronunciationContent",
|
|
73
89
|
"pronunciationLanguage": "https://www.glossarist.org/ontologies/pronunciationLanguage",
|
|
74
90
|
"pronunciationScript": "https://www.glossarist.org/ontologies/pronunciationScript",
|
package/src/rdf/shacl.js
CHANGED
|
@@ -91,8 +91,9 @@ export function quadsToDataset(quads) {
|
|
|
91
91
|
return ds;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
94
|
+
// Clears the in-memory shapes cache. Exposed as part of the public API
|
|
95
|
+
// so callers (including tests) can force a fresh load when the
|
|
96
|
+
// underlying shapes file changes during a process's lifetime.
|
|
97
|
+
export function clearShapesCache() {
|
|
97
98
|
SHAPES_CACHE.clear();
|
|
98
99
|
}
|