glossarist 0.4.1 → 0.4.3
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/README.md +44 -0
- package/data/concept-model/shapes/glossarist.shacl.ttl +704 -0
- package/package.json +24 -4
- package/src/concept-collection.js +57 -0
- package/src/concept-parser.js +1 -1
- package/src/concept-reader.js +1 -1
- package/src/concept-serializer.js +1 -1
- package/src/gcr-reader.js +1 -1
- package/src/index.js +15 -0
- package/src/models/bibliography-data.js +1 -1
- package/src/models/concept.js +6 -0
- package/src/models/dataset-color.js +79 -0
- package/src/models/designation.js +54 -0
- package/src/models/gcr-metadata.js +1 -1
- package/src/models/index.d.ts +121 -4
- package/src/models/index.js +13 -0
- package/src/models/register.js +99 -1
- package/src/models/relation-categories.js +151 -0
- package/src/models/relation-colors.js +78 -0
- package/src/rdf/deterministic-id.js +17 -0
- package/src/rdf/document-writer.js +87 -0
- package/src/rdf/gloss-concept.js +43 -0
- package/src/rdf/gloss-designation.js +72 -0
- package/src/rdf/gloss-detailed-definition.js +69 -0
- package/src/rdf/gloss-localized-concept.js +72 -0
- package/src/rdf/gloss-source.js +51 -0
- package/src/rdf/index.d.ts +107 -0
- package/src/rdf/index.js +27 -0
- package/src/rdf/normalize-enum.js +23 -0
- package/src/rdf/predicates.d.ts +443 -0
- package/src/rdf/predicates.js +245 -0
- package/src/rdf/prefixes.js +31 -0
- package/src/rdf/shacl.js +98 -0
- package/src/rdf/terms.js +15 -0
- package/src/transforms/concept-to-gloss.transform.js +75 -0
- package/src/transforms/index.d.ts +26 -0
- package/src/transforms/index.js +1 -0
- package/src/v1-reader.js +1 -1
- package/src/validators/gcr-validator.js +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// LocalizedConcept → RDF quads. Mirrors glossarist-ruby's
|
|
2
|
+
// `Rdf::GlossLocalizedConcept` + the `EmitsExtraTriples` hook.
|
|
3
|
+
//
|
|
4
|
+
// Emits BOTH reified SKOS-XL labels AND direct SKOS literals, so consumers
|
|
5
|
+
// that don't implement SKOS-XL still see labels/definitions/notes/examples
|
|
6
|
+
// as plain literals. This is the same shape glossarist-ruby emits after
|
|
7
|
+
// WS-B Phase 1.
|
|
8
|
+
import { PRED, PREFIXES } from './predicates.js';
|
|
9
|
+
import { WELL_KNOWN } from './prefixes.js';
|
|
10
|
+
import { designationToQuads, skosLabelPredicate } from './gloss-designation.js';
|
|
11
|
+
import { detailedDefinitionToQuads } from './gloss-detailed-definition.js';
|
|
12
|
+
import { conceptSourceToQuads } from './gloss-source.js';
|
|
13
|
+
import { namedNode, literal, quad } from './terms.js';
|
|
14
|
+
const DCTERMS_LANGUAGE = `${PREFIXES.dcterms}language`;
|
|
15
|
+
|
|
16
|
+
export function localizedConceptUri(parentUri, language) {
|
|
17
|
+
return `${parentUri}/${language}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function* localizedConceptToQuads(localizedConcept, { parentUri, language }) {
|
|
21
|
+
const subjectUri = localizedConceptUri(parentUri, language);
|
|
22
|
+
const s = namedNode(subjectUri);
|
|
23
|
+
|
|
24
|
+
yield quad(s, namedNode(WELL_KNOWN.rdfType), namedNode(PRED.gloss.LocalizedConcept));
|
|
25
|
+
yield quad(s, namedNode(WELL_KNOWN.rdfType), namedNode(WELL_KNOWN.skosConcept));
|
|
26
|
+
yield quad(s, namedNode(PRED.gloss.isLocalizationOf), namedNode(parentUri));
|
|
27
|
+
yield quad(s, namedNode(DCTERMS_LANGUAGE), literal(language));
|
|
28
|
+
|
|
29
|
+
if (localizedConcept.entryStatus) {
|
|
30
|
+
yield quad(s, namedNode(PRED.gloss.hasEntryStatus), namedNode(`${PRED.gloss.$ns}entstatus/${localizedConcept.entryStatus}`));
|
|
31
|
+
}
|
|
32
|
+
if (localizedConcept.domain) {
|
|
33
|
+
yield quad(s, namedNode(PRED.gloss.domain), literal(localizedConcept.domain));
|
|
34
|
+
}
|
|
35
|
+
if (localizedConcept.release) {
|
|
36
|
+
yield quad(s, namedNode(PRED.gloss.release), literal(localizedConcept.release));
|
|
37
|
+
}
|
|
38
|
+
if (localizedConcept.script) {
|
|
39
|
+
yield quad(s, namedNode(PRED.gloss.script), literal(localizedConcept.script));
|
|
40
|
+
}
|
|
41
|
+
if (localizedConcept.system) {
|
|
42
|
+
yield quad(s, namedNode(PRED.gloss.conversionSystem), literal(localizedConcept.system));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let desigIndex = 0;
|
|
46
|
+
for (const designation of localizedConcept.terms ?? []) {
|
|
47
|
+
yield* designationToQuads(designation, { subjectUri, language, index: desigIndex });
|
|
48
|
+
// Direct SKOS literal alongside the reified SKOS-XL form.
|
|
49
|
+
yield quad(s, namedNode(skosLabelPredicate(designation)), literal(designation.designation, language));
|
|
50
|
+
desigIndex += 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
yield* definitionsToQuads(localizedConcept.definitions, { subjectUri, language, role: 'hasDefinition' });
|
|
54
|
+
yield* definitionsToQuads(localizedConcept.notes, { subjectUri, language, role: 'hasNote' });
|
|
55
|
+
yield* definitionsToQuads(localizedConcept.examples, { subjectUri, language, role: 'hasExample' });
|
|
56
|
+
yield* definitionsToQuads(localizedConcept.annotations, { subjectUri, language, role: 'hasAnnotation' });
|
|
57
|
+
|
|
58
|
+
let srcIndex = 0;
|
|
59
|
+
for (const source of localizedConcept.sources ?? []) {
|
|
60
|
+
yield* conceptSourceToQuads(source, { subjectUri, index: srcIndex });
|
|
61
|
+
srcIndex += 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function* definitionsToQuads(definitions, { subjectUri, language, role }) {
|
|
66
|
+
if (!definitions) return;
|
|
67
|
+
let i = 0;
|
|
68
|
+
for (const def of definitions) {
|
|
69
|
+
yield* detailedDefinitionToQuads(def, { subjectUri, language, index: i, role });
|
|
70
|
+
i += 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// ConceptSource → RDF quads. Mirrors glossarist-ruby's
|
|
2
|
+
// `Rdf::GlossConceptSource` + `Rdf::GlossCitation`. Sources are reified
|
|
3
|
+
// resources linked from their parent (concept or localized concept or
|
|
4
|
+
// definition) via `gloss:hasSource`.
|
|
5
|
+
import { PRED } from './predicates.js';
|
|
6
|
+
import { WELL_KNOWN } from './prefixes.js';
|
|
7
|
+
import { deterministicBnode } from './deterministic-id.js';
|
|
8
|
+
import { normalizeEnum } from './normalize-enum.js';
|
|
9
|
+
import { namedNode, literal, quad } from './terms.js';
|
|
10
|
+
|
|
11
|
+
export function* conceptSourceToQuads(source, { subjectUri, index }) {
|
|
12
|
+
const srcSubject = deterministicBnode(subjectUri, 'source', index);
|
|
13
|
+
|
|
14
|
+
yield quad(namedNode(subjectUri), namedNode(PRED.gloss.hasSource), namedNode(srcSubject));
|
|
15
|
+
yield quad(namedNode(srcSubject), namedNode(WELL_KNOWN.rdfType), namedNode(PRED.gloss.ConceptSource));
|
|
16
|
+
|
|
17
|
+
const statusToken = normalizeEnum(source.status);
|
|
18
|
+
if (statusToken) {
|
|
19
|
+
yield quad(namedNode(srcSubject), namedNode(PRED.gloss.sourceStatus), namedNode(`${PRED.gloss.$ns}srcstatus/${statusToken}`));
|
|
20
|
+
}
|
|
21
|
+
const typeToken = normalizeEnum(source.type);
|
|
22
|
+
if (typeToken) {
|
|
23
|
+
yield quad(namedNode(srcSubject), namedNode(PRED.gloss.sourceType), namedNode(`${PRED.gloss.$ns}srctype/${typeToken}`));
|
|
24
|
+
}
|
|
25
|
+
if (source.modification) {
|
|
26
|
+
yield quad(namedNode(srcSubject), namedNode(PRED.gloss.modification), literal(source.modification));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (source.origin) {
|
|
30
|
+
yield* citationToQuads(source.origin, { subjectUri: srcSubject });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function* citationToQuads(citation, { subjectUri }) {
|
|
35
|
+
const citSubject = deterministicBnode(subjectUri, 'origin', 0);
|
|
36
|
+
yield quad(namedNode(subjectUri), namedNode(PRED.gloss.sourceOrigin), namedNode(citSubject));
|
|
37
|
+
yield quad(namedNode(citSubject), namedNode(WELL_KNOWN.rdfType), namedNode(PRED.gloss.Citation));
|
|
38
|
+
|
|
39
|
+
if (citation.original) {
|
|
40
|
+
yield quad(namedNode(citSubject), namedNode(PRED.gloss.citationOriginal), literal(citation.original));
|
|
41
|
+
}
|
|
42
|
+
if (citation.link) {
|
|
43
|
+
yield quad(namedNode(citSubject), namedNode(PRED.gloss.citationLink), literal(citation.link));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (citation.ref) {
|
|
47
|
+
if (citation.ref.source) yield quad(namedNode(citSubject), namedNode(PRED.gloss.citationRefSource), literal(citation.ref.source));
|
|
48
|
+
if (citation.ref.id) yield quad(namedNode(citSubject), namedNode(PRED.gloss.citationRefId), literal(citation.ref.id));
|
|
49
|
+
if (citation.ref.version) yield quad(namedNode(citSubject), namedNode(PRED.gloss.citationRefVersion), literal(citation.ref.version));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Type declarations for the public RDF layer.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors the runtime exports of src/rdf/index.js. Quads use the RDF/JS
|
|
4
|
+
// Quad interface from @rdfjs/dataset (compatible with n3's DataFactory
|
|
5
|
+
// output). Dataset is the RDF/JS Dataset.Core interface.
|
|
6
|
+
|
|
7
|
+
import type { Quad, Dataset, Term } from '@rdfjs/dataset';
|
|
8
|
+
import type { Concept } from '../models/index';
|
|
9
|
+
import type { LocalizedConcept } from '../models/index';
|
|
10
|
+
import type { Designation } from '../models/index';
|
|
11
|
+
import type { DetailedDefinition } from '../models/index';
|
|
12
|
+
import type { ConceptSource } from '../models/index';
|
|
13
|
+
|
|
14
|
+
export { PRED, PREFIXES } from './predicates';
|
|
15
|
+
export type PredicateMap = typeof PRED;
|
|
16
|
+
export type PrefixMap = typeof PREFIXES;
|
|
17
|
+
|
|
18
|
+
export type { Quad, Dataset, Term };
|
|
19
|
+
|
|
20
|
+
export const SKOSXL: {
|
|
21
|
+
prefLabel: string;
|
|
22
|
+
altLabel: string;
|
|
23
|
+
hiddenLabel: string;
|
|
24
|
+
literalForm: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const WELL_KNOWN: {
|
|
28
|
+
rdfType: string;
|
|
29
|
+
rdfValue: string;
|
|
30
|
+
skosConcept: string;
|
|
31
|
+
skosxlLabel: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export declare function deterministicId(...parts: Array<string | number | null | undefined>): string;
|
|
35
|
+
export declare function deterministicBnode(subject: string, role: string, index: number): string;
|
|
36
|
+
|
|
37
|
+
export interface ConceptUriOptions {
|
|
38
|
+
registerId: string;
|
|
39
|
+
uriBase?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare function conceptUri(concept: Concept | { id?: string; termid?: string }, options: ConceptUriOptions): string;
|
|
43
|
+
export declare function conceptToQuads(concept: Concept, options: ConceptUriOptions): Generator<Quad, void, unknown>;
|
|
44
|
+
|
|
45
|
+
export interface LocalizedConceptEmitOptions {
|
|
46
|
+
parentUri: string;
|
|
47
|
+
language: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export declare function localizedConceptUri(parentUri: string, language: string): string;
|
|
51
|
+
export declare function localizedConceptToQuads(localizedConcept: LocalizedConcept, options: LocalizedConceptEmitOptions): Generator<Quad, void, unknown>;
|
|
52
|
+
|
|
53
|
+
export interface DesignationEmitOptions {
|
|
54
|
+
subjectUri: string;
|
|
55
|
+
language: string;
|
|
56
|
+
index: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export declare function designationToQuads(designation: Designation, options: DesignationEmitOptions): Generator<Quad, void, unknown>;
|
|
60
|
+
export declare function skosLabelPredicate(designation: Designation): string;
|
|
61
|
+
export declare function skosxlLabelPredicate(designation: Designation): string;
|
|
62
|
+
|
|
63
|
+
export interface DetailedDefinitionEmitOptions {
|
|
64
|
+
subjectUri: string;
|
|
65
|
+
language?: string;
|
|
66
|
+
index: number;
|
|
67
|
+
role: 'hasDefinition' | 'hasNote' | 'hasExample' | 'hasAnnotation' | 'hasScopedExample';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export declare function detailedDefinitionToQuads(definition: DetailedDefinition, options: DetailedDefinitionEmitOptions): Generator<Quad, void, unknown>;
|
|
71
|
+
|
|
72
|
+
export interface ConceptSourceEmitOptions {
|
|
73
|
+
subjectUri: string;
|
|
74
|
+
index: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export declare function conceptSourceToQuads(source: ConceptSource, options: ConceptSourceEmitOptions): Generator<Quad, void, unknown>;
|
|
78
|
+
|
|
79
|
+
export declare function collectQuads(quadsIterable: Iterable<Quad>): Quad[];
|
|
80
|
+
|
|
81
|
+
export interface WriteTurtleOptions {
|
|
82
|
+
prefixes?: Record<string, string>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export declare function writeTurtle(quads: Iterable<Quad>, options?: WriteTurtleOptions): Promise<string>;
|
|
86
|
+
export declare function writeNTriples(quads: Iterable<Quad>): Promise<string>;
|
|
87
|
+
|
|
88
|
+
export interface WriteJsonldOptions {
|
|
89
|
+
context?: Record<string, string>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export declare function writeJsonld(quads: Iterable<Quad>, options?: WriteJsonldOptions): Promise<string>;
|
|
93
|
+
export declare function sortQuads(quads: Iterable<Quad>): Quad[];
|
|
94
|
+
|
|
95
|
+
export interface ValidationReport {
|
|
96
|
+
conforms: boolean;
|
|
97
|
+
results: ReadonlyArray<{
|
|
98
|
+
focusNode?: Term;
|
|
99
|
+
shape?: Term;
|
|
100
|
+
path?: Term;
|
|
101
|
+
message: Term[];
|
|
102
|
+
}>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export declare function loadShapes(): Promise<Dataset>;
|
|
106
|
+
export declare function validateShacl(dataDataset: Dataset, options?: { shapes?: Dataset }): Promise<ValidationReport>;
|
|
107
|
+
export declare function quadsToDataset(quads: Iterable<Quad>): Dataset;
|
package/src/rdf/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Public RDF layer. Mirrors lib/glossarist/rdf/ in glossarist-ruby.
|
|
2
|
+
export { PRED, PREFIXES, SKOSXL, WELL_KNOWN } from './prefixes.js';
|
|
3
|
+
export { deterministicId, deterministicBnode } from './deterministic-id.js';
|
|
4
|
+
export { namedNode, blankNode, literal, defaultGraph, quad } from './terms.js';
|
|
5
|
+
export {
|
|
6
|
+
conceptUri,
|
|
7
|
+
conceptToQuads,
|
|
8
|
+
} from './gloss-concept.js';
|
|
9
|
+
export {
|
|
10
|
+
localizedConceptUri,
|
|
11
|
+
localizedConceptToQuads,
|
|
12
|
+
} from './gloss-localized-concept.js';
|
|
13
|
+
export {
|
|
14
|
+
designationToQuads,
|
|
15
|
+
skosLabelPredicate,
|
|
16
|
+
skosxlLabelPredicate,
|
|
17
|
+
} from './gloss-designation.js';
|
|
18
|
+
export { detailedDefinitionToQuads } from './gloss-detailed-definition.js';
|
|
19
|
+
export { conceptSourceToQuads } from './gloss-source.js';
|
|
20
|
+
export {
|
|
21
|
+
collectQuads,
|
|
22
|
+
writeTurtle,
|
|
23
|
+
writeNTriples,
|
|
24
|
+
writeJsonld,
|
|
25
|
+
sortQuads,
|
|
26
|
+
} from './document-writer.js';
|
|
27
|
+
export { validateShacl, loadShapes, quadsToDataset } from './shacl.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Helpers for normalizing enumeration values that get interpolated into
|
|
2
|
+
// URIs. Source data may contain compound forms ("preferred/admitted") or
|
|
3
|
+
// path-like values that must be reduced to a single local name before
|
|
4
|
+
// being embedded in a URI, otherwise the URI is malformed.
|
|
5
|
+
|
|
6
|
+
// Returns the last path segment of an enumeration value.
|
|
7
|
+
// Examples:
|
|
8
|
+
// 'preferred' → 'preferred'
|
|
9
|
+
// 'preferred/admitted' → 'admitted'
|
|
10
|
+
// 'http://x/ns#preferred' → 'preferred'
|
|
11
|
+
// '' / null / undefined → '' (caller decides whether to skip emission)
|
|
12
|
+
export function normalizeEnum(value) {
|
|
13
|
+
if (value == null) return '';
|
|
14
|
+
const s = String(value).trim();
|
|
15
|
+
if (!s) return '';
|
|
16
|
+
const parts = s.split(/[/#]/);
|
|
17
|
+
return parts[parts.length - 1];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// True when normalizeEnum would produce a non-empty token.
|
|
21
|
+
export function hasEnumValue(value) {
|
|
22
|
+
return normalizeEnum(value).length > 0;
|
|
23
|
+
}
|