@oml/language 0.18.0 → 0.19.0
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/out/oml/generated/ast.d.ts +178 -8
- package/out/oml/generated/ast.js +140 -0
- package/out/oml/generated/ast.js.map +1 -1
- package/out/oml/generated/grammar.js +1073 -375
- package/out/oml/generated/grammar.js.map +1 -1
- package/out/oml/oml-index.d.ts +35 -0
- package/out/oml/oml-index.js +185 -1
- package/out/oml/oml-index.js.map +1 -1
- package/out/oml/oml-serializer.js +14 -9
- package/out/oml/oml-serializer.js.map +1 -1
- package/out/oml/oml-update.js +60 -9
- package/out/oml/oml-update.js.map +1 -1
- package/out/oml/oml-validator.d.ts +9 -1
- package/out/oml/oml-validator.js +224 -3
- package/out/oml/oml-validator.js.map +1 -1
- package/package.json +1 -1
- package/src/oml/generated/ast.ts +198 -7
- package/src/oml/generated/grammar.ts +1073 -375
- package/src/oml/oml-index.ts +208 -1
- package/src/oml/oml-serializer.ts +15 -9
- package/src/oml/oml-update.ts +70 -9
- package/src/oml/oml-validator.ts +232 -5
- package/src/oml/oml.langium +39 -7
package/src/oml/oml-index.ts
CHANGED
|
@@ -2,11 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
import { DocumentState, URI, type LangiumDocument } from 'langium';
|
|
4
4
|
import type { LangiumSharedServices } from 'langium/lsp';
|
|
5
|
-
import { isAspect, isConcept, isConceptInstance, isDescription, isOntology, isRelationEntity, isRelationInstance, isScalar } from './generated/ast.js';
|
|
5
|
+
import { isAspect, isConcept, isConceptInstance, isDescription, isOntology, isRelationEntity, isRelationInstance, isScalar, isUnit } from './generated/ast.js';
|
|
6
6
|
import { collectOntologyMembers, getIriForNode, getSourceLocation, type SourceLocation } from './oml-utils.js';
|
|
7
7
|
|
|
8
8
|
const OML_LABEL_IRI = 'http://opencaesar.io/oml#label';
|
|
9
9
|
|
|
10
|
+
function ontologyIriFromMemberIri(memberIri: string): string | undefined {
|
|
11
|
+
const hash = memberIri.lastIndexOf('#');
|
|
12
|
+
if (hash >= 0) {
|
|
13
|
+
return memberIri.slice(0, hash);
|
|
14
|
+
}
|
|
15
|
+
const slash = memberIri.lastIndexOf('/');
|
|
16
|
+
if (slash >= 0) {
|
|
17
|
+
return memberIri.slice(0, slash);
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
const ontologyIndexByShared = new WeakMap<object, OmlIndex>();
|
|
11
23
|
|
|
12
24
|
export interface OmlIndexedInstance {
|
|
@@ -20,6 +32,28 @@ export interface OmlIndexedInstance {
|
|
|
20
32
|
location?: SourceLocation;
|
|
21
33
|
}
|
|
22
34
|
|
|
35
|
+
export interface OmlIndexedUnit {
|
|
36
|
+
unitIri: string;
|
|
37
|
+
symbol: string;
|
|
38
|
+
kindIris: string[];
|
|
39
|
+
ontologyIri: string;
|
|
40
|
+
modelUri: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type OmlClassKind = 'aspect' | 'concept' | 'relationEntity';
|
|
44
|
+
|
|
45
|
+
export interface OmlIndexedClass {
|
|
46
|
+
classIri: string;
|
|
47
|
+
kind: OmlClassKind;
|
|
48
|
+
name?: string;
|
|
49
|
+
label?: string;
|
|
50
|
+
prefix?: string;
|
|
51
|
+
ontologyIri: string;
|
|
52
|
+
modelUri: string;
|
|
53
|
+
superIris: string[];
|
|
54
|
+
location?: SourceLocation;
|
|
55
|
+
}
|
|
56
|
+
|
|
23
57
|
export function getOntologyModelIndex(shared: LangiumSharedServices): OmlIndex {
|
|
24
58
|
const key = shared as object;
|
|
25
59
|
const existing = ontologyIndexByShared.get(key);
|
|
@@ -34,6 +68,7 @@ export function getOntologyModelIndex(shared: LangiumSharedServices): OmlIndex {
|
|
|
34
68
|
export class OmlIndex {
|
|
35
69
|
private readonly workspaceModelUrisByOntologyIri = new Map<string, Set<string>>();
|
|
36
70
|
private readonly workspaceNamespaceByModelUri = new Map<string, string>();
|
|
71
|
+
private readonly prefixByOntologyIri = new Map<string, string>();
|
|
37
72
|
private readonly memberLabelByIri = new Map<string, string>();
|
|
38
73
|
private readonly labeledMemberIrisByModelUri = new Map<string, Set<string>>();
|
|
39
74
|
private readonly instanceIrisByTypeIri = new Map<string, Set<string>>();
|
|
@@ -42,6 +77,11 @@ export class OmlIndex {
|
|
|
42
77
|
private readonly indexedInstanceIrisByModelUri = new Map<string, Set<string>>();
|
|
43
78
|
private readonly subTypeIrisByTypeIri = new Map<string, Set<string>>();
|
|
44
79
|
private readonly typeSuperIrisByModelUri = new Map<string, Map<string, Set<string>>>();
|
|
80
|
+
private readonly unitIrisBySymbol = new Map<string, Set<string>>();
|
|
81
|
+
private readonly indexedUnitsByIri = new Map<string, OmlIndexedUnit>();
|
|
82
|
+
private readonly unitIrisByModelUri = new Map<string, Set<string>>();
|
|
83
|
+
private readonly indexedClassesByIri = new Map<string, OmlIndexedClass>();
|
|
84
|
+
private readonly classIrisByModelUri = new Map<string, Set<string>>();
|
|
45
85
|
|
|
46
86
|
constructor(private readonly shared: LangiumSharedServices) {
|
|
47
87
|
this.shared.workspace.DocumentBuilder.onUpdate((_changed, deleted) => {
|
|
@@ -246,6 +286,8 @@ export class OmlIndex {
|
|
|
246
286
|
this.removeTypesForModelUri(modelUri);
|
|
247
287
|
this.removeIndexedInstancesForModelUri(modelUri);
|
|
248
288
|
this.removeTypeHierarchyForModelUri(modelUri);
|
|
289
|
+
this.removeUnitsForModelUri(modelUri);
|
|
290
|
+
this.removeIndexedClassesForModelUri(modelUri);
|
|
249
291
|
this.unindexModelUri(modelUri);
|
|
250
292
|
}
|
|
251
293
|
|
|
@@ -275,6 +317,23 @@ export class OmlIndex {
|
|
|
275
317
|
modelUris.add(modelUri);
|
|
276
318
|
this.workspaceModelUrisByOntologyIri.set(ontologyIri, modelUris);
|
|
277
319
|
this.workspaceNamespaceByModelUri.set(modelUri, namespace);
|
|
320
|
+
const prefix = this.getPrefix(document);
|
|
321
|
+
if (prefix) {
|
|
322
|
+
this.prefixByOntologyIri.set(ontologyIri, prefix);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
getPrefixForOntologyIri(ontologyIri: string): string | undefined {
|
|
327
|
+
this.ensureIndexedFromLoadedDocuments();
|
|
328
|
+
return this.prefixByOntologyIri.get(ontologyIri);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
getPrefixForMemberIri(memberIri: string): string | undefined {
|
|
332
|
+
const normalized = this.normalizeIri(memberIri);
|
|
333
|
+
if (!normalized) return undefined;
|
|
334
|
+
const ontologyIri = ontologyIriFromMemberIri(normalized);
|
|
335
|
+
if (!ontologyIri) return undefined;
|
|
336
|
+
return this.getPrefixForOntologyIri(ontologyIri);
|
|
278
337
|
}
|
|
279
338
|
|
|
280
339
|
private indexLinkedDocument(document: LangiumDocument): void {
|
|
@@ -283,12 +342,16 @@ export class OmlIndex {
|
|
|
283
342
|
this.removeTypesForModelUri(modelUri);
|
|
284
343
|
this.removeIndexedInstancesForModelUri(modelUri);
|
|
285
344
|
this.removeTypeHierarchyForModelUri(modelUri);
|
|
345
|
+
this.removeUnitsForModelUri(modelUri);
|
|
346
|
+
this.removeIndexedClassesForModelUri(modelUri);
|
|
286
347
|
const root = document.parseResult?.value;
|
|
287
348
|
if (!isOntology(root)) {
|
|
288
349
|
return;
|
|
289
350
|
}
|
|
290
351
|
|
|
291
352
|
this.indexTypeHierarchy(root as any, modelUri);
|
|
353
|
+
this.indexUnits(root as any, modelUri);
|
|
354
|
+
this.indexClasses(root as any, modelUri);
|
|
292
355
|
|
|
293
356
|
if (!isDescription(root)) {
|
|
294
357
|
return;
|
|
@@ -354,6 +417,141 @@ export class OmlIndex {
|
|
|
354
417
|
}
|
|
355
418
|
}
|
|
356
419
|
|
|
420
|
+
getUnitsBySymbol(symbol: string): OmlIndexedUnit[] {
|
|
421
|
+
this.ensureIndexedFromLoadedDocuments();
|
|
422
|
+
const iris = this.unitIrisBySymbol.get(symbol);
|
|
423
|
+
if (!iris) return [];
|
|
424
|
+
const results: OmlIndexedUnit[] = [];
|
|
425
|
+
for (const iri of iris) {
|
|
426
|
+
const entry = this.indexedUnitsByIri.get(iri);
|
|
427
|
+
if (entry) results.push(entry);
|
|
428
|
+
}
|
|
429
|
+
return results;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
getAllUnits(): OmlIndexedUnit[] {
|
|
433
|
+
this.ensureIndexedFromLoadedDocuments();
|
|
434
|
+
return [...this.indexedUnitsByIri.values()];
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private indexUnits(root: any, modelUri: string): void {
|
|
438
|
+
const ontologyIri = this.resolveOntologyIri(modelUri) ?? '';
|
|
439
|
+
const modelUnitIris = new Set<string>();
|
|
440
|
+
for (const member of collectOntologyMembers(root as any)) {
|
|
441
|
+
if (!isUnit(member)) continue;
|
|
442
|
+
const unitIri = this.normalizeIri(getIriForNode(member) ?? '');
|
|
443
|
+
if (!unitIri) continue;
|
|
444
|
+
const symbols = (((member as any).symbol ?? []) as unknown[]).filter((s): s is string => typeof s === 'string' && s.length > 0);
|
|
445
|
+
if (symbols.length === 0) continue;
|
|
446
|
+
const kindIris = (((member as any).kinds ?? []) as any[])
|
|
447
|
+
.map((kindRef) => this.normalizeIri(getIriForNode(kindRef?.ref) ?? ''))
|
|
448
|
+
.filter((iri): iri is string => Boolean(iri));
|
|
449
|
+
for (const symbol of symbols) {
|
|
450
|
+
const entry: OmlIndexedUnit = { unitIri, symbol, kindIris, ontologyIri, modelUri };
|
|
451
|
+
this.indexedUnitsByIri.set(unitIri, entry);
|
|
452
|
+
const byIri = this.unitIrisBySymbol.get(symbol) ?? new Set<string>();
|
|
453
|
+
byIri.add(unitIri);
|
|
454
|
+
this.unitIrisBySymbol.set(symbol, byIri);
|
|
455
|
+
modelUnitIris.add(unitIri);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (modelUnitIris.size > 0) {
|
|
459
|
+
this.unitIrisByModelUri.set(modelUri, modelUnitIris);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
getAllClasses(): OmlIndexedClass[] {
|
|
464
|
+
this.ensureIndexedFromLoadedDocuments();
|
|
465
|
+
return [...this.indexedClassesByIri.values()];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private indexClasses(root: any, modelUri: string): void {
|
|
469
|
+
const ontologyIri = this.resolveOntologyIri(modelUri) ?? '';
|
|
470
|
+
const rootPrefix = typeof root?.prefix === 'string' && root.prefix.length > 0 ? root.prefix : undefined;
|
|
471
|
+
if (ontologyIri && rootPrefix) {
|
|
472
|
+
this.prefixByOntologyIri.set(ontologyIri, rootPrefix);
|
|
473
|
+
}
|
|
474
|
+
const modelClassIris = new Set<string>();
|
|
475
|
+
for (const member of collectOntologyMembers(root as any)) {
|
|
476
|
+
let kind: OmlClassKind | undefined;
|
|
477
|
+
if (isAspect(member)) {
|
|
478
|
+
kind = 'aspect';
|
|
479
|
+
} else if (isConcept(member)) {
|
|
480
|
+
kind = 'concept';
|
|
481
|
+
} else if (isRelationEntity(member)) {
|
|
482
|
+
kind = 'relationEntity';
|
|
483
|
+
}
|
|
484
|
+
if (!kind) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
const classIri = this.normalizeIri(getIriForNode(member) ?? '');
|
|
488
|
+
if (!classIri) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const label = this.extractLabel(member);
|
|
492
|
+
if (label !== undefined) {
|
|
493
|
+
this.memberLabelByIri.set(classIri, label);
|
|
494
|
+
const labeled = this.labeledMemberIrisByModelUri.get(modelUri) ?? new Set<string>();
|
|
495
|
+
labeled.add(classIri);
|
|
496
|
+
this.labeledMemberIrisByModelUri.set(modelUri, labeled);
|
|
497
|
+
}
|
|
498
|
+
const specializations = Array.isArray((member as any).ownedSpecializations) ? (member as any).ownedSpecializations : [];
|
|
499
|
+
const superIris: string[] = [];
|
|
500
|
+
for (const specialization of specializations) {
|
|
501
|
+
const superIri = this.normalizeIri(getIriForNode(specialization?.superTerm?.ref) ?? '');
|
|
502
|
+
if (superIri) {
|
|
503
|
+
superIris.push(superIri);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const entry: OmlIndexedClass = {
|
|
507
|
+
classIri,
|
|
508
|
+
kind,
|
|
509
|
+
name: typeof (member as any).name === 'string' ? (member as any).name : undefined,
|
|
510
|
+
label,
|
|
511
|
+
prefix: rootPrefix ?? this.prefixByOntologyIri.get(ontologyIri),
|
|
512
|
+
ontologyIri,
|
|
513
|
+
modelUri,
|
|
514
|
+
superIris,
|
|
515
|
+
location: getSourceLocation(member as any),
|
|
516
|
+
};
|
|
517
|
+
this.indexedClassesByIri.set(classIri, entry);
|
|
518
|
+
modelClassIris.add(classIri);
|
|
519
|
+
}
|
|
520
|
+
if (modelClassIris.size > 0) {
|
|
521
|
+
this.classIrisByModelUri.set(modelUri, modelClassIris);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
private removeIndexedClassesForModelUri(modelUri: string): void {
|
|
526
|
+
const classIris = this.classIrisByModelUri.get(modelUri);
|
|
527
|
+
if (!classIris) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
for (const classIri of classIris) {
|
|
531
|
+
this.indexedClassesByIri.delete(classIri);
|
|
532
|
+
}
|
|
533
|
+
this.classIrisByModelUri.delete(modelUri);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private removeUnitsForModelUri(modelUri: string): void {
|
|
537
|
+
const unitIris = this.unitIrisByModelUri.get(modelUri);
|
|
538
|
+
if (!unitIris) return;
|
|
539
|
+
for (const unitIri of unitIris) {
|
|
540
|
+
const entry = this.indexedUnitsByIri.get(unitIri);
|
|
541
|
+
if (entry) {
|
|
542
|
+
const bySymbol = this.unitIrisBySymbol.get(entry.symbol);
|
|
543
|
+
if (bySymbol) {
|
|
544
|
+
bySymbol.delete(unitIri);
|
|
545
|
+
if (bySymbol.size === 0) {
|
|
546
|
+
this.unitIrisBySymbol.delete(entry.symbol);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
this.indexedUnitsByIri.delete(unitIri);
|
|
551
|
+
}
|
|
552
|
+
this.unitIrisByModelUri.delete(modelUri);
|
|
553
|
+
}
|
|
554
|
+
|
|
357
555
|
private indexTypeHierarchy(root: any, modelUri: string): void {
|
|
358
556
|
const typeSuperIrisByTypeIri = new Map<string, Set<string>>();
|
|
359
557
|
for (const member of collectOntologyMembers(root as any)) {
|
|
@@ -506,6 +704,15 @@ export class OmlIndex {
|
|
|
506
704
|
return namespace;
|
|
507
705
|
}
|
|
508
706
|
|
|
707
|
+
private getPrefix(document: LangiumDocument): string | undefined {
|
|
708
|
+
const root = document.parseResult?.value;
|
|
709
|
+
if (!isOntology(root)) {
|
|
710
|
+
return undefined;
|
|
711
|
+
}
|
|
712
|
+
const prefix = (root as any).prefix;
|
|
713
|
+
return typeof prefix === 'string' && prefix.length > 0 ? prefix : undefined;
|
|
714
|
+
}
|
|
715
|
+
|
|
509
716
|
private ontologyIriFromNamespace(namespace: string): string {
|
|
510
717
|
return namespace.replace(/[\/#]+$/, '');
|
|
511
718
|
}
|
|
@@ -845,29 +845,35 @@ const serializeLiteral = (literal: Literal): string => {
|
|
|
845
845
|
return literal.value ? 'true' : 'false';
|
|
846
846
|
}
|
|
847
847
|
if (isIntegerLiteral(literal)) {
|
|
848
|
-
return `${literal.value}
|
|
848
|
+
return appendUnitSuffix(`${literal.value}`, literal);
|
|
849
849
|
}
|
|
850
850
|
if (isDecimalLiteral(literal)) {
|
|
851
851
|
const v = literal.value as unknown;
|
|
852
852
|
// Langium parses decimal literals to JS numbers; integer-valued ones (e.g. 567.0→567)
|
|
853
853
|
// must be written with a decimal point to remain valid DECIMAL syntax.
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
return
|
|
854
|
+
const base = (typeof v === 'number' && Number.isFinite(v) && Number.isInteger(v))
|
|
855
|
+
? `${v}.0`
|
|
856
|
+
: `${literal.value}`;
|
|
857
|
+
return appendUnitSuffix(base, literal);
|
|
858
858
|
}
|
|
859
859
|
if (isDoubleLiteral(literal)) {
|
|
860
860
|
const v = literal.value as unknown;
|
|
861
861
|
// Langium parses double literals to JS numbers, losing the required e-notation.
|
|
862
862
|
// OML DOUBLE terminal requires e/E; always emit it.
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
return
|
|
863
|
+
const base = (typeof v === 'number' && Number.isFinite(v))
|
|
864
|
+
? (Number.isInteger(v) ? `${v}.0e0` : `${v}e0`)
|
|
865
|
+
: `${literal.value}`;
|
|
866
|
+
return appendUnitSuffix(base, literal);
|
|
867
867
|
}
|
|
868
868
|
return '';
|
|
869
869
|
};
|
|
870
870
|
|
|
871
|
+
const appendUnitSuffix = (base: string, literal: any): string => {
|
|
872
|
+
const unitRef = literal?.unit;
|
|
873
|
+
const refText = unitRef?.$refText ?? unitRef?.ref?.name;
|
|
874
|
+
return refText ? `${base}^^${refText}` : base;
|
|
875
|
+
};
|
|
876
|
+
|
|
871
877
|
const serializeQuotedLiteral = (literal: QuotedLiteral): string => {
|
|
872
878
|
const base = serializeStringLiteral(literal.value ?? '');
|
|
873
879
|
if (literal.type?.$refText) {
|
package/src/oml/oml-update.ts
CHANGED
|
@@ -1215,17 +1215,22 @@ async function ensureReferenceImport(shared: any, ontology: any, iri: string): P
|
|
|
1215
1215
|
const importedNamespace = normalizeNamespace(String(resolveImportNamespaceRaw(imp) ?? ''));
|
|
1216
1216
|
return importedNamespace === target.namespace;
|
|
1217
1217
|
});
|
|
1218
|
+
const importedOntology = await findOntologyByNamespace(shared, target.namespace);
|
|
1219
|
+
const declaredPrefix = typeof importedOntology?.prefix === 'string' ? importedOntology.prefix.trim() : '';
|
|
1220
|
+
const preferredPrefix = declaredPrefix && !usedPrefixes.has(declaredPrefix)
|
|
1221
|
+
? declaredPrefix
|
|
1222
|
+
: pickImportPrefix(target.namespace, usedPrefixes);
|
|
1218
1223
|
if (existingImport) {
|
|
1219
1224
|
// If the existing import has no prefix (e.g., a bundle `includes` added without one),
|
|
1220
1225
|
// patch it now so that the reference can use the abbreviated form.
|
|
1221
1226
|
if (!resolveImportPrefix(existingImport)) {
|
|
1222
|
-
existingImport.prefix =
|
|
1227
|
+
existingImport.prefix = preferredPrefix;
|
|
1223
1228
|
}
|
|
1224
1229
|
return;
|
|
1225
1230
|
}
|
|
1226
|
-
const prefix =
|
|
1231
|
+
const prefix = preferredPrefix;
|
|
1227
1232
|
const importedRef = `<${target.namespace}${target.separator}>`;
|
|
1228
|
-
const importKind = await resolveImportKind(shared, ontology, target.namespace);
|
|
1233
|
+
const importKind = await resolveImportKind(shared, ontology, target.namespace, importedOntology);
|
|
1229
1234
|
const importStatement: any = {
|
|
1230
1235
|
$type: 'Import',
|
|
1231
1236
|
kind: importKind,
|
|
@@ -1418,6 +1423,21 @@ function matchesRefTextFragment(statement: any, fragment: string): boolean {
|
|
|
1418
1423
|
}
|
|
1419
1424
|
|
|
1420
1425
|
function asLiteral(ontology: any, value: unknown): any {
|
|
1426
|
+
if (isQuantityLiteralTransport(value)) {
|
|
1427
|
+
const raw = value.value;
|
|
1428
|
+
const num = typeof raw === 'number' ? raw : Number(raw);
|
|
1429
|
+
const $type = !Number.isFinite(num)
|
|
1430
|
+
? 'DecimalLiteral'
|
|
1431
|
+
: Number.isInteger(num)
|
|
1432
|
+
? 'IntegerLiteral'
|
|
1433
|
+
: (typeof raw === 'string' && /[eE]/.test(raw) ? 'DoubleLiteral' : 'DecimalLiteral');
|
|
1434
|
+
const literal: Record<string, unknown> = { $type, value: num };
|
|
1435
|
+
const unitIri = literalUnitIriFromTransport(ontology, value);
|
|
1436
|
+
if (unitIri) {
|
|
1437
|
+
literal.unit = { $refText: toRefText(ontology, unitIri) };
|
|
1438
|
+
}
|
|
1439
|
+
return literal;
|
|
1440
|
+
}
|
|
1421
1441
|
if (isTypedQuotedLiteralTransport(value)) {
|
|
1422
1442
|
const literalValue = String(value.value ?? '');
|
|
1423
1443
|
const langTag = literalLanguageTagFromTransport(value);
|
|
@@ -1453,14 +1473,18 @@ function asLiteral(ontology: any, value: unknown): any {
|
|
|
1453
1473
|
}
|
|
1454
1474
|
|
|
1455
1475
|
async function ensureTypedLiteralDatatypeImport(shared: any, ontology: any, value: unknown): Promise<void> {
|
|
1456
|
-
if (
|
|
1457
|
-
|
|
1476
|
+
if (isTypedQuotedLiteralTransport(value)) {
|
|
1477
|
+
const datatypeIri = literalDatatypeIriFromTransport(ontology, value);
|
|
1478
|
+
if (datatypeIri && !isXsdStringDatatypeIri(ontology, datatypeIri)) {
|
|
1479
|
+
await ensureReferenceImport(shared, ontology, datatypeIri);
|
|
1480
|
+
}
|
|
1458
1481
|
}
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1482
|
+
if (isQuantityLiteralTransport(value)) {
|
|
1483
|
+
const unitIri = literalUnitIriFromTransport(ontology, value);
|
|
1484
|
+
if (unitIri) {
|
|
1485
|
+
await ensureReferenceImport(shared, ontology, unitIri);
|
|
1486
|
+
}
|
|
1462
1487
|
}
|
|
1463
|
-
await ensureReferenceImport(shared, ontology, datatypeIri);
|
|
1464
1488
|
}
|
|
1465
1489
|
|
|
1466
1490
|
function isTypedQuotedLiteralTransport(value: unknown): value is {
|
|
@@ -1490,6 +1514,43 @@ function isTypedQuotedLiteralTransport(value: unknown): value is {
|
|
|
1490
1514
|
) && 'value' in record;
|
|
1491
1515
|
}
|
|
1492
1516
|
|
|
1517
|
+
function isQuantityLiteralTransport(value: unknown): value is {
|
|
1518
|
+
value: number | string;
|
|
1519
|
+
unitIri?: unknown;
|
|
1520
|
+
unitRefText?: unknown;
|
|
1521
|
+
unit?: unknown;
|
|
1522
|
+
$type?: unknown;
|
|
1523
|
+
} {
|
|
1524
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1525
|
+
return false;
|
|
1526
|
+
}
|
|
1527
|
+
const record = value as Record<string, unknown>;
|
|
1528
|
+
const hasUnit = typeof record.unitIri === 'string'
|
|
1529
|
+
|| typeof record.unitRefText === 'string'
|
|
1530
|
+
|| typeof record.unit === 'string';
|
|
1531
|
+
if (!hasUnit) return false;
|
|
1532
|
+
const v = record.value;
|
|
1533
|
+
return typeof v === 'number' || (typeof v === 'string' && v.length > 0);
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function literalUnitIriFromTransport(ontology: any, value: {
|
|
1537
|
+
unitIri?: unknown;
|
|
1538
|
+
unitRefText?: unknown;
|
|
1539
|
+
unit?: unknown;
|
|
1540
|
+
}): string {
|
|
1541
|
+
const directIri = typeof value.unitIri === 'string'
|
|
1542
|
+
? value.unitIri.trim()
|
|
1543
|
+
: (typeof value.unit === 'string' && value.unit.includes('://') ? value.unit.trim() : '');
|
|
1544
|
+
if (directIri) {
|
|
1545
|
+
return normalizeIri(directIri);
|
|
1546
|
+
}
|
|
1547
|
+
const refText = typeof value.unitRefText === 'string'
|
|
1548
|
+
? value.unitRefText.trim()
|
|
1549
|
+
: (typeof value.unit === 'string' ? value.unit.trim() : '');
|
|
1550
|
+
if (!refText) return '';
|
|
1551
|
+
return normalizeIri(expandRefTextToIri(ontology, refText) ?? refText);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1493
1554
|
function literalLanguageTag(literal: any): string {
|
|
1494
1555
|
if (!literal || typeof literal !== 'object') {
|
|
1495
1556
|
return '';
|