@glossarist/concept-browser 0.7.91 → 0.7.93

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.
@@ -4,6 +4,8 @@ import type { Router } from 'vue-router';
4
4
  // Import the MECE-augmented types from glossarist/models (extended by
5
5
  // src/adapters/non-verbal/glossarist-augment.d.ts).
6
6
  import type { Concept, RelatedConcept, ConceptRef } from 'glossarist';
7
+ import { PartitiveHyperedge } from 'glossarist';
8
+ import { GenericHyperedge } from 'glossarist/models';
7
9
  import type {
8
10
  PartitiveRelation as GlsPartitiveRelation,
9
11
  PartitiveMember as GlsPartitiveMember,
@@ -13,9 +15,11 @@ import type {
13
15
  GraphEdge,
14
16
  PartitiveRelationWire,
15
17
  PartitiveMemberWire,
18
+ GenericRelationWire,
16
19
  } from '../adapters/types';
17
20
  import { getFactory } from '../adapters/factory';
18
21
  import { conceptUri } from '../adapters/model-bridge';
22
+ import { resolveDesignation } from '../utils/resolve-designation';
19
23
  import { UriRouter } from '../adapters/UriRouter';
20
24
  import { useVocabularyStore } from '../stores/vocabulary';
21
25
  import { useDsStyle } from '../utils/dataset-style';
@@ -111,25 +115,7 @@ export function useConceptEdges(
111
115
  * IDs like '1.3'.
112
116
  */
113
117
  function designationFor(uri: string): string {
114
- const node = store.graph.getNode(uri);
115
- if (node) {
116
- const des = node.designations[locale.value]
117
- || node.designations.eng
118
- || Object.values(node.designations)[0];
119
- if (des) return des;
120
- }
121
- const resolution = factory.resolve(uri);
122
- if (resolution.type === 'internal') {
123
- const adapter = store.datasets.get(resolution.registerId);
124
- const entry = adapter?.getIndexEntry(resolution.conceptId);
125
- if (entry) {
126
- const des = entry.designations[locale.value]
127
- || entry.designations.eng
128
- || Object.values(entry.designations)[0];
129
- if (des) return des;
130
- }
131
- }
132
- return resolution.type === 'internal' ? resolution.conceptId : uri;
118
+ return resolveDesignation(uri, store, factory, locale.value);
133
119
  }
134
120
 
135
121
  function edgeBadgeColor(type: string, direction: 'out' | 'in'): string {
@@ -174,42 +160,59 @@ export function useConceptEdges(
174
160
  });
175
161
  });
176
162
 
177
- // Concept-level partitive relations (ISO 704 one-to-many decompositions).
178
- // Reads the glossarist-js native model (`concept.partitiveRelations`)
179
- // and projects each relation into a URI-resolved wire shape for display.
180
- // Independent of binary `conceptRelated`.
181
- // v2 shape per concept-model/TODO.partitive-relation-v2.
182
- const conceptPartitiveRelations = computed<PartitiveRelationWire[]>(() => {
163
+ // Concept-level n-ary hyperedge relations (ISO 704 one-to-many
164
+ // decompositions). Reads the glossarist-js unified `concept.relations`
165
+ // array and projects PartitiveHyperedge → PartitiveRelationWire,
166
+ // GenericHyperedge → GenericRelationWire for display.
167
+ //
168
+ // glossarist 0.4.33+ exposes a unified `.relations` array; type
169
+ // discrimination is via instanceof.
170
+ function projectHyperedge(rel: any): PartitiveRelationWire | GenericRelationWire | null {
183
171
  const source = conceptUriValue.value;
184
- const relations: readonly GlsPartitiveRelation[] = concept.value.partitiveRelations;
185
- return relations
186
- .map((rel): PartitiveRelationWire | null => {
187
- const comprehensive = resolveConceptRefUri(rel.comprehensive);
188
- if (!comprehensive) return null;
189
- const partitives: PartitiveMemberWire[] = rel.partitives
190
- .map((m: GlsPartitiveMember): PartitiveMemberWire | null => {
191
- const uri = resolveConceptRefUri(m.ref);
192
- if (!uri || uri === source) return null;
193
- return {
194
- uri,
195
- presence: readPresence(m),
196
- count: readCount(m),
197
- isDelimiting: readIsDelimiting(m),
198
- };
199
- })
200
- .filter((m: PartitiveMemberWire | null): m is PartitiveMemberWire => m !== null);
201
- if (partitives.length === 0) return null;
202
-
203
- return {
204
- source,
205
- comprehensive,
206
- partitives,
207
- completeness: rel.completeness,
208
- criterion: rel.criterion ?? undefined,
209
- register: registerId.value,
172
+ const comprehensive = resolveConceptRefUri(rel.comprehensive);
173
+ if (!comprehensive) return null;
174
+ const isGeneric = rel instanceof GenericHyperedge;
175
+ const members: any[] = (rel.members ?? rel.partitives ?? [])
176
+ .map((m: any): any | null => {
177
+ const uri = resolveConceptRefUri(m.ref);
178
+ if (!uri || uri === source) return null;
179
+ const base: any = {
180
+ uri,
181
+ presence: readPresence(m),
182
+ count: readCount(m),
210
183
  };
184
+ if (isGeneric) {
185
+ base.delimitingCharacteristic = m.delimitingCharacteristic;
186
+ } else {
187
+ base.isDelimiting = readIsDelimiting(m);
188
+ }
189
+ return base;
211
190
  })
212
- .filter((r: PartitiveRelationWire | null): r is PartitiveRelationWire => r !== null);
191
+ .filter((m: any | null): m is any => m !== null);
192
+ if (members.length === 0) return null;
193
+ return {
194
+ source,
195
+ comprehensive,
196
+ members,
197
+ partitives: members,
198
+ completeness: rel.completeness,
199
+ criterion: rel.criterion ?? undefined,
200
+ register: registerId.value,
201
+ };
202
+ }
203
+
204
+ const conceptPartitiveRelations = computed<PartitiveRelationWire[]>(() => {
205
+ return (concept.value.relations as any[] ?? [])
206
+ .filter(r => r instanceof PartitiveHyperedge)
207
+ .map(projectHyperedge)
208
+ .filter((r): r is PartitiveRelationWire => r !== null);
209
+ });
210
+
211
+ const conceptGenericRelations = computed<GenericRelationWire[]>(() => {
212
+ return (concept.value.relations as any[] ?? [])
213
+ .filter(r => r instanceof GenericHyperedge)
214
+ .map(projectHyperedge)
215
+ .filter((r): r is GenericRelationWire => r !== null);
213
216
  });
214
217
 
215
218
  function resolveConceptRefUri(ref: ConceptRef | null): string | null {
@@ -307,6 +310,7 @@ export function useConceptEdges(
307
310
  inverseEdgeType,
308
311
  conceptRelated,
309
312
  conceptPartitiveRelations,
313
+ conceptGenericRelations,
310
314
  resolveRelatedRef,
311
315
  getResolvedRef,
312
316
  relatedLabel,
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Resolve a concept URI to its display designation (term string).
3
+ *
4
+ * Single SSOT for the designation fallback chain used by:
5
+ * - PartitiveRelationList.vue
6
+ * - GenericRelationList.vue
7
+ * - use-concept-edges.ts (designationFor method)
8
+ *
9
+ * Previously each site had its own copy with subtle divergences (one
10
+ * used `entry.titles`, another used `entry.designations` — the former
11
+ * is a bug since ConceptSummary has no `titles` property).
12
+ *
13
+ * Fallback chain:
14
+ * 1. BFS graph node (already loaded as a neighbor) → locale → eng → any
15
+ * 2. Dataset adapter index entry → designations[locale] → eng → any
16
+ * 3. Concept ID (for internal URIs) or raw URI (for external)
17
+ */
18
+ import type { useVocabularyStore } from '../stores/vocabulary';
19
+ import type { AdapterFactory } from '../adapters/factory';
20
+
21
+ type VocabularyStore = ReturnType<typeof useVocabularyStore>;
22
+ type Factory = AdapterFactory;
23
+
24
+ export function resolveDesignation(
25
+ uri: string,
26
+ store: VocabularyStore,
27
+ factory: Factory,
28
+ currentLocale: string,
29
+ ): string {
30
+ const node = store.graph.getNode(uri);
31
+ if (node) {
32
+ const des = node.designations[currentLocale]
33
+ || node.designations.eng
34
+ || Object.values(node.designations)[0];
35
+ if (des) return des;
36
+ }
37
+ const resolution = factory.resolve(uri);
38
+ if (resolution.type === 'internal') {
39
+ const adapter = store.datasets.get(resolution.registerId);
40
+ const entry = adapter?.getIndexEntry(resolution.conceptId);
41
+ if (entry) {
42
+ const des = entry.designations[currentLocale]
43
+ || entry.designations.eng
44
+ || Object.values(entry.designations)[0];
45
+ if (des) return des;
46
+ }
47
+ return resolution.conceptId;
48
+ }
49
+ return uri;
50
+ }
@@ -89,7 +89,7 @@ const partitiveRelationsForSphere = computed<PartitiveRelationWire[]>(() => {
89
89
  if (uri === sourceUri) return null;
90
90
  const presence: PartitivePresence = member.presence;
91
91
  const count: PartitiveCount = member.count;
92
- const isDelimiting = member.isDelimiting;
92
+ const isDelimiting = (member as any).is_delimiting === true;
93
93
  return { uri, presence, count, isDelimiting };
94
94
  })
95
95
  .filter((x): x is PartitiveMemberWire => x !== null);