@glossarist/concept-browser 0.7.87 → 0.7.89
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 +1 -1
- package/scripts/__tests__/bibliography.test.mjs +29 -0
- package/scripts/generate-data.mjs +4 -2
- package/scripts/lib/bibliography.mjs +18 -0
- package/src/__tests__/cross-repo-multiplicity-contract.test.ts +84 -0
- package/src/__tests__/model-bridge-partitive-migration.test.ts +153 -0
- package/src/__tests__/uri-router.test.ts +29 -0
- package/src/__tests__/wire-keys.test.ts +65 -0
- package/src/adapters/GraphDataSource.ts +1 -1
- package/src/adapters/UriRouter.ts +7 -3
- package/src/adapters/concept-identity.ts +6 -2
- package/src/adapters/model-bridge/jsonld-types.ts +169 -0
- package/src/adapters/model-bridge.ts +172 -297
- package/src/adapters/non-verbal/glossarist-augment.d.ts +8 -17
- package/src/adapters/wire-keys.ts +154 -0
- package/vite.config.ts +4 -1
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
isPartitivePresence,
|
|
30
30
|
isPartitiveCount,
|
|
31
31
|
} from '../utils/partitive-multiplicity';
|
|
32
|
+
import { GL } from './wire-keys';
|
|
32
33
|
import {
|
|
33
34
|
LetterSymbol,
|
|
34
35
|
GrammarInfo,
|
|
@@ -43,165 +44,24 @@ import type { ConceptSummary } from './types';
|
|
|
43
44
|
import { ConceptIdentity } from './concept-identity';
|
|
44
45
|
|
|
45
46
|
// ── JSON-LD wire-format types ─────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
interface JsonLdGrammarInfo {
|
|
65
|
-
'gl:gender'?: string;
|
|
66
|
-
'gl:number'?: string;
|
|
67
|
-
'gl:partOfSpeech'?: string;
|
|
68
|
-
'gl:noun'?: boolean;
|
|
69
|
-
'gl:verb'?: boolean;
|
|
70
|
-
'gl:adj'?: boolean;
|
|
71
|
-
'gl:adverb'?: boolean;
|
|
72
|
-
'gl:preposition'?: boolean;
|
|
73
|
-
'gl:participle'?: boolean;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
interface JsonLdRef {
|
|
77
|
-
'gl:source'?: string;
|
|
78
|
-
'gl:id'?: string;
|
|
79
|
-
'gl:version'?: string;
|
|
80
|
-
'gl:text'?: string;
|
|
81
|
-
source?: string;
|
|
82
|
-
id?: string;
|
|
83
|
-
version?: string;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
interface JsonLdLocality {
|
|
87
|
-
'gl:localityType'?: string;
|
|
88
|
-
'gl:referenceFrom'?: string;
|
|
89
|
-
'gl:referenceTo'?: string;
|
|
90
|
-
type?: string;
|
|
91
|
-
reference_from?: string;
|
|
92
|
-
reference_to?: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
interface JsonLdOrigin {
|
|
96
|
-
'gl:ref'?: string | JsonLdRef;
|
|
97
|
-
'gl:locality'?: JsonLdLocality;
|
|
98
|
-
'gl:link'?: string;
|
|
99
|
-
'gl:id'?: string;
|
|
100
|
-
'gl:version'?: string;
|
|
101
|
-
'gl:source'?: string;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
interface JsonLdSource {
|
|
105
|
-
'gl:id'?: string;
|
|
106
|
-
'gl:sourceType'?: string;
|
|
107
|
-
'gl:sourceStatus'?: string;
|
|
108
|
-
'gl:modification'?: string;
|
|
109
|
-
'gl:origin'?: JsonLdOrigin;
|
|
110
|
-
'gl:sourcedFrom'?: JsonLdOrigin[];
|
|
111
|
-
'gl:sourced_from'?: JsonLdOrigin[];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
interface JsonLdRelated {
|
|
115
|
-
'gl:relationshipType'?: string;
|
|
116
|
-
'gl:ref'?: JsonLdRef;
|
|
117
|
-
'@id'?: string;
|
|
118
|
-
'gl:term'?: string;
|
|
119
|
-
'gl:target'?: string;
|
|
120
|
-
'gl:sourceId'?: string;
|
|
121
|
-
'gl:citation'?: JsonLdOrigin;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
interface JsonLdDesignation {
|
|
125
|
-
'@type'?: string;
|
|
126
|
-
'gl:term'?: string;
|
|
127
|
-
'gl:normativeStatus'?: string;
|
|
128
|
-
'gl:absent'?: unknown;
|
|
129
|
-
'gl:fieldOfApplication'?: string;
|
|
130
|
-
'gl:usageInfo'?: string;
|
|
131
|
-
'gl:geographicalArea'?: string;
|
|
132
|
-
'gl:language'?: string;
|
|
133
|
-
'gl:script'?: string;
|
|
134
|
-
'gl:system'?: string;
|
|
135
|
-
'gl:international'?: boolean;
|
|
136
|
-
'gl:termType'?: string;
|
|
137
|
-
'gl:pronunciation'?: JsonLdPronunciation[];
|
|
138
|
-
'gl:source'?: JsonLdSource[];
|
|
139
|
-
'gl:related'?: JsonLdRelated[];
|
|
140
|
-
'gl:prefix'?: string;
|
|
141
|
-
'gl:gender'?: string;
|
|
142
|
-
'gl:grammarInfo'?: JsonLdGrammarInfo[];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
interface JsonLdLocalizedConcept {
|
|
146
|
-
'gl:languageCode'?: string;
|
|
147
|
-
'gl:entryStatus'?: string;
|
|
148
|
-
'gl:classification'?: string;
|
|
149
|
-
'gl:reviewType'?: string;
|
|
150
|
-
'gl:domain'?: string;
|
|
151
|
-
'gl:release'?: string;
|
|
152
|
-
'gl:lineageSourceSimilarity'?: number;
|
|
153
|
-
'gl:script'?: string;
|
|
154
|
-
'gl:system'?: string;
|
|
155
|
-
'gl:designation'?: JsonLdDesignation[];
|
|
156
|
-
'gl:definition'?: JsonLdContent[];
|
|
157
|
-
'gl:notes'?: JsonLdContent[];
|
|
158
|
-
'gl:annotations'?: JsonLdContent[];
|
|
159
|
-
'gl:examples'?: JsonLdContent[];
|
|
160
|
-
'gl:source'?: JsonLdSource[];
|
|
161
|
-
'gl:dates'?: JsonLdDate[];
|
|
162
|
-
'gl:references'?: JsonLdRelated[];
|
|
163
|
-
'gl:reviewDate'?: string;
|
|
164
|
-
'gl:reviewDecisionDate'?: string;
|
|
165
|
-
'gl:reviewDecisionEvent'?: string;
|
|
166
|
-
'gl:reviewStatus'?: string;
|
|
167
|
-
'gl:reviewDecision'?: string;
|
|
168
|
-
'gl:reviewDecisionNotes'?: string;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
interface JsonLdPartitiveMember {
|
|
172
|
-
'gl:ref'?: JsonLdRef;
|
|
173
|
-
/** ISO 704:2022 MECE: presence (required | optional) */
|
|
174
|
-
'gl:presence'?: string;
|
|
175
|
-
/** ISO 704:2022 MECE: count (exactly_one | at_least_one | multiple) */
|
|
176
|
-
'gl:count'?: string;
|
|
177
|
-
/** ISO 704:2022: delimiting part (3× stroke width in diagrams) */
|
|
178
|
-
'gl:isDelimiting'?: boolean;
|
|
179
|
-
/** Legacy v3 field — one-string multiplicity, split into presence+count */
|
|
180
|
-
'gl:multiplicity'?: string;
|
|
181
|
-
/** Legacy v2 field — migrated to presence+count */
|
|
182
|
-
'gl:certainty'?: string;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
interface JsonLdPartitiveRelation {
|
|
186
|
-
'gl:comprehensive'?: JsonLdRef;
|
|
187
|
-
'gl:hasPartitive'?: JsonLdPartitiveMember[];
|
|
188
|
-
'gl:completeness'?: string;
|
|
189
|
-
'gl:criterion'?: Record<string, string> | string;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
interface JsonLdConcept {
|
|
193
|
-
'@type'?: string;
|
|
194
|
-
'@id'?: string;
|
|
195
|
-
'gl:identifier'?: string | number;
|
|
196
|
-
'gl:term'?: string;
|
|
197
|
-
'gl:localizedConcept'?: Record<string, JsonLdLocalizedConcept>;
|
|
198
|
-
'gl:related'?: JsonLdRelated[];
|
|
199
|
-
'gl:partitiveRelations'?: JsonLdPartitiveRelation[];
|
|
200
|
-
'gl:tags'?: string[];
|
|
201
|
-
'gl:figureRef'?: unknown[];
|
|
202
|
-
'gl:tableRef'?: unknown[];
|
|
203
|
-
'gl:formulaRef'?: unknown[];
|
|
204
|
-
}
|
|
47
|
+
// Extracted to model-bridge/jsonld-types.ts for scannability.
|
|
48
|
+
|
|
49
|
+
import type {
|
|
50
|
+
JsonLdContent,
|
|
51
|
+
JsonLdDate,
|
|
52
|
+
JsonLdPronunciation,
|
|
53
|
+
JsonLdGrammarInfo,
|
|
54
|
+
JsonLdRef,
|
|
55
|
+
JsonLdLocality,
|
|
56
|
+
JsonLdOrigin,
|
|
57
|
+
JsonLdSource,
|
|
58
|
+
JsonLdRelated,
|
|
59
|
+
JsonLdDesignation,
|
|
60
|
+
JsonLdLocalizedConcept,
|
|
61
|
+
JsonLdPartitiveMember,
|
|
62
|
+
JsonLdPartitiveRelation,
|
|
63
|
+
JsonLdConcept,
|
|
64
|
+
} from './model-bridge/jsonld-types';
|
|
205
65
|
|
|
206
66
|
// ── Bridges for fields not yet in glossarist-js ────────────────────────────
|
|
207
67
|
// Remove each bridge when glossarist-js publishes native support.
|
|
@@ -351,7 +211,7 @@ function attachRelatedBridges(
|
|
|
351
211
|
// ── Detection ─────────────────────────────────────────────────────────────
|
|
352
212
|
|
|
353
213
|
function isJsonLd(doc: Record<string, unknown>): boolean {
|
|
354
|
-
return '@type' in doc &&
|
|
214
|
+
return '@type' in doc && GL.LOCALIZED_CONCEPT in doc;
|
|
355
215
|
}
|
|
356
216
|
|
|
357
217
|
// ── JSON-LD → Glossarist native mapping ───────────────────────────────────
|
|
@@ -366,58 +226,62 @@ function mapDesignationFromJsonLd(d: JsonLdDesignation): Record<string, unknown>
|
|
|
366
226
|
else if (rawType.includes('Symbol')) result.type = 'symbol';
|
|
367
227
|
else result.type = 'expression';
|
|
368
228
|
|
|
369
|
-
result.designation = d[
|
|
370
|
-
result.normative_status = d[
|
|
371
|
-
|
|
372
|
-
if (d[
|
|
373
|
-
if (d[
|
|
374
|
-
if (d[
|
|
375
|
-
if (d[
|
|
376
|
-
if (d[
|
|
377
|
-
if (d[
|
|
378
|
-
if (d[
|
|
379
|
-
if (d[
|
|
380
|
-
if (d[
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
229
|
+
result.designation = d[GL.TERM] ?? '';
|
|
230
|
+
result.normative_status = d[GL.NORMATIVE_STATUS] ?? null;
|
|
231
|
+
|
|
232
|
+
if (d[GL.ABSENT] != null) result.absent = d[GL.ABSENT];
|
|
233
|
+
if (d[GL.FIELD_OF_APPLICATION]) result.field_of_application = d[GL.FIELD_OF_APPLICATION];
|
|
234
|
+
if (d[GL.USAGE_INFO]) result.usage_info = d[GL.USAGE_INFO];
|
|
235
|
+
if (d[GL.GEOGRAPHICAL_AREA]) result.geographical_area = d[GL.GEOGRAPHICAL_AREA];
|
|
236
|
+
if (d[GL.LANGUAGE]) result.language = d[GL.LANGUAGE];
|
|
237
|
+
if (d[GL.SCRIPT]) result.script = d[GL.SCRIPT];
|
|
238
|
+
if (d[GL.SYSTEM]) result.system = d[GL.SYSTEM];
|
|
239
|
+
if (d[GL.INTERNATIONAL] != null) result.international = d[GL.INTERNATIONAL];
|
|
240
|
+
if (d[GL.TERM_TYPE]) result.term_type = d[GL.TERM_TYPE];
|
|
241
|
+
|
|
242
|
+
const pronunciation = d[GL.PRONUNCIATION];
|
|
243
|
+
if (pronunciation?.length) {
|
|
244
|
+
result.pronunciation = pronunciation.map(p => ({
|
|
245
|
+
content: p[GL.CONTENT] ?? null,
|
|
246
|
+
language: p[GL.LANGUAGE] ?? null,
|
|
247
|
+
script: p[GL.SCRIPT] ?? null,
|
|
248
|
+
system: p[GL.SYSTEM] ?? null,
|
|
249
|
+
country: p[GL.COUNTRY] ?? null,
|
|
389
250
|
}));
|
|
390
251
|
}
|
|
391
252
|
|
|
392
|
-
|
|
393
|
-
|
|
253
|
+
const sources = d[GL.SOURCE];
|
|
254
|
+
if (sources?.length) {
|
|
255
|
+
result.sources = sources.map(mapSourceFromJsonLd);
|
|
394
256
|
}
|
|
395
257
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
258
|
+
const related = d[GL.RELATED];
|
|
259
|
+
if (related?.length) {
|
|
260
|
+
result.related = related.map(r => {
|
|
261
|
+
const relType = r[GL.RELATIONSHIP_TYPE] ?? 'references';
|
|
262
|
+
if (DESIGNATION_REL_TYPES.has(relType) && r[GL.TARGET]) {
|
|
263
|
+
return { type: relType, target: r[GL.TARGET] };
|
|
401
264
|
}
|
|
402
265
|
return mapRelatedFromJsonLd(r);
|
|
403
266
|
});
|
|
404
267
|
}
|
|
405
268
|
|
|
406
|
-
if (d[
|
|
407
|
-
if (d[
|
|
408
|
-
result.grammar_info = [{ gender: d[
|
|
269
|
+
if (d[GL.PREFIX] != null) result.prefix = d[GL.PREFIX];
|
|
270
|
+
if (d[GL.GENDER]) {
|
|
271
|
+
result.grammar_info = [{ gender: d[GL.GENDER] }];
|
|
409
272
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
273
|
+
const grammarInfo = d[GL.GRAMMAR_INFO];
|
|
274
|
+
if (grammarInfo?.length) {
|
|
275
|
+
result.grammar_info = grammarInfo.map(gi => ({
|
|
276
|
+
gender: gi[GL.GENDER] ?? null,
|
|
277
|
+
number: gi[GL.NUMBER] ?? null,
|
|
278
|
+
part_of_speech: gi[GL.PART_OF_SPEECH] ?? null,
|
|
279
|
+
noun: gi[GL.NOUN] ?? false,
|
|
280
|
+
verb: gi[GL.VERB] ?? false,
|
|
281
|
+
adj: gi[GL.ADJ] ?? false,
|
|
282
|
+
adverb: gi[GL.ADVERB] ?? false,
|
|
283
|
+
preposition: gi[GL.PREPOSITION] ?? false,
|
|
284
|
+
participle: gi[GL.PARTICIPLE] ?? false,
|
|
421
285
|
}));
|
|
422
286
|
}
|
|
423
287
|
|
|
@@ -429,10 +293,10 @@ function mapRefFromJsonLd(rawRef: JsonLdRef | string | undefined): Record<string
|
|
|
429
293
|
if (typeof rawRef === 'string') return { source: rawRef };
|
|
430
294
|
const refObj: Record<string, unknown> = {};
|
|
431
295
|
// gl:-prefixed keys take precedence over unprefixed keys
|
|
432
|
-
refObj.source = rawRef[
|
|
433
|
-
refObj.id = rawRef[
|
|
434
|
-
refObj.version = rawRef[
|
|
435
|
-
if (rawRef[
|
|
296
|
+
refObj.source = rawRef[GL.SOURCE] ?? rawRef.source;
|
|
297
|
+
refObj.id = rawRef[GL.LOCAL_ID] ?? rawRef.id;
|
|
298
|
+
refObj.version = rawRef[GL.VERSION] ?? rawRef.version;
|
|
299
|
+
if (rawRef[GL.TEXT]) refObj.text = rawRef[GL.TEXT];
|
|
436
300
|
return (refObj.source ?? refObj.id ?? refObj.version ?? refObj.text) != null
|
|
437
301
|
? refObj : null;
|
|
438
302
|
}
|
|
@@ -445,46 +309,50 @@ function mapRefFromJsonLd(rawRef: JsonLdRef | string | undefined): Record<string
|
|
|
445
309
|
function mapLocalityFromJsonLd(rawLoc: JsonLdLocality | undefined): Record<string, unknown> | null {
|
|
446
310
|
if (!rawLoc) return null;
|
|
447
311
|
const locObj: Record<string, unknown> = {};
|
|
448
|
-
locObj.type = rawLoc[
|
|
449
|
-
locObj.reference_from = rawLoc[
|
|
450
|
-
locObj.reference_to = rawLoc[
|
|
312
|
+
locObj.type = rawLoc[GL.LOCALITY_TYPE] ?? rawLoc.type;
|
|
313
|
+
locObj.reference_from = rawLoc[GL.REFERENCE_FROM] ?? rawLoc.reference_from;
|
|
314
|
+
locObj.reference_to = rawLoc[GL.REFERENCE_TO] ?? rawLoc.reference_to;
|
|
451
315
|
return (locObj.type ?? locObj.reference_from ?? locObj.reference_to) != null
|
|
452
316
|
? locObj : null;
|
|
453
317
|
}
|
|
454
318
|
|
|
455
319
|
function mapDetailedDefinitionFromJsonLd(d: any): Record<string, unknown> {
|
|
456
|
-
const result: Record<string, unknown> = { content: d[
|
|
457
|
-
if (d[
|
|
458
|
-
result.examples = d[
|
|
320
|
+
const result: Record<string, unknown> = { content: d[GL.CONTENT] ?? '' };
|
|
321
|
+
if (d[GL.EXAMPLES]?.length) {
|
|
322
|
+
result.examples = d[GL.EXAMPLES].map(mapDetailedDefinitionFromJsonLd);
|
|
459
323
|
}
|
|
460
324
|
return result;
|
|
461
325
|
}
|
|
462
326
|
|
|
463
327
|
function mapOriginFromJsonLd(o: JsonLdOrigin): Record<string, unknown> {
|
|
464
328
|
const origin: Record<string, unknown> = {};
|
|
465
|
-
const ref = mapRefFromJsonLd(o[
|
|
329
|
+
const ref = mapRefFromJsonLd(o[GL.REF]);
|
|
466
330
|
if (ref) origin.ref = ref;
|
|
467
|
-
const loc = mapLocalityFromJsonLd(o[
|
|
331
|
+
const loc = mapLocalityFromJsonLd(o[GL.LOCALITY]);
|
|
468
332
|
if (loc) origin.locality = loc;
|
|
469
|
-
if (o[
|
|
470
|
-
if (o[
|
|
471
|
-
if (o[
|
|
472
|
-
if (o[
|
|
333
|
+
if (o[GL.LINK]) origin.link = o[GL.LINK];
|
|
334
|
+
if (o[GL.LOCAL_ID]) origin.id = o[GL.LOCAL_ID];
|
|
335
|
+
if (o[GL.VERSION]) origin.version = o[GL.VERSION];
|
|
336
|
+
if (o[GL.SOURCE]) origin.source = o[GL.SOURCE];
|
|
473
337
|
return origin;
|
|
474
338
|
}
|
|
475
339
|
|
|
476
340
|
function mapSourceFromJsonLd(s: JsonLdSource): Record<string, unknown> {
|
|
477
341
|
const result: Record<string, unknown> = {};
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if (s[
|
|
482
|
-
|
|
483
|
-
if (s[
|
|
484
|
-
|
|
342
|
+
// Note: JsonLdSource uses GL.LOCAL_ID for the source's local id, which is
|
|
343
|
+
// distinct from JSON-LD's '@id' (the concept IRI). Keep this as a
|
|
344
|
+
// literal — adding a wire-key for an isolated one-off would be noise.
|
|
345
|
+
if (s[GL.LOCAL_ID]) result.id = s[GL.LOCAL_ID];
|
|
346
|
+
if (s[GL.SOURCE_TYPE]) result.type = s[GL.SOURCE_TYPE];
|
|
347
|
+
if (s[GL.SOURCE_STATUS]) result.status = s[GL.SOURCE_STATUS];
|
|
348
|
+
if (s[GL.MODIFICATION]) result.modification = s[GL.MODIFICATION];
|
|
349
|
+
|
|
350
|
+
const origin = s[GL.ORIGIN];
|
|
351
|
+
if (origin) {
|
|
352
|
+
result.origin = mapOriginFromJsonLd(origin);
|
|
485
353
|
}
|
|
486
354
|
|
|
487
|
-
const sf = s[
|
|
355
|
+
const sf = s[GL.SOURCED_FROM] ?? s[GL.SOURCED_FROM_ALT];
|
|
488
356
|
if (sf?.length) {
|
|
489
357
|
result.sourced_from = sf.map(item => mapOriginFromJsonLd(item));
|
|
490
358
|
}
|
|
@@ -495,12 +363,12 @@ function mapSourceFromJsonLd(s: JsonLdSource): Record<string, unknown> {
|
|
|
495
363
|
function mapRelatedFromJsonLd(r: JsonLdRelated): Record<string, unknown> {
|
|
496
364
|
const result: Record<string, unknown> = { type: 'references' };
|
|
497
365
|
|
|
498
|
-
if (r[
|
|
499
|
-
result.type = r[
|
|
366
|
+
if (r[GL.RELATIONSHIP_TYPE]) {
|
|
367
|
+
result.type = r[GL.RELATIONSHIP_TYPE];
|
|
500
368
|
}
|
|
501
369
|
|
|
502
|
-
if (r[
|
|
503
|
-
const ref = mapRefFromJsonLd(r[
|
|
370
|
+
if (r[GL.REF]) {
|
|
371
|
+
const ref = mapRefFromJsonLd(r[GL.REF]);
|
|
504
372
|
if (ref) result.ref = ref;
|
|
505
373
|
}
|
|
506
374
|
|
|
@@ -511,20 +379,21 @@ function mapRelatedFromJsonLd(r: JsonLdRelated): Record<string, unknown> {
|
|
|
511
379
|
? { source: uri.split('/').slice(-3, -2)[0] || '', id: idMatch[1] }
|
|
512
380
|
: { source: uri, id: null };
|
|
513
381
|
}
|
|
514
|
-
if (r[
|
|
382
|
+
if (r[GL.TERM]) result.content = r[GL.TERM];
|
|
515
383
|
|
|
516
384
|
// Bridged fields — stored in raw dict, extracted by attachBridges()
|
|
517
|
-
if (r[
|
|
518
|
-
|
|
519
|
-
|
|
385
|
+
if (r[GL.SOURCE_ID]) result.sourceId = r[GL.SOURCE_ID];
|
|
386
|
+
const rawCitation = r[GL.CITATION];
|
|
387
|
+
if (rawCitation) {
|
|
388
|
+
const c = rawCitation;
|
|
520
389
|
const citation: Record<string, unknown> = {};
|
|
521
|
-
if (c[
|
|
522
|
-
const cr = mapRefFromJsonLd(c[
|
|
390
|
+
if (c[GL.REF]) {
|
|
391
|
+
const cr = mapRefFromJsonLd(c[GL.REF]);
|
|
523
392
|
if (cr) citation.ref = cr;
|
|
524
393
|
}
|
|
525
|
-
const loc = mapLocalityFromJsonLd(c[
|
|
394
|
+
const loc = mapLocalityFromJsonLd(c[GL.LOCALITY]);
|
|
526
395
|
if (loc) citation.locality = loc;
|
|
527
|
-
if (c[
|
|
396
|
+
if (c[GL.LINK]) citation.link = c[GL.LINK];
|
|
528
397
|
if (Object.keys(citation).length > 0) result.citation = citation;
|
|
529
398
|
}
|
|
530
399
|
|
|
@@ -534,87 +403,95 @@ function mapRelatedFromJsonLd(r: JsonLdRelated): Record<string, unknown> {
|
|
|
534
403
|
function mapLocalizedFromJsonLd(lc: JsonLdLocalizedConcept): Record<string, unknown> {
|
|
535
404
|
const data: Record<string, unknown> = {};
|
|
536
405
|
|
|
537
|
-
if (lc[
|
|
538
|
-
if (lc[
|
|
539
|
-
if (lc[
|
|
540
|
-
if (lc[
|
|
541
|
-
if (lc[
|
|
542
|
-
if (lc[
|
|
543
|
-
if (lc[
|
|
544
|
-
if (lc[
|
|
545
|
-
if (lc[
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
406
|
+
if (lc[GL.LANGUAGE_CODE]) data.language_code = lc[GL.LANGUAGE_CODE];
|
|
407
|
+
if (lc[GL.ENTRY_STATUS]) data.entry_status = lc[GL.ENTRY_STATUS];
|
|
408
|
+
if (lc[GL.CLASSIFICATION]) data.classification = lc[GL.CLASSIFICATION];
|
|
409
|
+
if (lc[GL.REVIEW_TYPE]) data.review_type = lc[GL.REVIEW_TYPE];
|
|
410
|
+
if (lc[GL.DOMAIN]) data.domain = lc[GL.DOMAIN];
|
|
411
|
+
if (lc[GL.RELEASE]) data.release = lc[GL.RELEASE];
|
|
412
|
+
if (lc[GL.LINEAGE_SOURCE_SIMILARITY] != null) data.lineage_source_similarity = lc[GL.LINEAGE_SOURCE_SIMILARITY];
|
|
413
|
+
if (lc[GL.SCRIPT]) data.script = lc[GL.SCRIPT];
|
|
414
|
+
if (lc[GL.SYSTEM]) data.system = lc[GL.SYSTEM];
|
|
415
|
+
|
|
416
|
+
const designation = lc[GL.DESIGNATION];
|
|
417
|
+
if (designation?.length) {
|
|
418
|
+
data.terms = designation.map(mapDesignationFromJsonLd);
|
|
549
419
|
}
|
|
550
420
|
|
|
551
|
-
|
|
552
|
-
|
|
421
|
+
const definition = lc[GL.DEFINITION];
|
|
422
|
+
if (definition?.length) {
|
|
423
|
+
data.definition = definition.map(mapDetailedDefinitionFromJsonLd);
|
|
553
424
|
}
|
|
554
425
|
|
|
555
|
-
|
|
556
|
-
|
|
426
|
+
const notes = lc[GL.NOTES];
|
|
427
|
+
if (notes?.length) {
|
|
428
|
+
data.notes = notes.map(mapDetailedDefinitionFromJsonLd);
|
|
557
429
|
}
|
|
558
430
|
|
|
559
|
-
|
|
560
|
-
|
|
431
|
+
const annotations = lc[GL.ANNOTATIONS];
|
|
432
|
+
if (annotations?.length) {
|
|
433
|
+
data.annotations = annotations.map(mapDetailedDefinitionFromJsonLd);
|
|
561
434
|
}
|
|
562
435
|
|
|
563
|
-
|
|
564
|
-
|
|
436
|
+
const examples = lc[GL.EXAMPLES];
|
|
437
|
+
if (examples?.length) {
|
|
438
|
+
data.examples = examples.map(mapDetailedDefinitionFromJsonLd);
|
|
565
439
|
}
|
|
566
440
|
|
|
567
|
-
|
|
568
|
-
|
|
441
|
+
const lcSources = lc[GL.SOURCE];
|
|
442
|
+
if (lcSources?.length) {
|
|
443
|
+
data.sources = lcSources.map(mapSourceFromJsonLd);
|
|
569
444
|
}
|
|
570
445
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
446
|
+
const dates = lc[GL.DATES];
|
|
447
|
+
if (dates?.length) {
|
|
448
|
+
data.dates = dates.map(d => ({
|
|
449
|
+
date: d[GL.DATE] ?? null,
|
|
450
|
+
type: d[GL.DATE_TYPE] ?? null,
|
|
575
451
|
}));
|
|
576
452
|
}
|
|
577
453
|
|
|
578
|
-
|
|
579
|
-
|
|
454
|
+
const lcReferences = lc[GL.REFERENCES];
|
|
455
|
+
if (lcReferences?.length) {
|
|
456
|
+
data.related = lcReferences.map(mapRelatedFromJsonLd);
|
|
580
457
|
}
|
|
581
458
|
|
|
582
|
-
if (lc[
|
|
583
|
-
if (lc[
|
|
584
|
-
if (lc[
|
|
585
|
-
if (lc[
|
|
586
|
-
if (lc[
|
|
587
|
-
if (lc[
|
|
459
|
+
if (lc[GL.REVIEW_DATE]) data.review_date = lc[GL.REVIEW_DATE];
|
|
460
|
+
if (lc[GL.REVIEW_DECISION_DATE]) data.review_decision_date = lc[GL.REVIEW_DECISION_DATE];
|
|
461
|
+
if (lc[GL.REVIEW_DECISION_EVENT]) data.review_decision_event = lc[GL.REVIEW_DECISION_EVENT];
|
|
462
|
+
if (lc[GL.REVIEW_STATUS]) data.review_status = lc[GL.REVIEW_STATUS];
|
|
463
|
+
if (lc[GL.REVIEW_DECISION]) data.review_decision = lc[GL.REVIEW_DECISION];
|
|
464
|
+
if (lc[GL.REVIEW_DECISION_NOTES]) data.review_decision_notes = lc[GL.REVIEW_DECISION_NOTES];
|
|
588
465
|
|
|
589
466
|
return data;
|
|
590
467
|
}
|
|
591
468
|
|
|
592
469
|
function mapPartitiveRelationFromJsonLd(r: JsonLdPartitiveRelation): Record<string, unknown> | null {
|
|
593
|
-
const comprehensive = r[
|
|
470
|
+
const comprehensive = r[GL.COMPREHENSIVE] ? mapRefFromJsonLd(r[GL.COMPREHENSIVE]) : null;
|
|
594
471
|
if (!comprehensive) return null;
|
|
595
472
|
|
|
596
|
-
const partitives = (r[
|
|
473
|
+
const partitives = (r[GL.HAS_PARTITIVE] ?? [])
|
|
597
474
|
.map((m): Record<string, unknown> | null => {
|
|
598
|
-
const ref = m[
|
|
475
|
+
const ref = m[GL.REF] ? mapRefFromJsonLd(m[GL.REF]) : null;
|
|
599
476
|
if (!ref) return null;
|
|
600
477
|
const out: Record<string, unknown> = { ref };
|
|
601
478
|
// ISO 704:2022 MECE: prefer presence × count from JSON-LD. Fall back
|
|
602
479
|
// to migrating the legacy one-string `multiplicity` or v2 `certainty`
|
|
603
480
|
// so data in transit from older glossarist versions still loads.
|
|
604
|
-
const presence = m[
|
|
605
|
-
const count = m[
|
|
481
|
+
const presence = m[GL.PRESENCE];
|
|
482
|
+
const count = m[GL.COUNT];
|
|
606
483
|
if (isPartitivePresence(presence) && isPartitiveCount(count)) {
|
|
607
484
|
out.presence = presence;
|
|
608
485
|
out.count = count;
|
|
609
486
|
} else {
|
|
610
|
-
const raw = m[
|
|
487
|
+
const raw = m[GL.MULTIPLICITY] ?? splitLegacyCertainty(m[GL.CERTAINTY]);
|
|
611
488
|
if (raw) {
|
|
612
489
|
const parts = splitMultiplicity(raw);
|
|
613
490
|
out.presence = parts.presence;
|
|
614
491
|
out.count = parts.count;
|
|
615
492
|
}
|
|
616
493
|
}
|
|
617
|
-
if (m[
|
|
494
|
+
if (m[GL.IS_DELIMITING] === true) out.is_delimiting = true;
|
|
618
495
|
return out;
|
|
619
496
|
})
|
|
620
497
|
.filter((m): m is Record<string, unknown> => m !== null);
|
|
@@ -628,12 +505,12 @@ function mapPartitiveRelationFromJsonLd(r: JsonLdPartitiveRelation): Record<stri
|
|
|
628
505
|
partitives,
|
|
629
506
|
};
|
|
630
507
|
|
|
631
|
-
if (r[
|
|
508
|
+
if (r[GL.COMPLETENESS]) out.completeness = r[GL.COMPLETENESS];
|
|
632
509
|
|
|
633
|
-
if (r[
|
|
634
|
-
out.criterion = typeof r[
|
|
635
|
-
? { default: r[
|
|
636
|
-
: r[
|
|
510
|
+
if (r[GL.CRITERION]) {
|
|
511
|
+
out.criterion = typeof r[GL.CRITERION] === 'string'
|
|
512
|
+
? { default: r[GL.CRITERION] }
|
|
513
|
+
: r[GL.CRITERION];
|
|
637
514
|
}
|
|
638
515
|
|
|
639
516
|
return out;
|
|
@@ -658,33 +535,34 @@ function splitMultiplicity(m: string): { presence: 'required' | 'optional'; coun
|
|
|
658
535
|
}
|
|
659
536
|
|
|
660
537
|
function conceptFromJsonLd(doc: JsonLdConcept): Concept {
|
|
661
|
-
const id = String(doc[
|
|
538
|
+
const id = String(doc[GL.IDENTIFIER] ?? doc['@id']?.split('/').pop() ?? '');
|
|
662
539
|
const localizations: Record<string, unknown> = {};
|
|
663
540
|
|
|
664
|
-
const rawLc = doc[
|
|
541
|
+
const rawLc = doc[GL.LOCALIZED_CONCEPT] ?? {};
|
|
665
542
|
for (const [lang, lc] of Object.entries(rawLc)) {
|
|
666
543
|
if (lc && typeof lc === 'object') {
|
|
667
544
|
localizations[lang] = mapLocalizedFromJsonLd(lc);
|
|
668
545
|
}
|
|
669
546
|
}
|
|
670
547
|
|
|
671
|
-
const related = (doc[
|
|
672
|
-
const partitiveRelations = (doc[
|
|
548
|
+
const related = (doc[GL.RELATED] ?? []).map(mapRelatedFromJsonLd);
|
|
549
|
+
const partitiveRelations = (doc[GL.PARTITIVE_RELATIONS] ?? [])
|
|
673
550
|
.map(mapPartitiveRelationFromJsonLd)
|
|
674
551
|
.filter((r): r is Record<string, unknown> => r !== null);
|
|
675
|
-
const
|
|
552
|
+
const tagsArr = doc[GL.TAGS];
|
|
553
|
+
const tags = Array.isArray(tagsArr) ? [...tagsArr] : [];
|
|
676
554
|
|
|
677
555
|
const concept = Concept.fromJSON({
|
|
678
556
|
id,
|
|
679
|
-
term: doc[
|
|
557
|
+
term: doc[GL.TERM] ?? null,
|
|
680
558
|
uri: doc['@id'] ?? null,
|
|
681
559
|
localizations,
|
|
682
560
|
related,
|
|
683
561
|
partitive_relations: partitiveRelations,
|
|
684
562
|
tags,
|
|
685
|
-
figures: normalizeEntityRefs(doc[
|
|
686
|
-
tables: normalizeEntityRefs(doc[
|
|
687
|
-
formulas: normalizeEntityRefs(doc[
|
|
563
|
+
figures: normalizeEntityRefs(doc[GL.FIGURE_REF]),
|
|
564
|
+
tables: normalizeEntityRefs(doc[GL.TABLE_REF]),
|
|
565
|
+
formulas: normalizeEntityRefs(doc[GL.FORMULA_REF]),
|
|
688
566
|
status: null,
|
|
689
567
|
});
|
|
690
568
|
|
|
@@ -722,11 +600,8 @@ function normalizeOneEntityRef(entry: unknown): Record<string, string> | null {
|
|
|
722
600
|
const entityId = (atId ? lastPathSegment(atId) : null) ?? explicitRef;
|
|
723
601
|
if (!entityId) return null;
|
|
724
602
|
const out: Record<string, string> = { ref: entityId };
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
: typeof obj.display === 'string' ? obj.display
|
|
728
|
-
: null;
|
|
729
|
-
if (display) out.display = display;
|
|
603
|
+
const displayRaw = obj[GL.DISPLAY] ?? obj['gloss:display'] ?? obj.display;
|
|
604
|
+
if (typeof displayRaw === 'string') out.display = displayRaw;
|
|
730
605
|
return out;
|
|
731
606
|
}
|
|
732
607
|
|