@oml/language 0.9.0 → 0.11.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/oml-candidates.d.ts +17 -7
- package/out/oml/oml-candidates.js +119 -21
- package/out/oml/oml-candidates.js.map +1 -1
- package/out/oml/oml-completion.js +2 -1
- package/out/oml/oml-completion.js.map +1 -1
- package/out/oml/oml-document.d.ts +4 -4
- package/out/oml/oml-document.js +42 -7
- package/out/oml/oml-document.js.map +1 -1
- package/out/oml/oml-edit.d.ts +12 -0
- package/out/oml/oml-edit.js +201 -43
- package/out/oml/oml-edit.js.map +1 -1
- package/out/oml/oml-index.d.ts +26 -6
- package/out/oml/oml-index.js +305 -43
- package/out/oml/oml-index.js.map +1 -1
- package/out/oml/oml-rename.js +19 -1
- package/out/oml/oml-rename.js.map +1 -1
- package/out/oml/oml-utils.js +1 -0
- package/out/oml/oml-utils.js.map +1 -1
- package/package.json +1 -1
- package/src/oml/oml-candidates.ts +144 -23
- package/src/oml/oml-completion.ts +2 -1
- package/src/oml/oml-document.ts +49 -9
- package/src/oml/oml-edit.ts +211 -42
- package/src/oml/oml-index.ts +330 -44
- package/src/oml/oml-rename.ts +21 -1
- package/src/oml/oml-utils.ts +1 -0
- package/out/oml/oml-index-manager.d.ts +0 -10
- package/out/oml/oml-index-manager.js +0 -48
- package/out/oml/oml-index-manager.js.map +0 -1
- package/src/oml/oml-index-manager.ts +0 -56
package/src/oml/oml-index.ts
CHANGED
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
2
|
|
|
3
|
-
import { DocumentState, type LangiumDocument } from 'langium';
|
|
3
|
+
import { DocumentState, URI, type LangiumDocument } from 'langium';
|
|
4
4
|
import type { LangiumSharedServices } from 'langium/lsp';
|
|
5
|
-
import { isOntology } from './generated/ast.js';
|
|
6
|
-
import { isTransientEditorDocumentUri } from './oml-utils.js';
|
|
5
|
+
import { isAspect, isConcept, isConceptInstance, isDescription, isOntology, isRelationEntity, isRelationInstance, isScalar } from './generated/ast.js';
|
|
6
|
+
import { collectOntologyMembers, getIriForNode, isTransientEditorDocumentUri } from './oml-utils.js';
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const OML_LABEL_IRI = 'http://opencaesar.io/oml#label';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const ontologyIndexByShared = new WeakMap<object, OmlIndex>();
|
|
11
|
+
|
|
12
|
+
export function getOntologyModelIndex(shared: LangiumSharedServices): OmlIndex {
|
|
11
13
|
const key = shared as object;
|
|
12
14
|
const existing = ontologyIndexByShared.get(key);
|
|
13
15
|
if (existing) {
|
|
14
16
|
return existing;
|
|
15
17
|
}
|
|
16
|
-
const created = new
|
|
18
|
+
const created = new OmlIndex(shared);
|
|
17
19
|
ontologyIndexByShared.set(key, created);
|
|
18
20
|
return created;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export class
|
|
22
|
-
private readonly ontologyIdentifierToModelUri = new Map<string, string>();
|
|
23
|
-
private readonly modelUriToOntologyIri = new Map<string, string>();
|
|
23
|
+
export class OmlIndex {
|
|
24
24
|
private readonly workspaceModelUrisByOntologyIri = new Map<string, Set<string>>();
|
|
25
|
-
private readonly workspaceOntologyIriByModelUri = new Map<string, string>();
|
|
26
25
|
private readonly workspaceNamespaceByModelUri = new Map<string, string>();
|
|
26
|
+
private readonly memberLabelByIri = new Map<string, string>();
|
|
27
|
+
private readonly labeledMemberIrisByModelUri = new Map<string, Set<string>>();
|
|
28
|
+
private readonly instanceIrisByTypeIri = new Map<string, Set<string>>();
|
|
29
|
+
private readonly instanceTypeIrisByModelUri = new Map<string, Map<string, Set<string>>>();
|
|
30
|
+
private readonly subTypeIrisByTypeIri = new Map<string, Set<string>>();
|
|
31
|
+
private readonly typeSuperIrisByModelUri = new Map<string, Map<string, Set<string>>>();
|
|
27
32
|
|
|
28
33
|
constructor(private readonly shared: LangiumSharedServices) {
|
|
29
34
|
this.shared.workspace.DocumentBuilder.onDocumentPhase(DocumentState.Parsed, (document) => {
|
|
30
35
|
this.indexDocument(document);
|
|
31
36
|
});
|
|
37
|
+
this.shared.workspace.DocumentBuilder.onDocumentPhase(DocumentState.Linked, (document) => {
|
|
38
|
+
this.indexLinkedDocument(document);
|
|
39
|
+
});
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
resolveModelUri(identifier: string): string | undefined {
|
|
@@ -46,11 +54,83 @@ export class OntologyModelIndex {
|
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
resolveOntologyIri(modelUri: string): string | undefined {
|
|
49
|
-
this.
|
|
50
|
-
|
|
57
|
+
const document = this.shared.workspace.LangiumDocuments.getDocument(URI.parse(modelUri));
|
|
58
|
+
if (!document) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return this.getOntologyIri(document);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getMemberLabel(memberIri: string): string | undefined {
|
|
65
|
+
return this.memberLabelByIri.get(this.normalizeIri(memberIri));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getMemberLabelSnapshot(modelUris: Iterable<string>): Record<string, string> {
|
|
69
|
+
const snapshot: Record<string, string> = {};
|
|
70
|
+
for (const modelUri of modelUris) {
|
|
71
|
+
const labeledMemberIris = this.labeledMemberIrisByModelUri.get(modelUri);
|
|
72
|
+
if (!labeledMemberIris) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
for (const memberIri of labeledMemberIris) {
|
|
76
|
+
const label = this.memberLabelByIri.get(memberIri);
|
|
77
|
+
if (label) {
|
|
78
|
+
snapshot[memberIri] = label;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return snapshot;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getTypeMemberIris(typeIri: string): string[] {
|
|
86
|
+
const normalizedTypeIri = this.normalizeIri(typeIri);
|
|
87
|
+
if (!normalizedTypeIri) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const candidateTypeIris = new Set<string>();
|
|
91
|
+
const worklist = [normalizedTypeIri];
|
|
92
|
+
while (worklist.length > 0) {
|
|
93
|
+
const current = worklist.pop()!;
|
|
94
|
+
if (candidateTypeIris.has(current)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
candidateTypeIris.add(current);
|
|
98
|
+
const subTypes = this.subTypeIrisByTypeIri.get(current);
|
|
99
|
+
if (!subTypes) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const subType of subTypes) {
|
|
103
|
+
if (!candidateTypeIris.has(subType)) {
|
|
104
|
+
worklist.push(subType);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const iris: string[] = [];
|
|
109
|
+
for (const candidateTypeIri of candidateTypeIris) {
|
|
110
|
+
const instanceIris = this.instanceIrisByTypeIri.get(candidateTypeIri);
|
|
111
|
+
if (!instanceIris) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
iris.push(...instanceIris);
|
|
115
|
+
}
|
|
116
|
+
return [...new Set(iris)].sort();
|
|
51
117
|
}
|
|
52
118
|
|
|
53
|
-
|
|
119
|
+
getAllDescriptionInstanceIris(): string[] {
|
|
120
|
+
const iris = new Set<string>();
|
|
121
|
+
for (const instanceIris of this.instanceIrisByTypeIri.values()) {
|
|
122
|
+
for (const iri of instanceIris) {
|
|
123
|
+
iris.add(iri);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return [...iris].sort();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
removeDocument(document: LangiumDocument): void {
|
|
130
|
+
const modelUri = document.uri.toString();
|
|
131
|
+
this.removeLabelsForModelUri(modelUri);
|
|
132
|
+
this.removeTypesForModelUri(modelUri);
|
|
133
|
+
this.removeTypeHierarchyForModelUri(modelUri);
|
|
54
134
|
this.unindexModelUri(modelUri);
|
|
55
135
|
}
|
|
56
136
|
|
|
@@ -68,57 +148,180 @@ export class OntologyModelIndex {
|
|
|
68
148
|
private indexDocument(document: LangiumDocument): void {
|
|
69
149
|
const modelUri = document.uri.toString();
|
|
70
150
|
this.unindexModelUri(modelUri);
|
|
71
|
-
const
|
|
72
|
-
if (!
|
|
151
|
+
const ontologyIri = this.getOntologyIri(document);
|
|
152
|
+
if (!ontologyIri) {
|
|
73
153
|
return;
|
|
74
154
|
}
|
|
75
|
-
const namespace = this.
|
|
155
|
+
const namespace = this.getNamespace(document);
|
|
76
156
|
if (!namespace) {
|
|
77
157
|
return;
|
|
78
158
|
}
|
|
79
159
|
if (isTransientEditorDocumentUri(modelUri)) {
|
|
80
160
|
return;
|
|
81
161
|
}
|
|
82
|
-
const ontologyIri = this.ontologyIriFromNamespace(namespace);
|
|
83
162
|
const modelUris = this.workspaceModelUrisByOntologyIri.get(ontologyIri) ?? new Set<string>();
|
|
84
163
|
modelUris.add(modelUri);
|
|
85
164
|
this.workspaceModelUrisByOntologyIri.set(ontologyIri, modelUris);
|
|
86
|
-
this.workspaceOntologyIriByModelUri.set(modelUri, ontologyIri);
|
|
87
165
|
this.workspaceNamespaceByModelUri.set(modelUri, namespace);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private indexLinkedDocument(document: LangiumDocument): void {
|
|
169
|
+
const modelUri = document.uri.toString();
|
|
170
|
+
this.removeLabelsForModelUri(modelUri);
|
|
171
|
+
this.removeTypesForModelUri(modelUri);
|
|
172
|
+
this.removeTypeHierarchyForModelUri(modelUri);
|
|
173
|
+
const root = document.parseResult?.value;
|
|
174
|
+
if (!isOntology(root) || isTransientEditorDocumentUri(modelUri)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.indexTypeHierarchy(root as any, modelUri);
|
|
179
|
+
|
|
180
|
+
if (!isDescription(root)) {
|
|
92
181
|
return;
|
|
93
182
|
}
|
|
94
|
-
|
|
95
|
-
|
|
183
|
+
|
|
184
|
+
const labeledMemberIris = new Set<string>();
|
|
185
|
+
const typedInstanceIrisByTypeIri = new Map<string, Set<string>>();
|
|
186
|
+
for (const member of collectOntologyMembers(root as any)) {
|
|
187
|
+
const memberIri = this.normalizeIri(getIriForNode(member) ?? '');
|
|
188
|
+
if (!memberIri) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const label = this.extractLabel(member);
|
|
192
|
+
if (label !== undefined) {
|
|
193
|
+
this.memberLabelByIri.set(memberIri, label);
|
|
194
|
+
labeledMemberIris.add(memberIri);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!isConceptInstance(member) && !isRelationInstance(member)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const instanceIri = this.resolveInstanceIri(member);
|
|
201
|
+
if (!instanceIri) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const ownedTypes = Array.isArray((member as any).ownedTypes) ? (member as any).ownedTypes : [];
|
|
205
|
+
for (const typeAssertion of ownedTypes) {
|
|
206
|
+
const typeIri = this.resolveTypeIri(typeAssertion?.type);
|
|
207
|
+
if (!typeIri) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const instanceIris = this.instanceIrisByTypeIri.get(typeIri) ?? new Set<string>();
|
|
211
|
+
instanceIris.add(instanceIri);
|
|
212
|
+
this.instanceIrisByTypeIri.set(typeIri, instanceIris);
|
|
213
|
+
|
|
214
|
+
const modelTypeIris = typedInstanceIrisByTypeIri.get(typeIri) ?? new Set<string>();
|
|
215
|
+
modelTypeIris.add(instanceIri);
|
|
216
|
+
typedInstanceIrisByTypeIri.set(typeIri, modelTypeIris);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (labeledMemberIris.size > 0) {
|
|
221
|
+
this.labeledMemberIrisByModelUri.set(modelUri, labeledMemberIris);
|
|
222
|
+
}
|
|
223
|
+
if (typedInstanceIrisByTypeIri.size > 0) {
|
|
224
|
+
this.instanceTypeIrisByModelUri.set(modelUri, typedInstanceIrisByTypeIri);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private indexTypeHierarchy(root: any, modelUri: string): void {
|
|
229
|
+
const typeSuperIrisByTypeIri = new Map<string, Set<string>>();
|
|
230
|
+
for (const member of collectOntologyMembers(root as any)) {
|
|
231
|
+
if (!isConcept(member) && !isAspect(member) && !isRelationEntity(member) && !isScalar(member)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const typeIri = this.normalizeIri(getIriForNode(member) ?? '');
|
|
235
|
+
if (!typeIri) {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const directSupers = typeSuperIrisByTypeIri.get(typeIri) ?? new Set<string>();
|
|
239
|
+
const specializations = Array.isArray((member as any).ownedSpecializations) ? (member as any).ownedSpecializations : [];
|
|
240
|
+
for (const specialization of specializations) {
|
|
241
|
+
const superIri = this.normalizeIri(getIriForNode(specialization?.superTerm?.ref) ?? '');
|
|
242
|
+
if (!superIri) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
directSupers.add(superIri);
|
|
246
|
+
const subTypes = this.subTypeIrisByTypeIri.get(superIri) ?? new Set<string>();
|
|
247
|
+
subTypes.add(typeIri);
|
|
248
|
+
this.subTypeIrisByTypeIri.set(superIri, subTypes);
|
|
249
|
+
}
|
|
250
|
+
if (directSupers.size > 0) {
|
|
251
|
+
typeSuperIrisByTypeIri.set(typeIri, directSupers);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (typeSuperIrisByTypeIri.size > 0) {
|
|
255
|
+
this.typeSuperIrisByModelUri.set(modelUri, typeSuperIrisByTypeIri);
|
|
256
|
+
}
|
|
96
257
|
}
|
|
97
258
|
|
|
98
259
|
private unindexModelUri(modelUri: string): void {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const ontologyIri = this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
260
|
+
const namespace = this.workspaceNamespaceByModelUri.get(modelUri);
|
|
261
|
+
if (!namespace) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this.workspaceNamespaceByModelUri.delete(modelUri);
|
|
265
|
+
const ontologyIri = this.ontologyIriFromNamespace(namespace);
|
|
266
|
+
const modelUris = this.workspaceModelUrisByOntologyIri.get(ontologyIri);
|
|
267
|
+
if (!modelUris) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
modelUris.delete(modelUri);
|
|
271
|
+
if (modelUris.size === 0) {
|
|
272
|
+
this.workspaceModelUrisByOntologyIri.delete(ontologyIri);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private removeLabelsForModelUri(modelUri: string): void {
|
|
277
|
+
const labeledMemberIris = this.labeledMemberIrisByModelUri.get(modelUri);
|
|
278
|
+
if (!labeledMemberIris) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
for (const memberIri of labeledMemberIris) {
|
|
282
|
+
this.memberLabelByIri.delete(memberIri);
|
|
283
|
+
}
|
|
284
|
+
this.labeledMemberIrisByModelUri.delete(modelUri);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private removeTypesForModelUri(modelUri: string): void {
|
|
288
|
+
const typedInstanceIrisByTypeIri = this.instanceTypeIrisByModelUri.get(modelUri);
|
|
289
|
+
if (!typedInstanceIrisByTypeIri) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
for (const [typeIri, instanceIris] of typedInstanceIrisByTypeIri.entries()) {
|
|
293
|
+
const globalInstanceIris = this.instanceIrisByTypeIri.get(typeIri);
|
|
294
|
+
if (!globalInstanceIris) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
for (const instanceIri of instanceIris) {
|
|
298
|
+
globalInstanceIris.delete(instanceIri);
|
|
299
|
+
}
|
|
300
|
+
if (globalInstanceIris.size === 0) {
|
|
301
|
+
this.instanceIrisByTypeIri.delete(typeIri);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
this.instanceTypeIrisByModelUri.delete(modelUri);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private removeTypeHierarchyForModelUri(modelUri: string): void {
|
|
308
|
+
const typeSuperIrisByTypeIri = this.typeSuperIrisByModelUri.get(modelUri);
|
|
309
|
+
if (!typeSuperIrisByTypeIri) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
for (const [typeIri, superIris] of typeSuperIrisByTypeIri.entries()) {
|
|
313
|
+
for (const superIri of superIris) {
|
|
314
|
+
const subTypes = this.subTypeIrisByTypeIri.get(superIri);
|
|
315
|
+
if (!subTypes) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
subTypes.delete(typeIri);
|
|
319
|
+
if (subTypes.size === 0) {
|
|
320
|
+
this.subTypeIrisByTypeIri.delete(superIri);
|
|
116
321
|
}
|
|
117
322
|
}
|
|
118
|
-
this.workspaceOntologyIriByModelUri.delete(modelUri);
|
|
119
|
-
this.workspaceNamespaceByModelUri.delete(modelUri);
|
|
120
323
|
}
|
|
121
|
-
this.
|
|
324
|
+
this.typeSuperIrisByModelUri.delete(modelUri);
|
|
122
325
|
}
|
|
123
326
|
|
|
124
327
|
getDuplicateWorkspaceModelUris(identifier: string): string[] {
|
|
@@ -139,7 +342,90 @@ export class OntologyModelIndex {
|
|
|
139
342
|
return namespace.replace(/^<|>$/g, '');
|
|
140
343
|
}
|
|
141
344
|
|
|
345
|
+
private normalizeIri(iri: string): string {
|
|
346
|
+
return iri.replace(/^<|>$/g, '').trim();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private getOntologyIri(document: LangiumDocument): string | undefined {
|
|
350
|
+
const namespace = this.getNamespace(document);
|
|
351
|
+
if (!namespace) {
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
return this.ontologyIriFromNamespace(namespace);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private getNamespace(document: LangiumDocument): string | undefined {
|
|
358
|
+
const root = document.parseResult?.value;
|
|
359
|
+
if (!isOntology(root)) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
const namespace = this.normalizeNamespace((root as any).namespace ?? '');
|
|
363
|
+
if (!namespace) {
|
|
364
|
+
return undefined;
|
|
365
|
+
}
|
|
366
|
+
return namespace;
|
|
367
|
+
}
|
|
368
|
+
|
|
142
369
|
private ontologyIriFromNamespace(namespace: string): string {
|
|
143
370
|
return namespace.replace(/[\/#]+$/, '');
|
|
144
371
|
}
|
|
372
|
+
|
|
373
|
+
private extractLabel(member: any): string | undefined {
|
|
374
|
+
const annotations = Array.isArray(member?.ownedAnnotations) ? member.ownedAnnotations : [];
|
|
375
|
+
if (annotations.length === 0) {
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
for (const annotation of annotations) {
|
|
379
|
+
const propertyIri = this.normalizeIri(getIriForNode(annotation?.property?.ref) ?? '');
|
|
380
|
+
if (propertyIri !== OML_LABEL_IRI) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const label = this.readAnnotationLiteral(annotation);
|
|
384
|
+
if (label) {
|
|
385
|
+
return label;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return undefined;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
private readAnnotationLiteral(annotation: any): string | undefined {
|
|
392
|
+
const literal = Array.isArray(annotation?.literalValues) ? annotation.literalValues[0] : undefined;
|
|
393
|
+
if (!literal) {
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
const value = literal?.value;
|
|
397
|
+
if (typeof value === 'string') {
|
|
398
|
+
return value.trim();
|
|
399
|
+
}
|
|
400
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
401
|
+
return String(value);
|
|
402
|
+
}
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private resolveInstanceIri(member: any): string | undefined {
|
|
407
|
+
const namedIri = this.normalizeIri(getIriForNode(member) ?? '');
|
|
408
|
+
if (namedIri) {
|
|
409
|
+
return namedIri;
|
|
410
|
+
}
|
|
411
|
+
const resolved = member?.ref?.ref ?? member?.ref?._ref;
|
|
412
|
+
if (resolved) {
|
|
413
|
+
const resolvedIri = this.normalizeIri(getIriForNode(resolved) ?? '');
|
|
414
|
+
if (resolvedIri) {
|
|
415
|
+
return resolvedIri;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return undefined;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private resolveTypeIri(typeRef: any): string | undefined {
|
|
422
|
+
const resolved = typeRef?.ref ?? typeRef?._ref;
|
|
423
|
+
if (resolved) {
|
|
424
|
+
const resolvedIri = this.normalizeIri(getIriForNode(resolved) ?? '');
|
|
425
|
+
if (resolvedIri) {
|
|
426
|
+
return resolvedIri;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return undefined;
|
|
430
|
+
}
|
|
145
431
|
}
|
package/src/oml/oml-rename.ts
CHANGED
|
@@ -114,6 +114,7 @@ export class OmlRenameProvider extends DefaultRenameProvider {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
private buildReplacement(refText: string, newName: string): string {
|
|
117
|
+
const escapedName = escapeIdentifier(newName);
|
|
117
118
|
if (refText.startsWith('<') && refText.endsWith('>')) {
|
|
118
119
|
const inner = refText.slice(1, -1);
|
|
119
120
|
return `<${this.replaceIriTail(inner, newName)}>`;
|
|
@@ -125,7 +126,7 @@ export class OmlRenameProvider extends DefaultRenameProvider {
|
|
|
125
126
|
if (qnameMatch) {
|
|
126
127
|
return `${qnameMatch[1]}${newName}`;
|
|
127
128
|
}
|
|
128
|
-
return
|
|
129
|
+
return escapedName;
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
private replaceIriTail(iri: string, newName: string): string {
|
|
@@ -138,3 +139,22 @@ export class OmlRenameProvider extends DefaultRenameProvider {
|
|
|
138
139
|
return newName;
|
|
139
140
|
}
|
|
140
141
|
}
|
|
142
|
+
|
|
143
|
+
const OML_KEYWORDS = new Set([
|
|
144
|
+
'all', 'annotation', 'as', 'aspect', 'asymmetric', 'builtIn', 'builtin', 'bundle', 'concept', 'description',
|
|
145
|
+
'differentFrom', 'domain', 'entity', 'exactly', 'extends', 'forward', 'from', 'functional', 'includes',
|
|
146
|
+
'instance', 'inverse', 'irreflexive', 'key', 'language', 'length', 'max', 'maxExclusive', 'maxInclusive',
|
|
147
|
+
'maxLength', 'min', 'minExclusive', 'minInclusive', 'minLength', 'oneOf', 'pattern', 'property', 'range', 'ref',
|
|
148
|
+
'reflexive', 'relation', 'restricts', 'reverse', 'rule', 'sameAs', 'scalar', 'self', 'some', 'symmetric', 'to',
|
|
149
|
+
'transitive', 'uses', 'vocabulary'
|
|
150
|
+
]);
|
|
151
|
+
|
|
152
|
+
function escapeIdentifier(value: string): string {
|
|
153
|
+
if (!value) {
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
if (value.startsWith('^')) {
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
return OML_KEYWORDS.has(value) ? `^${value}` : value;
|
|
160
|
+
}
|
package/src/oml/oml-utils.ts
CHANGED
|
@@ -164,6 +164,7 @@ const GITHUB_COPILOT_TRANSIENT_DOCUMENT_SCHEMES = new Set([
|
|
|
164
164
|
'chat-editing-text-model',
|
|
165
165
|
'chat-editing-snapshot-text-model',
|
|
166
166
|
'vscode-chat-code-block',
|
|
167
|
+
'git',
|
|
167
168
|
]);
|
|
168
169
|
|
|
169
170
|
export function isTransientEditorDocumentUri(uri: string): boolean {
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { DefaultIndexManager, type AstNode, type LangiumDocument, type LangiumSharedCoreServices, type ReferenceDescription } from 'langium';
|
|
2
|
-
import type { CancellationToken } from 'vscode-jsonrpc';
|
|
3
|
-
export declare class OmlIndexManager extends DefaultIndexManager {
|
|
4
|
-
private readonly services;
|
|
5
|
-
constructor(services: LangiumSharedCoreServices);
|
|
6
|
-
findAllReferences(targetNode: AstNode, astNodePath: string): import("langium").Stream<ReferenceDescription>;
|
|
7
|
-
updateReferences(document: LangiumDocument, cancelToken?: CancellationToken): Promise<void>;
|
|
8
|
-
isAffected(document: LangiumDocument, changedUris: Set<string>): boolean;
|
|
9
|
-
private canonicalizeUri;
|
|
10
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
|
-
import { AstUtils, DefaultIndexManager, URI, UriUtils, stream } from 'langium';
|
|
3
|
-
import { canonicalizeWorkspaceDocumentUri } from './oml-workspace.js';
|
|
4
|
-
export class OmlIndexManager extends DefaultIndexManager {
|
|
5
|
-
constructor(services) {
|
|
6
|
-
super(services);
|
|
7
|
-
this.services = services;
|
|
8
|
-
}
|
|
9
|
-
findAllReferences(targetNode, astNodePath) {
|
|
10
|
-
const targetDocUri = this.canonicalizeUri(AstUtils.getDocument(targetNode).uri);
|
|
11
|
-
const result = [];
|
|
12
|
-
this.referenceIndex.forEach(docRefs => {
|
|
13
|
-
docRefs.forEach(refDescr => {
|
|
14
|
-
if (UriUtils.equals(this.canonicalizeUri(refDescr.targetUri), targetDocUri) && refDescr.targetPath === astNodePath) {
|
|
15
|
-
result.push(refDescr);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
return stream(result);
|
|
20
|
-
}
|
|
21
|
-
async updateReferences(document, cancelToken) {
|
|
22
|
-
const services = this.serviceRegistry.getServices(document.uri);
|
|
23
|
-
const references = await services.workspace.ReferenceDescriptionProvider.createDescriptions(document, cancelToken);
|
|
24
|
-
const sourceUri = this.canonicalizeUri(document.uri);
|
|
25
|
-
this.referenceIndex.set(document.uri.toString(), references.map(ref => {
|
|
26
|
-
const targetUri = this.canonicalizeUri(ref.targetUri);
|
|
27
|
-
return {
|
|
28
|
-
...ref,
|
|
29
|
-
sourceUri,
|
|
30
|
-
targetUri,
|
|
31
|
-
local: UriUtils.equals(sourceUri, targetUri),
|
|
32
|
-
};
|
|
33
|
-
}));
|
|
34
|
-
}
|
|
35
|
-
isAffected(document, changedUris) {
|
|
36
|
-
const references = this.referenceIndex.get(document.uri.toString());
|
|
37
|
-
if (!references) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
const canonicalChangedUris = new Set(Array.from(changedUris, uri => this.canonicalizeUri(uri).toString()));
|
|
41
|
-
return references.some(ref => !ref.local && canonicalChangedUris.has(this.canonicalizeUri(ref.targetUri).toString()));
|
|
42
|
-
}
|
|
43
|
-
canonicalizeUri(uri) {
|
|
44
|
-
const parsedUri = typeof uri === 'string' ? URI.parse(uri) : uri;
|
|
45
|
-
return canonicalizeWorkspaceDocumentUri(this.services.workspace.WorkspaceManager, parsedUri);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
//# sourceMappingURL=oml-index-manager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oml-index-manager.js","sourceRoot":"","sources":["../../src/oml/oml-index-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
|
-
|
|
3
|
-
import { AstUtils, DefaultIndexManager, URI, UriUtils, stream, type AstNode, type LangiumDocument, type LangiumSharedCoreServices, type ReferenceDescription } from 'langium';
|
|
4
|
-
import type { CancellationToken } from 'vscode-jsonrpc';
|
|
5
|
-
import { canonicalizeWorkspaceDocumentUri } from './oml-workspace.js';
|
|
6
|
-
|
|
7
|
-
export class OmlIndexManager extends DefaultIndexManager {
|
|
8
|
-
private readonly services: LangiumSharedCoreServices;
|
|
9
|
-
|
|
10
|
-
constructor(services: LangiumSharedCoreServices) {
|
|
11
|
-
super(services);
|
|
12
|
-
this.services = services;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
override findAllReferences(targetNode: AstNode, astNodePath: string) {
|
|
16
|
-
const targetDocUri = this.canonicalizeUri(AstUtils.getDocument(targetNode).uri);
|
|
17
|
-
const result: ReferenceDescription[] = [];
|
|
18
|
-
this.referenceIndex.forEach(docRefs => {
|
|
19
|
-
docRefs.forEach(refDescr => {
|
|
20
|
-
if (UriUtils.equals(this.canonicalizeUri(refDescr.targetUri), targetDocUri) && refDescr.targetPath === astNodePath) {
|
|
21
|
-
result.push(refDescr);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
return stream(result);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
override async updateReferences(document: LangiumDocument, cancelToken?: CancellationToken): Promise<void> {
|
|
29
|
-
const services = this.serviceRegistry.getServices(document.uri);
|
|
30
|
-
const references = await services.workspace.ReferenceDescriptionProvider.createDescriptions(document, cancelToken);
|
|
31
|
-
const sourceUri = this.canonicalizeUri(document.uri);
|
|
32
|
-
this.referenceIndex.set(document.uri.toString(), references.map(ref => {
|
|
33
|
-
const targetUri = this.canonicalizeUri(ref.targetUri);
|
|
34
|
-
return {
|
|
35
|
-
...ref,
|
|
36
|
-
sourceUri,
|
|
37
|
-
targetUri,
|
|
38
|
-
local: UriUtils.equals(sourceUri, targetUri),
|
|
39
|
-
};
|
|
40
|
-
}));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
override isAffected(document: LangiumDocument, changedUris: Set<string>): boolean {
|
|
44
|
-
const references = this.referenceIndex.get(document.uri.toString());
|
|
45
|
-
if (!references) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
const canonicalChangedUris = new Set(Array.from(changedUris, uri => this.canonicalizeUri(uri).toString()));
|
|
49
|
-
return references.some(ref => !ref.local && canonicalChangedUris.has(this.canonicalizeUri(ref.targetUri).toString()));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private canonicalizeUri(uri: URI | string): URI {
|
|
53
|
-
const parsedUri = typeof uri === 'string' ? URI.parse(uri) : uri;
|
|
54
|
-
return canonicalizeWorkspaceDocumentUri(this.services.workspace.WorkspaceManager, parsedUri);
|
|
55
|
-
}
|
|
56
|
-
}
|