@glossarist/concept-browser 0.7.7 → 0.7.8

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.7",
3
+ "version": "0.7.8",
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": {
@@ -679,10 +679,11 @@ function processDataset(dir, register, opts) {
679
679
  }));
680
680
 
681
681
  const graphNodeEntries = concepts.map(c => {
682
- let term = '', lang = '';
683
- if (c.designations.eng) { term = c.designations.eng; lang = 'eng'; }
684
- else { for (const [l, t] of Object.entries(c.designations)) { if (t) { term = t; lang = l; break; } } }
685
- return [c.id, term.replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim(), lang, c.status];
682
+ const cleanDesignations = {};
683
+ for (const [l, t] of Object.entries(c.designations)) {
684
+ if (t) cleanDesignations[l] = t.replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();
685
+ }
686
+ return [c.id, cleanDesignations, c.status];
686
687
  });
687
688
  fs.mkdirSync(path.join(DATA, register), { recursive: true });
688
689
  fs.writeFileSync(
@@ -61,9 +61,9 @@ describe('DatasetAdapter', () => {
61
61
  chunkSize: 500,
62
62
  chunks: [],
63
63
  concepts: [
64
- { id: '102-01-01', eng: 'equality', status: 'Standard' },
65
- { id: '102-01-02', eng: 'inequality', status: 'Standard' },
66
- { id: '103-01-02', eng: 'functional', status: 'Standard' },
64
+ { id: '102-01-01', designations: { eng: 'equality' }, eng: 'equality', status: 'Standard' },
65
+ { id: '102-01-02', designations: { eng: 'inequality' }, eng: 'inequality', status: 'Standard' },
66
+ { id: '103-01-02', designations: { eng: 'functional' }, eng: 'functional', status: 'Standard' },
67
67
  ],
68
68
  };
69
69
  mockFetch.mockReturnValue(mockJsonResponse(index));
@@ -128,9 +128,9 @@ describe('DatasetAdapter', () => {
128
128
  chunkSize: 500,
129
129
  chunks: [],
130
130
  concepts: [
131
- { id: '102-01-01', eng: 'equality', status: 'Standard' },
132
- { id: '102-01-02', eng: 'inequality', status: 'Standard' },
133
- { id: '103-01-02', eng: 'functional', status: 'Standard' },
131
+ { id: '102-01-01', designations: { eng: 'equality' }, eng: 'equality', status: 'Standard' },
132
+ { id: '102-01-02', designations: { eng: 'inequality' }, eng: 'inequality', status: 'Standard' },
133
+ { id: '103-01-02', designations: { eng: 'functional' }, eng: 'functional', status: 'Standard' },
134
134
  ],
135
135
  };
136
136
  mockFetch.mockReturnValue(mockJsonResponse(index));
@@ -150,7 +150,7 @@ describe('DatasetAdapter', () => {
150
150
  chunkSize: 500,
151
151
  chunks: [],
152
152
  concepts: [
153
- { id: '103-01-02', eng: 'functional', status: 'Standard' },
153
+ { id: '103-01-02', designations: { eng: 'functional' }, eng: 'functional', status: 'Standard' },
154
154
  ],
155
155
  };
156
156
  mockFetch.mockReturnValue(mockJsonResponse(index));
@@ -169,7 +169,7 @@ describe('DatasetAdapter', () => {
169
169
  chunkSize: 500,
170
170
  chunks: [],
171
171
  concepts: [
172
- { id: '102-01-01', eng: 'Equality', status: 'Standard' },
172
+ { id: '102-01-01', designations: { eng: 'Equality' }, eng: 'Equality', status: 'Standard' },
173
173
  ],
174
174
  };
175
175
  mockFetch.mockReturnValue(mockJsonResponse(index));
@@ -187,7 +187,7 @@ describe('DatasetAdapter', () => {
187
187
  chunkSize: 500,
188
188
  chunks: [],
189
189
  concepts: [
190
- { id: '102-01-01', eng: 'equality', status: 'Standard' },
190
+ { id: '102-01-01', designations: { eng: 'equality' }, eng: 'equality', status: 'Standard' },
191
191
  ],
192
192
  };
193
193
  mockFetch.mockReturnValue(mockJsonResponse(index));
@@ -26,6 +26,9 @@ describe('GraphView', () => {
26
26
  pinia = createPinia();
27
27
  setActivePinia(pinia);
28
28
  router = await createTestRouter();
29
+ // Mark store as initialized so loadAllGraphData skips discoverDatasets
30
+ const store = useVocabularyStore();
31
+ store.initialized = true;
29
32
  });
30
33
 
31
34
  function mountGraph() {
@@ -69,23 +69,12 @@ export class DatasetAdapter {
69
69
  }
70
70
 
71
71
  private normalizeIndex(data: any): ConceptIndex {
72
- const concepts: ConceptSummary[] = (data.concepts || []).map((c: any) => {
73
- if (c.designations && typeof c.designations === 'object') {
74
- return {
75
- id: c.id,
76
- designations: c.designations,
77
- eng: c.eng || c.designations.eng || Object.values(c.designations)[0] || '',
78
- status: c.status,
79
- };
80
- }
81
- // Legacy format: c.eng is a string, no designations map
82
- return {
83
- id: c.id,
84
- designations: c.eng ? { eng: c.eng } : {},
85
- eng: c.eng || '',
86
- status: c.status,
87
- };
88
- });
72
+ const concepts: ConceptSummary[] = (data.concepts || []).map((c: any) => ({
73
+ id: c.id,
74
+ designations: c.designations || {},
75
+ eng: c.eng || c.designations?.eng || Object.values(c.designations || {})[0] || '',
76
+ status: c.status,
77
+ }));
89
78
 
90
79
  return {
91
80
  registerId: data.registerId,
@@ -391,7 +380,7 @@ export class DatasetAdapter {
391
380
  return data.edges ?? [];
392
381
  }
393
382
 
394
- async loadGraphNodes(): Promise<{ uriPrefix: string; nodes: [string, string, string, string][] }> {
383
+ async loadGraphNodes(): Promise<{ uriPrefix: string; nodes: [string, Record<string, string>, string][] }> {
395
384
  const resp = await fetch(`${this.baseUrl}/graph-nodes.json`);
396
385
  if (!resp.ok) return { uriPrefix: '', nodes: [] };
397
386
  return await resp.json();
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { useRouter } from 'vue-router';
2
+ import { useRouter, useRoute } from 'vue-router';
3
3
  import { useUiStore } from '../stores/ui';
4
4
  import { useVocabularyStore } from '../stores/vocabulary';
5
5
  import { ref, watch, onMounted, computed, nextTick } from 'vue';
@@ -9,6 +9,7 @@ import { useDsStyle } from '../utils/dataset-style';
9
9
  import { useI18n } from '../i18n';
10
10
 
11
11
  const router = useRouter();
12
+ const route = useRoute();
12
13
  const ui = useUiStore();
13
14
  const store = useVocabularyStore();
14
15
  const { getStyle } = useDsStyle();
@@ -37,7 +38,9 @@ async function doSearch() {
37
38
  }
38
39
  searched.value = true;
39
40
  selectedIdx.value = -1;
40
- router.replace({ query: { q } });
41
+ if (route.query.q !== q) {
42
+ router.replace({ query: { q } });
43
+ }
41
44
  }
42
45
 
43
46
  function onInput() {
@@ -140,6 +140,10 @@ export const useVocabularyStore = defineStore('vocabulary', () => {
140
140
  }
141
141
 
142
142
  async function loadAllGraphData() {
143
+ if (!initialized.value) {
144
+ await discoverDatasets();
145
+ }
146
+
143
147
  const engine = toRaw(graph.value);
144
148
  const adapters = factory.getAdapters();
145
149
 
@@ -155,13 +159,13 @@ export const useVocabularyStore = defineStore('vocabulary', () => {
155
159
 
156
160
  if (nodeResult.status === 'fulfilled') {
157
161
  const { uriPrefix, nodes } = nodeResult.value;
158
- for (const [id, term, lang, status] of nodes) {
162
+ for (const [id, designations, status] of nodes) {
159
163
  engine.addNode({
160
164
  uri: uriPrefix + id,
161
165
  register: adapter.registerId,
162
166
  conceptId: id,
163
- designations: term ? { [lang || 'eng']: term } : {},
164
- status,
167
+ designations: designations || {},
168
+ status: status || 'unknown',
165
169
  loaded: false,
166
170
  });
167
171
  }
@@ -296,9 +300,16 @@ export const useVocabularyStore = defineStore('vocabulary', () => {
296
300
  }
297
301
 
298
302
  async function searchAcrossDatasets(query: string): Promise<SearchHit[]> {
303
+ if (!initialized.value) {
304
+ await discoverDatasets();
305
+ }
306
+
299
307
  const allHits: SearchHit[] = [];
300
308
  for (const adapter of datasets.value.values()) {
301
- if (adapter.index || adapter.manifest) {
309
+ if (adapter.manifest) {
310
+ if (!adapter.index) {
311
+ await adapter.loadIndex();
312
+ }
302
313
  await adapter.ensureAllChunksLoaded();
303
314
  allHits.push(...adapter.search(query));
304
315
  }