@glossarist/concept-browser 0.7.63 → 0.7.64

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glossarist/concept-browser",
3
- "version": "0.7.63",
3
+ "version": "0.7.64",
4
4
  "description": "Vue SPA for browsing Glossarist terminology datasets with cross-reference resolution, graph visualization, and multi-language support",
5
5
  "type": "module",
6
6
  "bin": {
@@ -49,7 +49,8 @@ function extractReferences(concept, registerId) {
49
49
  }
50
50
 
51
51
  function extractDomains(concept, registerId, uriBase) {
52
- const base = uriBase || 'https://glossarist.org';
52
+ if (!uriBase) throw new Error('build-edges: uriBase is required — set uriBase in site-config.yml');
53
+ const base = uriBase;
53
54
  const edges = [];
54
55
  const sourceUri = concept['@id'];
55
56
  const seen = new Set();
@@ -188,7 +189,8 @@ function buildEdgesForDataset(datasetDir, registerId, uriBase, urnMap, manifest)
188
189
  // Build domain-nodes.json from manifest sections (authoritative source)
189
190
  const manifestSections = manifest.sections;
190
191
  if (manifestSections && manifestSections.length > 0) {
191
- const uriBase = manifest.uriBase || 'https://glossarist.org';
192
+ const uriBase = manifest.uriBase;
193
+ if (!uriBase) throw new Error('build-edges: manifest.uriBase is required');
192
194
 
193
195
  function buildSectionNode(section, idx) {
194
196
  const sectionId = `section-${section.id}`;
@@ -293,7 +295,8 @@ for (const ds of datasets) {
293
295
  if (!manifest) continue;
294
296
  try {
295
297
  console.log(`${manifest.title} (${ds}):`);
296
- const uriBase = manifest.uriBase || 'https://glossarist.org';
298
+ const uriBase = manifest.uriBase;
299
+ if (!uriBase) throw new Error('build-edges: manifest.uriBase is required');
297
300
  const result = buildEdgesForDataset(join(DATA_DIR, ds), ds, uriBase, urnMap, manifest);
298
301
  allDatasetEdges.set(ds, result.edges);
299
302
  allSourceRefs.push(...result.sourceRefs);
@@ -347,7 +350,8 @@ if (auditUnmatched.size > 0) {
347
350
  // edges.json contains edges targeting that dataset's URIs.
348
351
  const datasetUriPrefixes = new Map();
349
352
  for (const [ds, manifest] of manifestCache) {
350
- const uriBase = manifest.uriBase || 'https://glossarist.org';
353
+ const uriBase = manifest.uriBase;
354
+ if (!uriBase) throw new Error('build-edges: manifest.uriBase is required');
351
355
  datasetUriPrefixes.set(ds, `${uriBase}/${ds}/`);
352
356
  }
353
357
 
@@ -92,7 +92,8 @@ function writeJson(filePath, data) {
92
92
  }
93
93
 
94
94
  async function writeDatasetRdf(register, manifest, concepts, refMaps, opts) {
95
- const uriBase = refMaps?.uriBase ?? 'https://glossarist.org';
95
+ const uriBase = refMaps?.uriBase;
96
+ if (!uriBase) throw new Error('generate-data: uriBase is required — set uriBase in site-config.yml');
96
97
  const datasetIri = `${uriBase}/${register}/`;
97
98
  const topConceptUris = concepts
98
99
  .slice(0, 32)
@@ -375,7 +376,8 @@ function buildRefMaps(config, registerCache) {
375
376
  const xref = config.crossReferences || {};
376
377
  if (xref.refPrefixMap) Object.assign(refPrefixMap, xref.refPrefixMap);
377
378
 
378
- const uriBase = config.uriBase || `https://${config.domain}`;
379
+ const uriBase = config.uriBase;
380
+ if (!uriBase) throw new Error('site-config.yml: uriBase is required');
379
381
  return { patternIndex, refPrefixMap, uriBase, register: null };
380
382
  }
381
383
 
@@ -1617,7 +1619,7 @@ console.log('Emitted vocabulary graph: data/_vocab.ttl');
1617
1619
 
1618
1620
  const contributors = config.contributors ?? [];
1619
1621
  if (contributors.length > 0) {
1620
- fs.writeFileSync(path.join(DATA, 'agents.ttl'), await buildAgentsTurtle(contributors));
1622
+ fs.writeFileSync(path.join(DATA, 'agents.ttl'), await buildAgentsTurtle(contributors, refMaps.uriBase + '/agent'));
1621
1623
  console.log(`Emitted agents graph: data/agents.ttl (${contributors.length} contributors)`);
1622
1624
  }
1623
1625
 
@@ -1626,7 +1628,7 @@ for (const ds of registry) {
1626
1628
  const bibPath = path.join(DATA, ds.id, 'bibliography.json');
1627
1629
  if (fs.existsSync(bibPath)) {
1628
1630
  const bibJson = JSON.parse(fs.readFileSync(bibPath, 'utf8'));
1629
- const bibTtl = await buildBibliographyTurtle(ds.id, bibJson);
1631
+ const bibTtl = await buildBibliographyTurtle(ds.id, bibJson, refMaps.uriBase);
1630
1632
  fs.writeFileSync(path.join(DATA, ds.id, 'bib.ttl'), bibTtl);
1631
1633
  }
1632
1634
  }
@@ -19,7 +19,8 @@ function writerPrefixes() {
19
19
  };
20
20
  }
21
21
 
22
- export async function buildAgentsTurtle(contributors, agentBase = 'https://glossarist.org/agent') {
22
+ export async function buildAgentsTurtle(contributors, agentBase) {
23
+ if (!agentBase) throw new Error('buildAgentsTurtle requires agentBase');
23
24
  const agents = agentsFromContributors(contributors ?? [], agentBase);
24
25
  const quads = collectQuads(agentsToQuads(agents));
25
26
  return writeTurtle(quads, { prefixes: writerPrefixes() });
@@ -10,7 +10,7 @@ import {
10
10
  writeTurtle,
11
11
  } from 'glossarist/rdf';
12
12
 
13
- const DEFAULT_BASE_URI = 'https://glossarist.org';
13
+ // No hardcoded default base URI — callers MUST pass it.
14
14
 
15
15
  function writerPrefixes() {
16
16
  return {
@@ -22,7 +22,8 @@ function writerPrefixes() {
22
22
 
23
23
  export { normalizeBibliographyData };
24
24
 
25
- export async function buildBibliographyTurtle(register, bibliographyJson, baseUri = DEFAULT_BASE_URI) {
25
+ export async function buildBibliographyTurtle(register, bibliographyJson, baseUri) {
26
+ if (!baseUri) throw new Error('buildBibliographyTurtle requires baseUri');
26
27
  const entries = normalizeBibliographyData(bibliographyJson);
27
28
  const quads = collectQuads(bibliographyToQuads({ registerId: register, entries, baseUri }));
28
29
  return writeTurtle(quads, { prefixes: writerPrefixes() });
@@ -19,6 +19,7 @@ describe('DatasetAdapter', () => {
19
19
 
20
20
  beforeEach(() => {
21
21
  adapter = new DatasetAdapter('test', '/data/test');
22
+ adapter.manifest = { uriBase: 'https://glossarist.org' } as any;
22
23
  mockFetch.mockReset();
23
24
  });
24
25
 
@@ -16,13 +16,13 @@ const RDF_TYPE = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
16
16
 
17
17
  describe('buildAgentsTurtle (mjs)', () => {
18
18
  it('parses without errors', async () => {
19
- const ttl = await buildAgentsTurtle([{ name: 'Ada Lovelace' }]);
19
+ const ttl = await buildAgentsTurtle([{ name: 'Ada Lovelace' }], 'https://glossarist.org/agent');
20
20
  const store = parse(ttl);
21
21
  expect(store.size).toBeGreaterThan(0);
22
22
  });
23
23
 
24
24
  it('types each person as foaf:Person, prov:Person, prov:Agent', async () => {
25
- const ttl = await buildAgentsTurtle([{ name: 'Ada Lovelace' }]);
25
+ const ttl = await buildAgentsTurtle([{ name: 'Ada Lovelace' }], 'https://glossarist.org/agent');
26
26
  const store = parse(ttl);
27
27
  const types = store.getObjects('https://glossarist.org/agent/ada-lovelace', RDF_TYPE, null).map(q => q.value);
28
28
  expect(types).toContain(`${FOAF}Person`);
@@ -33,7 +33,7 @@ describe('buildAgentsTurtle (mjs)', () => {
33
33
  it('records name, mailto mbox, role, and seeAlso', async () => {
34
34
  const ttl = await buildAgentsTurtle([
35
35
  { name: 'Ada Lovelace', email: 'ada@example.org', role: 'Editor', url: 'https://example.org/ada' },
36
- ]);
36
+ ], 'https://glossarist.org/agent');
37
37
  const store = parse(ttl);
38
38
  const iri = 'https://glossarist.org/agent/ada-lovelace';
39
39
  expect(store.getObjects(iri, `${FOAF}name`, null).map(q => q.value)).toContain('Ada Lovelace');
@@ -46,7 +46,7 @@ describe('buildAgentsTurtle (mjs)', () => {
46
46
  const ttl = await buildAgentsTurtle([
47
47
  { name: 'Alice', organization: 'ISO' },
48
48
  { name: 'Bob', organization: 'ISO' },
49
- ]);
49
+ ], 'https://glossarist.org/agent');
50
50
  const store = parse(ttl);
51
51
  const types = store.getObjects('https://glossarist.org/org/iso', RDF_TYPE, null).map(q => q.value);
52
52
  expect(types).toContain(`${FOAF}Organization`);
@@ -54,7 +54,7 @@ describe('buildAgentsTurtle (mjs)', () => {
54
54
  });
55
55
 
56
56
  it('emits only prefix declarations for an empty input', async () => {
57
- const ttl = await buildAgentsTurtle([]);
57
+ const ttl = await buildAgentsTurtle([], 'https://glossarist.org/agent');
58
58
  expect(ttl).toContain('@prefix foaf:');
59
59
  expect(ttl).not.toContain('<https://glossarist.org/agent/');
60
60
  });
@@ -15,13 +15,13 @@ function parse(turtle: string): Store {
15
15
 
16
16
  describe('buildBibliographyTurtle (mjs)', () => {
17
17
  it('parses without errors', async () => {
18
- const ttl = await buildBibliographyTurtle('iso-geodetic', { iso704: { reference: 'ISO 704' } });
18
+ const ttl = await buildBibliographyTurtle('iso-geodetic', { iso704: { reference: 'ISO 704' } }, 'https://glossarist.org');
19
19
  const store = parse(ttl);
20
20
  expect(store.size).toBeGreaterThan(0);
21
21
  });
22
22
 
23
23
  it('types each entry as dcterms:BibliographicResource', async () => {
24
- const ttl = await buildBibliographyTurtle('iso-geodetic', { iso704: { reference: 'ISO 704' } });
24
+ const ttl = await buildBibliographyTurtle('iso-geodetic', { iso704: { reference: 'ISO 704' } }, 'https://glossarist.org');
25
25
  const store = parse(ttl);
26
26
  const types = store.getObjects('https://glossarist.org/iso-geodetic/bib/iso704', RDF_TYPE, null).map(q => q.value);
27
27
  expect(types).toContain(`${DCTERMS}BibliographicResource`);
@@ -30,7 +30,7 @@ describe('buildBibliographyTurtle (mjs)', () => {
30
30
  it('emits identifier, bibliographicCitation, and title', async () => {
31
31
  const ttl = await buildBibliographyTurtle('iso-geodetic', {
32
32
  iso704: { reference: 'ISO 704', title: 'Terminology work — Principles and methods' },
33
- });
33
+ }, 'https://glossarist.org');
34
34
  const store = parse(ttl);
35
35
  const iri = 'https://glossarist.org/iso-geodetic/bib/iso704';
36
36
  expect(store.getObjects(iri, `${DCTERMS}identifier`, null).map(q => q.value)).toContain('iso704');
@@ -41,7 +41,7 @@ describe('buildBibliographyTurtle (mjs)', () => {
41
41
  it('emits foaf:page when link is provided', async () => {
42
42
  const ttl = await buildBibliographyTurtle('iso-geodetic', {
43
43
  ref: { reference: 'X', link: 'https://example.org/x' },
44
- });
44
+ }, 'https://glossarist.org');
45
45
  const store = parse(ttl);
46
46
  const iri = 'https://glossarist.org/iso-geodetic/bib/ref';
47
47
  expect(store.getObjects(iri, `${FOAF}page`, null).map(q => q.value)).toContain('https://example.org/x');
@@ -51,7 +51,7 @@ describe('buildBibliographyTurtle (mjs)', () => {
51
51
  const ttl = await buildBibliographyTurtle('iso-geodetic', {
52
52
  a: { reference: 'A' },
53
53
  b: { reference: 'B' },
54
- });
54
+ }, 'https://glossarist.org');
55
55
  const store = parse(ttl);
56
56
  expect(store.getObjects('https://glossarist.org/iso-geodetic/bib/a', `${DCTERMS}bibliographicCitation`, null).map(q => q.value)).toContain('A');
57
57
  expect(store.getObjects('https://glossarist.org/iso-geodetic/bib/b', `${DCTERMS}bibliographicCitation`, null).map(q => q.value)).toContain('B');
@@ -61,7 +61,7 @@ describe('WS F Layer 8 — build pipeline integration', () => {
61
61
  it('agents-turtle.mjs produces parseable foaf:Person', () => {
62
62
  const out = runInline(`
63
63
  import { buildAgentsTurtle } from './scripts/lib/agents-turtle.mjs';
64
- console.log(await buildAgentsTurtle([{ name: 'Ada Lovelace', role: 'Editor', organization: 'Royal Society' }]));
64
+ console.log(await buildAgentsTurtle([{ name: 'Ada Lovelace', role: 'Editor', organization: 'Royal Society' }], 'https://glossarist.org/agent'));
65
65
  `);
66
66
  const store = parseTurtle(out);
67
67
  const persons = [...store].filter(q =>
@@ -74,7 +74,7 @@ describe('WS F Layer 8 — build pipeline integration', () => {
74
74
  it('bibliography-turtle.mjs produces parseable dcterms:BibliographicResource', () => {
75
75
  const out = runInline(`
76
76
  import { buildBibliographyTurtle } from './scripts/lib/bibliography-turtle.mjs';
77
- console.log(await buildBibliographyTurtle('test', { iso704: { reference: 'ISO 704' } }));
77
+ console.log(await buildBibliographyTurtle('test', { iso704: { reference: 'ISO 704' } }, 'https://glossarist.org'));
78
78
  `);
79
79
  const store = parseTurtle(out);
80
80
  const bibs = [...store].filter(q =>
@@ -122,8 +122,8 @@ describe('WS F Layer 8 — build pipeline integration', () => {
122
122
  await buildVocabularyTurtle(),
123
123
  await buildDatasetTurtle({ datasetIri: 'https://glossarist.org/test/', registerId: 'test', title: 't', modified: '2026-01-01', languages: ['eng'], distributions: [], topConceptUris: [], sections: [] }),
124
124
  await buildActivityTurtle({ runId: 'r', startedAt: '2026-01-01T00:00:00Z', endedAt: '2026-01-01T00:05:00Z', toolId: 'cb', toolVersion: '0', datasetRegisters: [], conceptCount: 0 }),
125
- await buildAgentsTurtle([{ name: 'Ada' }]),
126
- await buildBibliographyTurtle('test', { x: { reference: 'X' } }),
125
+ await buildAgentsTurtle([{ name: 'Ada' }], 'https://glossarist.org/agent'),
126
+ await buildBibliographyTurtle('test', { x: { reference: 'X' } }, 'https://glossarist.org'),
127
127
  await buildVersionHistoryTurtle({ registerId: 't', datasetIri: 'https://glossarist.org/t/', versions: [{ version: '1', generatedAt: '2026-01-01' }] }),
128
128
  ];
129
129
  console.log(parts.join('\\n'));
@@ -38,6 +38,7 @@ export function makeManifest(overrides: Partial<Manifest> = {}): Manifest {
38
38
 
39
39
  export interface AdapterStubOptions {
40
40
  concepts?: ConceptSummary[];
41
+ manifest?: Manifest | null;
41
42
  search?: () => SearchHit[];
42
43
  fetchConcept?: () => Promise<any>;
43
44
  getAdjacentConcepts?: () => { prev: string | null; next: string | null };
@@ -55,7 +56,7 @@ export interface AdapterStubOptions {
55
56
  export function makeAdapterStub(options: AdapterStubOptions = {}): any {
56
57
  return {
57
58
  index: options.concepts ?? [],
58
- manifest: null,
59
+ manifest: options.manifest ?? makeManifest(),
59
60
  registerId: 'test',
60
61
  getConceptCount: () => (options.concepts ?? []).length,
61
62
  getConcepts: () => options.concepts ?? [],
@@ -42,7 +42,9 @@ export class GraphDataSource {
42
42
  }
43
43
 
44
44
  private get uriBase(): string {
45
- return this.adapter.manifest?.uriBase || 'https://glossarist.org';
45
+ const uriBase = this.adapter.manifest?.uriBase;
46
+ if (!uriBase) throw new Error('GraphDataSource: manifest.uriBase is required');
47
+ return uriBase;
46
48
  }
47
49
 
48
50
  private get urnMap(): ReadonlyMap<string, string> {
@@ -113,7 +113,8 @@ let navDuration = 2200; /* mutable — shorter for expand changes than for conc
113
113
  async function loadNeighborTerms() {
114
114
  const factory = getFactory();
115
115
  const lang = sphereLang.value;
116
- const uriBase = props.manifest.uriBase || 'https://glossarist.org';
116
+ const uriBase = props.manifest.uriBase;
117
+ if (!uriBase) throw new Error('RelationSphere: manifest.uriBase is required');
117
118
  const neighborRegisters = new Set<string>();
118
119
 
119
120
  /* Phase 1: collect which neighbor datasets we need to load */
@@ -207,7 +207,8 @@ export const useVocabularyStore = defineStore('vocabulary', () => {
207
207
  // We do NOT call adapter.extractEdges(concept) here because that would duplicate
208
208
  // edges already present in edges.json, causing double-rendering of relations.
209
209
  const domainEdges = adapter.extractDomainEdges(concept);
210
- const uriBase = adapter.manifest?.uriBase || 'https://glossarist.org';
210
+ const uriBase = adapter.manifest?.uriBase;
211
+ if (!uriBase) throw new Error('vocabulary store: manifest.uriBase is required — set uriBase in site-config.yml');
211
212
  const uri = conceptUri(concept, registerId, uriBase);
212
213
 
213
214
  const designations: Record<string, string> = {};