@glossarist/concept-browser 0.7.125 → 0.7.127

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.125",
3
+ "version": "0.7.127",
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": {
@@ -1179,9 +1179,10 @@ function extractInlineRefs(localizedData, refMaps2, conceptSources = []) {
1179
1179
  if (seg.kind === "concept" || seg.kind === "cite") {
1180
1180
  const target = seg.target;
1181
1181
  if (target.type === "dataset_qualified" && target.dataset && target.id) {
1182
- const dsId = refMaps2.refPrefixMap[target.dataset] || target.dataset;
1183
- const ref = { id: buildConceptUri(refMaps2.uriBase, dsId, target.id), term: seg.label ?? `${target.dataset}:${target.id}` };
1184
- refs.push(ref);
1182
+ const dsId = refMaps2.refPrefixMap[target.dataset];
1183
+ if (dsId) {
1184
+ refs.push({ id: buildConceptUri(refMaps2.uriBase, dsId, target.id), term: seg.label ?? `${target.dataset}:${target.id}` });
1185
+ }
1185
1186
  } else if (target.type === "urn" && target.urn) {
1186
1187
  const pattern = refMaps2.patternIndex.resolve(target.urn);
1187
1188
  if (pattern) {
@@ -409,9 +409,15 @@ function extractInlineRefs(localizedData, refMaps, conceptSources = []) {
409
409
  if (seg.kind === 'concept' || seg.kind === 'cite') {
410
410
  const target = seg.target;
411
411
  if (target.type === 'dataset_qualified' && target.dataset && target.id) {
412
- const dsId = refMaps.refPrefixMap[target.dataset] || target.dataset;
413
- const ref = { id: buildConceptUri(refMaps.uriBase, dsId, target.id), term: seg.label ?? `${target.dataset}:${target.id}` };
414
- refs.push(ref);
412
+ // Only create a concept URI if the dataset is CO-DEPLOYED.
413
+ // If the dataset doesn't exist in this deployment's refPrefixMap,
414
+ // skip — the runtime resolver will handle it (unresolved text or
415
+ // external link via routing). Creating a URI for a non-existent
416
+ // dataset produces a 404.
417
+ const dsId = refMaps.refPrefixMap[target.dataset];
418
+ if (dsId) {
419
+ refs.push({ id: buildConceptUri(refMaps.uriBase, dsId, target.id), term: seg.label ?? `${target.dataset}:${target.id}` });
420
+ }
415
421
  } else if (target.type === 'urn' && target.urn) {
416
422
  const pattern = refMaps.patternIndex.resolve(target.urn);
417
423
  if (pattern) {
@@ -27,7 +27,7 @@ function checkFile(file, dataDir) {
27
27
  const json = JSON.parse(raw);
28
28
  const broken = [];
29
29
  function check(target, field) {
30
- if (!target) return;
30
+ if (!target || typeof target !== "string") return;
31
31
  if (!target.startsWith("http")) return;
32
32
  const { exists, expected } = localPathForUri(target, dataDir);
33
33
  if (!exists) {
@@ -71,8 +71,22 @@ function checkFile(file, dataDir) {
71
71
  }
72
72
  }
73
73
  const sourceIds = /* @__PURE__ */ new Set();
74
- for (const s of json["gl:sources"] ?? []) {
74
+ const sourceRefKeys = /* @__PURE__ */ new Set();
75
+ const allSourceArrays = [
76
+ ...json["gl:sources"] ?? []
77
+ ];
78
+ for (const lc of Object.values(json["gl:localizedConcept"] ?? {})) {
79
+ const lcSources = lc["gl:source"] ?? lc["gl:sources"];
80
+ if (Array.isArray(lcSources)) allSourceArrays.push(...lcSources);
81
+ }
82
+ for (const s of allSourceArrays) {
75
83
  if (s["gl:id"]) sourceIds.add(s["gl:id"]);
84
+ const origin = s["gl:origin"] ?? {};
85
+ const ref = origin["gl:ref"] ?? {};
86
+ if (ref["gl:source"] && ref["gl:id"]) {
87
+ sourceRefKeys.add(`${ref["gl:source"]}:${ref["gl:id"]}`);
88
+ sourceIds.add(ref["gl:id"]);
89
+ }
76
90
  }
77
91
  const textChunks = [];
78
92
  for (const lc of Object.values(json["gl:localizedConcept"] ?? {})) {
@@ -149,9 +163,11 @@ function checkFile(file, dataDir) {
149
163
  if (citeMatch) {
150
164
  const rest = citeMatch[1];
151
165
  const commaIdx = rest.indexOf(",");
152
- const id = commaIdx > 0 ? rest.slice(0, commaIdx).trim() : rest.trim();
153
- if (!sourceIds.has(id)) {
154
- broken.push({ file: relFile, line: 0, field: "{{cite:...}}", target: id, reason: `source "${id}" not found in this concept's sources[]` });
166
+ const rawId = commaIdx > 0 ? rest.slice(0, commaIdx).trim() : rest.trim();
167
+ const lastColon = rawId.lastIndexOf(":");
168
+ const idPart = lastColon > 0 ? rawId.slice(lastColon + 1) : rawId;
169
+ if (!sourceIds.has(rawId) && !sourceIds.has(idPart) && !sourceRefKeys.has(rawId)) {
170
+ broken.push({ file: relFile, line: 0, field: "{{cite:...}}", target: rawId, reason: `source "${rawId}" not found in this concept's sources[]` });
155
171
  }
156
172
  continue;
157
173
  }
@@ -56,7 +56,7 @@ function checkFile(file: string, dataDir: string): BrokenLink[] {
56
56
  const broken: BrokenLink[] = [];
57
57
 
58
58
  function check(target: string | undefined, field: string) {
59
- if (!target) return;
59
+ if (!target || typeof target !== 'string') return;
60
60
  if (!target.startsWith('http')) return; // External links checked separately
61
61
  const { exists, expected } = localPathForUri(target, dataDir);
62
62
  if (!exists) {
@@ -112,8 +112,23 @@ function checkFile(file: string, dataDir: string): BrokenLink[] {
112
112
  }
113
113
 
114
114
  const sourceIds = new Set<string>();
115
- for (const s of json['gl:sources'] ?? []) {
115
+ const sourceRefKeys = new Set<string>();
116
+ // Collect from concept-level sources AND localization-level sources
117
+ const allSourceArrays = [
118
+ ...(json['gl:sources'] ?? []),
119
+ ];
120
+ for (const lc of Object.values(json['gl:localizedConcept'] ?? {})) {
121
+ const lcSources = (lc as any)['gl:source'] ?? (lc as any)['gl:sources'];
122
+ if (Array.isArray(lcSources)) allSourceArrays.push(...lcSources);
123
+ }
124
+ for (const s of allSourceArrays) {
116
125
  if (s['gl:id']) sourceIds.add(s['gl:id']);
126
+ const origin = s['gl:origin'] ?? {};
127
+ const ref = origin['gl:ref'] ?? {};
128
+ if (ref['gl:source'] && ref['gl:id']) {
129
+ sourceRefKeys.add(`${ref['gl:source']}:${ref['gl:id']}`);
130
+ sourceIds.add(ref['gl:id']);
131
+ }
117
132
  }
118
133
 
119
134
  const textChunks: string[] = [];
@@ -190,14 +205,20 @@ function checkFile(file: string, dataDir: string): BrokenLink[] {
190
205
  continue;
191
206
  }
192
207
 
193
- // cite:id — source must exist in this concept's sources[]
208
+ // cite:id — source must exist in this concept's sources[].
209
+ // Handles DATASET:ID format: {{cite:IEV:702-02-07}} matches a source
210
+ // with id "702-02-07" or origin.ref { source: "IEV", id: "702-02-07" }.
194
211
  const citeMatch = body.match(/^cite:(.+)$/i);
195
212
  if (citeMatch) {
196
213
  const rest = citeMatch[1];
197
214
  const commaIdx = rest.indexOf(',');
198
- const id = (commaIdx > 0 ? rest.slice(0, commaIdx).trim() : rest.trim());
199
- if (!sourceIds.has(id)) {
200
- broken.push({ file: relFile, line: 0, field: '{{cite:...}}', target: id, reason: `source "${id}" not found in this concept's sources[]` });
215
+ const rawId = (commaIdx > 0 ? rest.slice(0, commaIdx).trim() : rest.trim());
216
+
217
+ // Check: rawId (e.g. "IEV:702-02-07"), or just the ID part ("702-02-07")
218
+ const lastColon = rawId.lastIndexOf(':');
219
+ const idPart = lastColon > 0 ? rawId.slice(lastColon + 1) : rawId;
220
+ if (!sourceIds.has(rawId) && !sourceIds.has(idPart) && !sourceRefKeys.has(rawId)) {
221
+ broken.push({ file: relFile, line: 0, field: '{{cite:...}}', target: rawId, reason: `source "${rawId}" not found in this concept's sources[]` });
201
222
  }
202
223
  continue;
203
224
  }