glossarist-js
JavaScript SDK for reading and writing Glossarist GCR packages — manages terminology concepts with rich domain models, bidirectional YAML serialization, validation, cross-reference resolution, RDF serializers, and SHACL validation.
Current version: v0.4.15 — full model parity with glossarist-ruby, synced to concept-model v3.1.0.
Install
npm install glossarist
Requires Node.js 20+.
Usage
Read a GCR package
import { loadGcr } from 'glossarist';
const pkg = await loadGcr(fs.readFileSync('my-dataset.gcr'));
const meta = await pkg.metadata();
await pkg.eachConcept((concept) => {
console.log(concept.id, concept.primaryDesignation('eng'));
});
Read from a directory
import { readConcepts, readRegister } from 'glossarist';
const concepts = readConcepts('./geolexica-v2/');
const register = readRegister('./geolexica-v2/');
Write a GCR package
import { createGcr, ManagedConceptCollection, conceptParser } from 'glossarist';
const concept = conceptParser.parse(`
termid: "3.1.1.1"
eng:
terms:
- type: expression
designation: entity
definition:
- content: A concrete or abstract thing.
`);
const buf = await createGcr([concept], { shortname: 'test' });
fs.writeFileSync('out.gcr', buf);
What’s new in 0.4
| Version | Highlights |
|---|---|
| 0.4.15 | Browser-safety split: glossarist/rdf/shacl extracted as its own subpath so the validator’s Node-only deps can’t leak into bundles that only need serialization |
| 0.4.14 | RDF sections-builder compacts classId and predicates to CURIE form |
| 0.4.13 | Register.name added; BibliographyData accepts bare-array shape; unified CURIE / blank-node ID / sections-builder / provenance-emitter refactor; rdf-validate-shacl 0.6 compat |
| 0.4.12 | Remove hardcoded glossarist.org base URI defaults — base URI is now always caller-supplied |
| 0.4.11 | writeTurtleSync — synchronous Turtle writer for CLI/build scripts |
| 0.4.10 | Fix dataset distribution blank-node serialization (_:bXXX not <_:bXXX>) |
| 0.4.9 | Domain RDF emitters — vocabulary (SKOS ConceptSchemes), dataset (dcat:Dataset), group (dcat:DatasetSeries / dcat:Catalog), bibliography (dcterms:BibliographicResource), provenance (prov:Activity, foaf:Person); section descendant closure; relation categories reconciled with concept-browser |
| 0.4.8 | glossarist/rdf/prefixes subpath export for browser-safe prefix lookup |
| 0.4.7 | Type exports for dataset-color and relation-categories from models/index.d.ts |
| 0.4.6 | Sync concept-model v3.1.0; NonVerbal RDF emitters (Figure / Table / Formula) |
| 0.4.5 | NonVerbal entity emitters + concept-model drift test |
| 0.4.4 | Concept-model synced to v3.1.0; RDF + transforms kept out of the main entry (browser-safe) |
| 0.4.3 | RDF serializers (Turtle, N-Triples, JSON-LD) + SHACL validator (WS C) |
| 0.4.2–0.4.0 | Type cleanup, js-yaml 5.x, Node 24 CI, eslint 10.x |
| 0.3.8 | DesignationRelationship model, mention syntax with URN + designation forms, out-of-line citations |
| 0.3.7 | Annotations, validation and search improvements |
| 0.3.6 | ISO 19135 relationship types added to RELATIONSHIP_TYPES enum |
| 0.3.5 | Register and Section models with hierarchical section support |
| 0.3.4 | Scoped examples in DetailedDefinition, walkTexts text-walking |
| 0.3.3 | Non-verbal entities: Figure, Table, Formula + V3 bibliography |
RDF serialization & SHACL validation
v0.4.3 adds a complete RDF pipeline. Every concept can be serialized to Turtle, N-Triples, or JSON-LD, and a SHACL validator runs the canonical glossarist.shacl.ttl shapes against the resulting graph. Since v0.4.15 the SHACL validator lives in its own glossarist/rdf/shacl subpath so its Node-only dependencies can’t leak into browser bundles that only need serialization.
import { ConceptCollection, RdfSerializer } from 'glossarist/rdf';
import { ShaclValidator } from 'glossarist/rdf/shacl';
const ttl = await RdfSerializer.serialize(collection, { format: 'turtle' });
const report = await ShaclValidator.validate(ttl, { format: 'turtle' });
if (!report.conforms) {
for (const result of report.results) {
console.warn(result.path, result.message);
}
}
RDF and transforms live in dedicated subpath exports so the main entry stays browser-safe — no Node-only dependencies leaked into the bundle.
Domain RDF emitters (v0.4.9)
Beyond per-concept serialization, v0.4.9 adds emitters for the surrounding linked-data graph: datasets, groups, vocabularies, bibliographies, and build provenance. These are what the concept-browser uses to produce its RDF artifacts.
| Emitter | RDF type | Output |
|---|---|---|
vocabulary-emitter | skos:ConceptScheme | Cross-dataset vocabulary graph |
dataset-emitter | dcat:Dataset + skos:ConceptScheme | Per-register dataset metadata + sections tree |
group-emitter | dcat:DatasetSeries / dcat:Catalog | Lineage series or topic/family/collection groupings |
bibliography-emitter | dcterms:BibliographicResource | Bibliography graph from bibliography.yaml |
provenance-emitters | prov:Activity, prov:SoftwareAgent, foaf:Person, prov:Entity | Build run, contributors, version chain |
Section membership is closed downward — section.descendants() returns the transitive set of child sections, so a concept tagged with 1.2 is also a member of 1 and the dataset root. Relation categories are reconciled with concept-browser so both libraries agree on broader/narrower/exact_match/etc. coloring.
Mention syntax
Concept text supports inline mentions for sources, figures, and designations:
import { parseMention } from 'glossarist';
parseMention('{{cite:iso-704}}'); // → { kind: 'cite', id: 'iso-704' }
parseMention('{{fig:quantity-diagram}}'); // → { kind: 'fig', id: 'quantity-diagram' }
parseMention('{{urn:iso:...:1.1}}'); // → { kind: 'urn', id: 'urn:iso:...:1.1', text: undefined }
The ID always comes first; display text, when present, comes last.
Dataset model (v3)
import { Register, Section, Figure, Table, Formula } from 'glossarist/models';
const section = new Section({
id: '1.2',
names: { eng: 'Quantities', fra: 'Grandeurs' },
children: [{ id: '1.2.1', names: { eng: 'General' } }],
});
const figure = new Figure({
id: 'quantity-classification',
caption: { eng: 'Classification of quantities' },
alt: { eng: 'Diagram of quantity types' },
images: [{ src: 'quantity-classification.svg', format: 'svg' }],
});
Rich domain models
Every domain entity is a class instance with toJSON(), fromJSON(), equals(), and clone():
import { Concept, LocalizedConcept, Expression, DetailedDefinition } from 'glossarist/models';
const lc = new LocalizedConcept({
language_code: 'eng',
terms: [{ type: 'expression', designation: 'entity', normative_status: 'preferred' }],
definition: [{ content: 'A concrete or abstract thing.' }],
entry_status: 'valid',
});
const concept = new Concept({ id: '3.1.1.1', localizations: { eng: lc.toJSON() } });
console.log(concept.primaryDesignation('eng')); // 'entity'
console.log(concept.equals(Concept.fromJSON(concept.toJSON()))); // true
Compiled / machine formats in GCR
GCR packages can contain pre-compiled machine formats (TBX, JSON-LD, Turtle, JSONL) inside a compiled/ directory.
const pkg = await loadGcr(fs.readFileSync('dataset.gcr'));
const formats = await pkg.compiledFormats(); // ['tbx', 'jsonld', 'turtle']
const ids = await pkg.compiledFormatIds('jsonld');
const jsonld = await pkg.compiledFile('jsonld', '3.1.1.1');
Bibliography and images
GCR packages can carry a bibliography.yaml file and an images/ directory — making the archive fully self-contained.
const pkg = await loadGcr(fs.readFileSync('dataset.gcr'));
const bib = await pkg.bibliography(); // raw YAML string or null
await pkg.hasImages(); // true
const names = await pkg.imageFileNames(); // ['images/fig1.png', ...]
const img = await pkg.imageFile('fig1.png'); // Uint8Array or null
Validation
import { validateConcept, validateRegister, createConceptValidator, ValidationRule } from 'glossarist';
const result = validateConcept(concept);
if (!result.valid) {
for (const err of result.errors) console.error(err.path, err.message);
}
// Custom rule
class MyRule extends ValidationRule {
validate(concept) { /* return array of errors */ }
}
const validate = createConceptValidator([new MyRule()]);
Format registry
import { COMPILED_FORMATS, COMPILED_EXTENSIONS, isKnownFormat } from 'glossarist';
COMPILED_FORMATS; // ['tbx', 'jsonld', 'turtle', 'jsonl']
COMPILED_EXTENSIONS.get('tbx'); // 'tbx.xml'
isKnownFormat('csv'); // false
Subpath exports
glossarist— main entry (browser-safe: readers, writers, models, validators)glossarist/models— domain model classesglossarist/rdf— RDF serializers (Turtle, N-Triples, JSON-LD) + domain emittersglossarist/rdf/prefixes— browser-safe prefix lookup (canonical prefix SSOT)glossarist/rdf/shacl— SHACL validator (Node-only deps; isolated since v0.4.15 so it can’t leak into browser bundles)glossarist/validators—ValidationRuleframework and built-in rulesglossarist/gcr—loadGcr,createGcr,GcrReader,GcrWriter
Links
See Also
- Concept Model docs — the entity model this SDK implements
- Datasets & sections — V3 self-describing dataset model
- Non-verbal entities — figures, tables, formulas
- Standards compliance — ISO standard mappings