@domainlang/language 0.5.2 → 0.7.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/README.md +1 -1
- package/out/domain-lang-module.js +5 -1
- package/out/domain-lang-module.js.map +1 -1
- package/out/generated/ast.d.ts +24 -0
- package/out/generated/ast.js.map +1 -1
- package/out/generated/grammar.js +22 -32
- package/out/generated/grammar.js.map +1 -1
- package/out/index.d.ts +2 -5
- package/out/index.js +10 -6
- package/out/index.js.map +1 -1
- package/out/lsp/domain-lang-code-actions.js +14 -8
- package/out/lsp/domain-lang-code-actions.js.map +1 -1
- package/out/lsp/domain-lang-completion.d.ts +3 -0
- package/out/lsp/domain-lang-completion.js +41 -13
- package/out/lsp/domain-lang-completion.js.map +1 -1
- package/out/lsp/domain-lang-formatter.js +24 -18
- package/out/lsp/domain-lang-formatter.js.map +1 -1
- package/out/lsp/domain-lang-index-manager.d.ts +170 -0
- package/out/lsp/domain-lang-index-manager.js +389 -0
- package/out/lsp/domain-lang-index-manager.js.map +1 -0
- package/out/lsp/domain-lang-scope-provider.d.ts +67 -0
- package/out/lsp/domain-lang-scope-provider.js +95 -0
- package/out/lsp/domain-lang-scope-provider.js.map +1 -0
- package/out/lsp/domain-lang-scope.js +31 -17
- package/out/lsp/domain-lang-scope.js.map +1 -1
- package/out/lsp/domain-lang-workspace-manager.d.ts +76 -9
- package/out/lsp/domain-lang-workspace-manager.js +176 -54
- package/out/lsp/domain-lang-workspace-manager.js.map +1 -1
- package/out/lsp/hover/domain-lang-hover.d.ts +45 -1
- package/out/lsp/hover/domain-lang-hover.js +308 -232
- package/out/lsp/hover/domain-lang-hover.js.map +1 -1
- package/out/lsp/hover/domain-lang-keywords.d.ts +3 -7
- package/out/lsp/hover/domain-lang-keywords.js +115 -38
- package/out/lsp/hover/domain-lang-keywords.js.map +1 -1
- package/out/lsp/manifest-diagnostics.js +95 -50
- package/out/lsp/manifest-diagnostics.js.map +1 -1
- package/out/main.js +204 -17
- package/out/main.js.map +1 -1
- package/out/services/import-resolver.d.ts +39 -2
- package/out/services/import-resolver.js +77 -12
- package/out/services/import-resolver.js.map +1 -1
- package/out/services/types.d.ts +2 -2
- package/out/services/workspace-manager.d.ts +33 -31
- package/out/services/workspace-manager.js +92 -148
- package/out/services/workspace-manager.js.map +1 -1
- package/out/utils/document-utils.d.ts +41 -0
- package/out/utils/document-utils.js +64 -0
- package/out/utils/document-utils.js.map +1 -0
- package/out/utils/import-utils.d.ts +0 -17
- package/out/utils/import-utils.js +2 -32
- package/out/utils/import-utils.js.map +1 -1
- package/out/utils/manifest-utils.d.ts +56 -0
- package/out/utils/manifest-utils.js +119 -0
- package/out/utils/manifest-utils.js.map +1 -0
- package/out/validation/constants.d.ts +13 -0
- package/out/validation/constants.js +18 -0
- package/out/validation/constants.js.map +1 -1
- package/out/validation/import.d.ts +12 -2
- package/out/validation/import.js +95 -22
- package/out/validation/import.js.map +1 -1
- package/out/validation/maps.js +51 -2
- package/out/validation/maps.js.map +1 -1
- package/package.json +1 -1
- package/src/domain-lang-module.ts +6 -1
- package/src/domain-lang.langium +37 -13
- package/src/generated/ast.ts +24 -0
- package/src/generated/grammar.ts +22 -32
- package/src/index.ts +12 -6
- package/src/lsp/domain-lang-code-actions.ts +13 -8
- package/src/lsp/domain-lang-completion.ts +61 -13
- package/src/lsp/domain-lang-formatter.ts +28 -23
- package/src/lsp/domain-lang-index-manager.ts +447 -0
- package/src/lsp/domain-lang-scope-provider.ts +134 -0
- package/src/lsp/domain-lang-scope.ts +29 -17
- package/src/lsp/domain-lang-workspace-manager.ts +201 -53
- package/src/lsp/hover/domain-lang-hover.ts +332 -226
- package/src/lsp/hover/domain-lang-keywords.ts +129 -43
- package/src/lsp/manifest-diagnostics.ts +100 -59
- package/src/main.ts +258 -16
- package/src/services/import-resolver.ts +91 -12
- package/src/services/types.ts +2 -2
- package/src/services/workspace-manager.ts +101 -175
- package/src/utils/document-utils.ts +80 -0
- package/src/utils/import-utils.ts +2 -40
- package/src/utils/manifest-utils.ts +132 -0
- package/src/validation/constants.ts +24 -0
- package/src/validation/import.ts +107 -24
- package/src/validation/maps.ts +59 -2
- package/out/lsp/hover/ddd-pattern-explanations.d.ts +0 -50
- package/out/lsp/hover/ddd-pattern-explanations.js +0 -196
- package/out/lsp/hover/ddd-pattern-explanations.js.map +0 -1
- package/out/services/dependency-analyzer.d.ts +0 -58
- package/out/services/dependency-analyzer.js +0 -254
- package/out/services/dependency-analyzer.js.map +0 -1
- package/out/services/dependency-resolver.d.ts +0 -146
- package/out/services/dependency-resolver.js +0 -452
- package/out/services/dependency-resolver.js.map +0 -1
- package/out/services/git-url-resolver.browser.d.ts +0 -10
- package/out/services/git-url-resolver.browser.js +0 -19
- package/out/services/git-url-resolver.browser.js.map +0 -1
- package/out/services/git-url-resolver.d.ts +0 -158
- package/out/services/git-url-resolver.js +0 -416
- package/out/services/git-url-resolver.js.map +0 -1
- package/out/services/governance-validator.d.ts +0 -44
- package/out/services/governance-validator.js +0 -153
- package/out/services/governance-validator.js.map +0 -1
- package/out/services/semver.d.ts +0 -98
- package/out/services/semver.js +0 -195
- package/out/services/semver.js.map +0 -1
- package/src/lsp/hover/ddd-pattern-explanations.ts +0 -237
- package/src/services/dependency-analyzer.ts +0 -321
- package/src/services/dependency-resolver.ts +0 -551
- package/src/services/git-url-resolver.browser.ts +0 -26
- package/src/services/git-url-resolver.ts +0 -517
- package/src/services/governance-validator.ts +0 -177
- package/src/services/semver.ts +0 -213
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { DefaultIndexManager, DocumentState } from 'langium';
|
|
2
|
+
import { CancellationToken } from 'vscode-jsonrpc';
|
|
3
|
+
import { resolveImportPath } from '../utils/import-utils.js';
|
|
4
|
+
/**
|
|
5
|
+
* Custom IndexManager that extends Langium's default to:
|
|
6
|
+
* 1. Automatically load imported documents during indexing
|
|
7
|
+
* 2. Track import dependencies for cross-file revalidation
|
|
8
|
+
*
|
|
9
|
+
* **Why this exists:**
|
|
10
|
+
* Langium's `DefaultIndexManager.isAffected()` only checks cross-references
|
|
11
|
+
* (elements declared with `[Type]` grammar syntax). DomainLang's imports use
|
|
12
|
+
* string literals (`import "path"`), which are not cross-references.
|
|
13
|
+
*
|
|
14
|
+
* **How it works:**
|
|
15
|
+
* - When a document is indexed, we ensure all its imports are also loaded
|
|
16
|
+
* - Maintains a reverse dependency graph: importedUri → Set<importingUri>
|
|
17
|
+
* - Also tracks import specifiers to detect when file moves affect resolution
|
|
18
|
+
* - Overrides `isAffected()` to also check this graph
|
|
19
|
+
* - This integrates with Langium's native `DocumentBuilder.update()` flow
|
|
20
|
+
*
|
|
21
|
+
* **Integration with Langium:**
|
|
22
|
+
* This approach is idiomatic because:
|
|
23
|
+
* 1. `updateContent()` is called for EVERY document during build
|
|
24
|
+
* 2. We load imports during indexing, BEFORE linking/validation
|
|
25
|
+
* 3. `DocumentBuilder.shouldRelink()` calls `IndexManager.isAffected()`
|
|
26
|
+
* 4. No need for separate lifecycle service - this IS the central place
|
|
27
|
+
*/
|
|
28
|
+
export class DomainLangIndexManager extends DefaultIndexManager {
|
|
29
|
+
constructor(services) {
|
|
30
|
+
super(services);
|
|
31
|
+
/**
|
|
32
|
+
* Reverse dependency graph: maps a document URI to all documents that import it.
|
|
33
|
+
* Key: imported document URI (string)
|
|
34
|
+
* Value: Set of URIs of documents that import the key document
|
|
35
|
+
*/
|
|
36
|
+
this.importDependencies = new Map();
|
|
37
|
+
/**
|
|
38
|
+
* Maps document URI to its import specifiers and their resolved URIs.
|
|
39
|
+
* Used to detect when file moves could affect import resolution.
|
|
40
|
+
* Key: importing document URI
|
|
41
|
+
* Value: Map of import specifier → resolved URI
|
|
42
|
+
*/
|
|
43
|
+
this.documentImportSpecifiers = new Map();
|
|
44
|
+
/**
|
|
45
|
+
* Tracks documents that have had their imports loaded to avoid redundant work.
|
|
46
|
+
* Cleared on workspace config changes.
|
|
47
|
+
*/
|
|
48
|
+
this.importsLoaded = new Set();
|
|
49
|
+
this.sharedServices = services;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extends the default content update to:
|
|
53
|
+
* 1. Ensure all imported documents are loaded
|
|
54
|
+
* 2. Track import dependencies for change propagation
|
|
55
|
+
*
|
|
56
|
+
* Called by Langium during the IndexedContent build phase.
|
|
57
|
+
* This is BEFORE linking/validation, so imports are available for resolution.
|
|
58
|
+
*/
|
|
59
|
+
async updateContent(document, cancelToken = CancellationToken.None) {
|
|
60
|
+
// First, do the standard content indexing
|
|
61
|
+
await super.updateContent(document, cancelToken);
|
|
62
|
+
// Then, ensure imports are loaded and track dependencies
|
|
63
|
+
await this.ensureImportsLoaded(document);
|
|
64
|
+
await this.trackImportDependencies(document);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Extends the default remove to also clean up import dependencies.
|
|
68
|
+
*/
|
|
69
|
+
remove(uri) {
|
|
70
|
+
super.remove(uri);
|
|
71
|
+
const uriString = uri.toString();
|
|
72
|
+
this.removeImportDependencies(uriString);
|
|
73
|
+
this.importsLoaded.delete(uriString);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Extends the default content removal to also clean up import dependencies.
|
|
77
|
+
*/
|
|
78
|
+
removeContent(uri) {
|
|
79
|
+
super.removeContent(uri);
|
|
80
|
+
const uriString = uri.toString();
|
|
81
|
+
this.removeImportDependencies(uriString);
|
|
82
|
+
this.importsLoaded.delete(uriString);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Extends `isAffected` to also check import dependencies.
|
|
86
|
+
*
|
|
87
|
+
* A document is affected if:
|
|
88
|
+
* 1. It has cross-references to any changed document (default Langium behavior)
|
|
89
|
+
* 2. It imports any of the changed documents (our extension)
|
|
90
|
+
*/
|
|
91
|
+
isAffected(document, changedUris) {
|
|
92
|
+
// First check Langium's default: cross-references
|
|
93
|
+
if (super.isAffected(document, changedUris)) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
// Then check our import dependencies
|
|
97
|
+
const docUri = document.uri.toString();
|
|
98
|
+
for (const changedUri of changedUris) {
|
|
99
|
+
const dependents = this.importDependencies.get(changedUri);
|
|
100
|
+
if (dependents?.has(docUri)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Tracks import dependencies for a document.
|
|
108
|
+
* For each import in the document, records:
|
|
109
|
+
* 1. That the imported URI is depended upon (for direct change detection)
|
|
110
|
+
* 2. The import specifier used (for file move detection)
|
|
111
|
+
*/
|
|
112
|
+
async trackImportDependencies(document) {
|
|
113
|
+
const importingUri = document.uri.toString();
|
|
114
|
+
// First, remove old dependencies from this document
|
|
115
|
+
// (in case imports changed)
|
|
116
|
+
this.removeDocumentFromDependencies(importingUri);
|
|
117
|
+
this.documentImportSpecifiers.delete(importingUri);
|
|
118
|
+
// Skip if document isn't ready (no parse result)
|
|
119
|
+
if (document.state < DocumentState.Parsed) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const model = document.parseResult.value;
|
|
123
|
+
if (!model.imports) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const specifierMap = new Map();
|
|
127
|
+
for (const imp of model.imports) {
|
|
128
|
+
if (!imp.uri)
|
|
129
|
+
continue;
|
|
130
|
+
try {
|
|
131
|
+
const resolvedUri = await resolveImportPath(document, imp.uri);
|
|
132
|
+
const importedUri = resolvedUri.toString();
|
|
133
|
+
// Track the specifier → resolved URI mapping
|
|
134
|
+
specifierMap.set(imp.uri, importedUri);
|
|
135
|
+
// Add to reverse dependency graph: importedUri → importingUri
|
|
136
|
+
let dependents = this.importDependencies.get(importedUri);
|
|
137
|
+
if (!dependents) {
|
|
138
|
+
dependents = new Set();
|
|
139
|
+
this.importDependencies.set(importedUri, dependents);
|
|
140
|
+
}
|
|
141
|
+
dependents.add(importingUri);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Import resolution failed - still track the specifier with empty resolution
|
|
145
|
+
specifierMap.set(imp.uri, '');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (specifierMap.size > 0) {
|
|
149
|
+
this.documentImportSpecifiers.set(importingUri, specifierMap);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Ensures all imported documents are loaded and available.
|
|
154
|
+
* This is called during indexing, BEFORE linking/validation,
|
|
155
|
+
* so that cross-file references can be resolved.
|
|
156
|
+
*
|
|
157
|
+
* Works for both workspace files and standalone files.
|
|
158
|
+
*/
|
|
159
|
+
async ensureImportsLoaded(document) {
|
|
160
|
+
const uriString = document.uri.toString();
|
|
161
|
+
// Skip if already processed (avoid redundant work and infinite loops)
|
|
162
|
+
if (this.importsLoaded.has(uriString)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.importsLoaded.add(uriString);
|
|
166
|
+
// Skip if document isn't ready (no parse result)
|
|
167
|
+
if (document.state < DocumentState.Parsed) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const model = document.parseResult.value;
|
|
171
|
+
if (!model.imports || model.imports.length === 0) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const langiumDocuments = this.sharedServices.workspace.LangiumDocuments;
|
|
175
|
+
const documentBuilder = this.sharedServices.workspace.DocumentBuilder;
|
|
176
|
+
const newDocs = [];
|
|
177
|
+
for (const imp of model.imports) {
|
|
178
|
+
if (!imp.uri)
|
|
179
|
+
continue;
|
|
180
|
+
try {
|
|
181
|
+
const resolvedUri = await resolveImportPath(document, imp.uri);
|
|
182
|
+
const importedUriString = resolvedUri.toString();
|
|
183
|
+
// Skip if already loaded
|
|
184
|
+
if (this.importsLoaded.has(importedUriString)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
// Load or create the imported document
|
|
188
|
+
const importedDoc = await langiumDocuments.getOrCreateDocument(resolvedUri);
|
|
189
|
+
// If document is not yet validated, add to batch for building
|
|
190
|
+
// This ensures all imported documents reach Validated state,
|
|
191
|
+
// preventing "workspace state is already Validated" errors
|
|
192
|
+
if (importedDoc.state < DocumentState.Validated) {
|
|
193
|
+
newDocs.push(importedDoc);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Import resolution failed - validation will report the error
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Build any newly discovered documents to Validated state
|
|
201
|
+
// This triggers indexing which will recursively load their imports
|
|
202
|
+
if (newDocs.length > 0) {
|
|
203
|
+
await documentBuilder.build(newDocs, { validation: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Removes a document from the import dependencies graph entirely.
|
|
208
|
+
* Called when a document is deleted.
|
|
209
|
+
*/
|
|
210
|
+
removeImportDependencies(uri) {
|
|
211
|
+
// Remove as an imported document
|
|
212
|
+
this.importDependencies.delete(uri);
|
|
213
|
+
// Remove from all dependency sets (as an importer)
|
|
214
|
+
this.removeDocumentFromDependencies(uri);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Removes a document from all dependency sets.
|
|
218
|
+
* Called when a document's imports change or it's deleted.
|
|
219
|
+
*/
|
|
220
|
+
removeDocumentFromDependencies(uri) {
|
|
221
|
+
for (const deps of this.importDependencies.values()) {
|
|
222
|
+
deps.delete(uri);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Clears all import-related caches.
|
|
227
|
+
* Call this when workspace configuration changes.
|
|
228
|
+
*/
|
|
229
|
+
clearImportDependencies() {
|
|
230
|
+
this.importDependencies.clear();
|
|
231
|
+
this.documentImportSpecifiers.clear();
|
|
232
|
+
this.importsLoaded.clear();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Marks a document as needing import re-loading.
|
|
236
|
+
* Called when a document's content changes.
|
|
237
|
+
*/
|
|
238
|
+
markForReprocessing(uri) {
|
|
239
|
+
this.importsLoaded.delete(uri);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Gets all documents that import the given URI.
|
|
243
|
+
* Used to find documents that need rebuilding when a file changes.
|
|
244
|
+
*
|
|
245
|
+
* @param uri - The URI of the changed/deleted file
|
|
246
|
+
* @returns Set of URIs (as strings) of documents that import this file
|
|
247
|
+
*/
|
|
248
|
+
getDependentDocuments(uri) {
|
|
249
|
+
return this.importDependencies.get(uri) ?? new Set();
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Gets the resolved import URIs for a document.
|
|
253
|
+
* Returns only URIs where import resolution succeeded (non-empty resolved URI).
|
|
254
|
+
*
|
|
255
|
+
* @param documentUri - The URI of the document
|
|
256
|
+
* @returns Set of resolved import URIs, or empty set if none
|
|
257
|
+
*/
|
|
258
|
+
getResolvedImports(documentUri) {
|
|
259
|
+
const specifierMap = this.documentImportSpecifiers.get(documentUri);
|
|
260
|
+
if (!specifierMap) {
|
|
261
|
+
return new Set();
|
|
262
|
+
}
|
|
263
|
+
const resolved = new Set();
|
|
264
|
+
for (const resolvedUri of specifierMap.values()) {
|
|
265
|
+
// Only include successfully resolved imports (non-empty string)
|
|
266
|
+
if (resolvedUri) {
|
|
267
|
+
resolved.add(resolvedUri);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return resolved;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Gets all documents that would be affected by changes to the given URIs.
|
|
274
|
+
* This includes direct dependents and transitive dependents.
|
|
275
|
+
*
|
|
276
|
+
* @param changedUris - URIs of changed/deleted files
|
|
277
|
+
* @returns Set of all affected document URIs
|
|
278
|
+
*/
|
|
279
|
+
getAllAffectedDocuments(changedUris) {
|
|
280
|
+
const affected = new Set();
|
|
281
|
+
const toProcess = [...changedUris];
|
|
282
|
+
while (toProcess.length > 0) {
|
|
283
|
+
const uri = toProcess.pop();
|
|
284
|
+
if (!uri) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const dependents = this.importDependencies.get(uri);
|
|
288
|
+
if (dependents) {
|
|
289
|
+
for (const dep of dependents) {
|
|
290
|
+
if (!affected.has(dep)) {
|
|
291
|
+
affected.add(dep);
|
|
292
|
+
// Also check transitive dependents
|
|
293
|
+
toProcess.push(dep);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return affected;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Gets documents that have import specifiers which might be affected by file moves.
|
|
302
|
+
*
|
|
303
|
+
* When a file is moved/renamed, import specifiers that previously resolved to it
|
|
304
|
+
* (or could now resolve to it) need to be re-evaluated. This method finds documents
|
|
305
|
+
* whose imports might resolve differently after the file system change.
|
|
306
|
+
*
|
|
307
|
+
* @param changedUris - URIs of changed/deleted/created files
|
|
308
|
+
* @returns Set of document URIs that should be rebuilt
|
|
309
|
+
*/
|
|
310
|
+
getDocumentsWithPotentiallyAffectedImports(changedUris) {
|
|
311
|
+
const changedPaths = this.extractPathSegments(changedUris);
|
|
312
|
+
return this.findDocumentsMatchingPaths(changedPaths);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Extracts path segments from URIs for fuzzy matching.
|
|
316
|
+
*/
|
|
317
|
+
extractPathSegments(uris) {
|
|
318
|
+
const paths = new Set();
|
|
319
|
+
for (const uri of uris) {
|
|
320
|
+
this.addPathSegmentsFromUri(uri, paths);
|
|
321
|
+
}
|
|
322
|
+
return paths;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Adds path segments from a single URI to the set.
|
|
326
|
+
*/
|
|
327
|
+
addPathSegmentsFromUri(uri, paths) {
|
|
328
|
+
try {
|
|
329
|
+
const url = new URL(uri);
|
|
330
|
+
const pathParts = url.pathname.split('/').filter(p => p.length > 0);
|
|
331
|
+
// Add filename
|
|
332
|
+
const fileName = pathParts.at(-1);
|
|
333
|
+
if (fileName) {
|
|
334
|
+
paths.add(fileName);
|
|
335
|
+
}
|
|
336
|
+
// Add parent/filename combination
|
|
337
|
+
if (pathParts.length >= 2) {
|
|
338
|
+
paths.add(pathParts.slice(-2).join('/'));
|
|
339
|
+
}
|
|
340
|
+
// Add grandparent/parent/filename combination
|
|
341
|
+
if (pathParts.length >= 3) {
|
|
342
|
+
paths.add(pathParts.slice(-3).join('/'));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
// Invalid URI, skip
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Finds documents with import specifiers matching any of the given paths.
|
|
351
|
+
*/
|
|
352
|
+
findDocumentsMatchingPaths(changedPaths) {
|
|
353
|
+
const affected = new Set();
|
|
354
|
+
for (const [docUri, specifierMap] of this.documentImportSpecifiers) {
|
|
355
|
+
if (this.hasMatchingSpecifierOrResolvedUri(specifierMap, changedPaths)) {
|
|
356
|
+
affected.add(docUri);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return affected;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Checks if any specifier OR its resolved URI matches the changed paths.
|
|
363
|
+
*
|
|
364
|
+
* This handles both regular imports and path aliases:
|
|
365
|
+
* - Regular: `./domains/sales.dlang` matches path `sales.dlang`
|
|
366
|
+
* - Aliased: `@domains/sales.dlang` resolves to `/full/path/domains/sales.dlang`
|
|
367
|
+
* When the file moves, the resolved URI matches but the specifier doesn't
|
|
368
|
+
*
|
|
369
|
+
* We check both to ensure moves of aliased imports trigger revalidation.
|
|
370
|
+
*/
|
|
371
|
+
hasMatchingSpecifierOrResolvedUri(specifierMap, changedPaths) {
|
|
372
|
+
for (const [specifier, resolvedUri] of specifierMap.entries()) {
|
|
373
|
+
const normalizedSpecifier = specifier.replace(/^[.@/]+/, '');
|
|
374
|
+
for (const changedPath of changedPaths) {
|
|
375
|
+
// Check the raw specifier (handles relative imports)
|
|
376
|
+
if (specifier.includes(changedPath) || changedPath.endsWith(normalizedSpecifier)) {
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
// Check the resolved URI (handles path aliases like @domains/...)
|
|
380
|
+
// The resolved URI contains the full file path which matches moved files
|
|
381
|
+
if (resolvedUri?.includes(changedPath)) {
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=domain-lang-index-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-lang-index-manager.js","sourceRoot":"","sources":["../../src/lsp/domain-lang-index-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DomainLang Scope Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements import-based scoping for the DomainLang DSL.
|
|
5
|
+
*
|
|
6
|
+
* **Key Concept:**
|
|
7
|
+
* Unlike languages with global namespaces, DomainLang enforces strict import-based scoping:
|
|
8
|
+
* - Elements are only visible if they are defined in the current document OR explicitly imported
|
|
9
|
+
* - The global scope is restricted to imported documents only
|
|
10
|
+
* - Transitive imports do NOT provide scope (only direct imports)
|
|
11
|
+
*
|
|
12
|
+
* **Why this matters:**
|
|
13
|
+
* Without this, Langium's DefaultScopeProvider would make ALL indexed documents visible
|
|
14
|
+
* in the global scope, which would:
|
|
15
|
+
* 1. Allow referencing elements that haven't been imported
|
|
16
|
+
* 2. Make the import system meaningless
|
|
17
|
+
* 3. Create confusion about dependencies between files
|
|
18
|
+
*
|
|
19
|
+
* @see https://langium.org/docs/recipes/scoping/ for Langium scoping patterns
|
|
20
|
+
*/
|
|
21
|
+
import type { ReferenceInfo, Scope } from 'langium';
|
|
22
|
+
import { DefaultScopeProvider } from 'langium';
|
|
23
|
+
import type { DomainLangServices } from '../domain-lang-module.js';
|
|
24
|
+
/**
|
|
25
|
+
* Custom scope provider that restricts cross-file references to imported documents only.
|
|
26
|
+
*
|
|
27
|
+
* Extends Langium's DefaultScopeProvider to override the global scope computation.
|
|
28
|
+
*/
|
|
29
|
+
export declare class DomainLangScopeProvider extends DefaultScopeProvider {
|
|
30
|
+
/**
|
|
31
|
+
* Reference to IndexManager for getting resolved imports.
|
|
32
|
+
*/
|
|
33
|
+
private readonly domainLangIndexManager;
|
|
34
|
+
constructor(services: DomainLangServices);
|
|
35
|
+
/**
|
|
36
|
+
* Override getGlobalScope to restrict it to imported documents only.
|
|
37
|
+
*
|
|
38
|
+
* The default Langium behavior includes ALL documents in the workspace.
|
|
39
|
+
* We restrict this to:
|
|
40
|
+
* 1. The current document's own exported symbols
|
|
41
|
+
* 2. Exported symbols from directly imported documents
|
|
42
|
+
*
|
|
43
|
+
* @param referenceType - The AST type being referenced
|
|
44
|
+
* @param context - Information about the reference
|
|
45
|
+
* @returns A scope containing only visible elements
|
|
46
|
+
*/
|
|
47
|
+
protected getGlobalScope(referenceType: string, context: ReferenceInfo): Scope;
|
|
48
|
+
/**
|
|
49
|
+
* Gets the set of document URIs that are directly imported by the given document.
|
|
50
|
+
*
|
|
51
|
+
* Uses the resolved imports tracked by DomainLangIndexManager during indexing.
|
|
52
|
+
* This ensures accurate resolution including path aliases.
|
|
53
|
+
*
|
|
54
|
+
* @param document - The document to get imports for
|
|
55
|
+
* @returns Set of imported document URIs (as strings)
|
|
56
|
+
*/
|
|
57
|
+
private getImportedDocumentUris;
|
|
58
|
+
/**
|
|
59
|
+
* Filters the global index to only include descriptions from imported documents.
|
|
60
|
+
*
|
|
61
|
+
* @param referenceType - The AST type being referenced
|
|
62
|
+
* @param currentDocument - The document making the reference
|
|
63
|
+
* @param importedUris - Set of URIs that are in scope
|
|
64
|
+
* @returns Stream of filtered descriptions
|
|
65
|
+
*/
|
|
66
|
+
private filterDescriptionsByImports;
|
|
67
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DomainLang Scope Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements import-based scoping for the DomainLang DSL.
|
|
5
|
+
*
|
|
6
|
+
* **Key Concept:**
|
|
7
|
+
* Unlike languages with global namespaces, DomainLang enforces strict import-based scoping:
|
|
8
|
+
* - Elements are only visible if they are defined in the current document OR explicitly imported
|
|
9
|
+
* - The global scope is restricted to imported documents only
|
|
10
|
+
* - Transitive imports do NOT provide scope (only direct imports)
|
|
11
|
+
*
|
|
12
|
+
* **Why this matters:**
|
|
13
|
+
* Without this, Langium's DefaultScopeProvider would make ALL indexed documents visible
|
|
14
|
+
* in the global scope, which would:
|
|
15
|
+
* 1. Allow referencing elements that haven't been imported
|
|
16
|
+
* 2. Make the import system meaningless
|
|
17
|
+
* 3. Create confusion about dependencies between files
|
|
18
|
+
*
|
|
19
|
+
* @see https://langium.org/docs/recipes/scoping/ for Langium scoping patterns
|
|
20
|
+
*/
|
|
21
|
+
import { AstUtils, DefaultScopeProvider, EMPTY_SCOPE, MapScope } from 'langium';
|
|
22
|
+
/**
|
|
23
|
+
* Custom scope provider that restricts cross-file references to imported documents only.
|
|
24
|
+
*
|
|
25
|
+
* Extends Langium's DefaultScopeProvider to override the global scope computation.
|
|
26
|
+
*/
|
|
27
|
+
export class DomainLangScopeProvider extends DefaultScopeProvider {
|
|
28
|
+
constructor(services) {
|
|
29
|
+
super(services);
|
|
30
|
+
this.domainLangIndexManager = services.shared.workspace.IndexManager;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Override getGlobalScope to restrict it to imported documents only.
|
|
34
|
+
*
|
|
35
|
+
* The default Langium behavior includes ALL documents in the workspace.
|
|
36
|
+
* We restrict this to:
|
|
37
|
+
* 1. The current document's own exported symbols
|
|
38
|
+
* 2. Exported symbols from directly imported documents
|
|
39
|
+
*
|
|
40
|
+
* @param referenceType - The AST type being referenced
|
|
41
|
+
* @param context - Information about the reference
|
|
42
|
+
* @returns A scope containing only visible elements
|
|
43
|
+
*/
|
|
44
|
+
getGlobalScope(referenceType, context) {
|
|
45
|
+
const document = AstUtils.getDocument(context.container);
|
|
46
|
+
if (!document) {
|
|
47
|
+
return EMPTY_SCOPE;
|
|
48
|
+
}
|
|
49
|
+
// Get the set of URIs that are in scope for this document
|
|
50
|
+
const importedUris = this.getImportedDocumentUris(document);
|
|
51
|
+
// Filter the global index to only include descriptions from imported documents
|
|
52
|
+
const filteredDescriptions = this.filterDescriptionsByImports(referenceType, document, importedUris);
|
|
53
|
+
// Create a scope from the filtered descriptions
|
|
54
|
+
return new MapScope(filteredDescriptions);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Gets the set of document URIs that are directly imported by the given document.
|
|
58
|
+
*
|
|
59
|
+
* Uses the resolved imports tracked by DomainLangIndexManager during indexing.
|
|
60
|
+
* This ensures accurate resolution including path aliases.
|
|
61
|
+
*
|
|
62
|
+
* @param document - The document to get imports for
|
|
63
|
+
* @returns Set of imported document URIs (as strings)
|
|
64
|
+
*/
|
|
65
|
+
getImportedDocumentUris(document) {
|
|
66
|
+
const docUri = document.uri.toString();
|
|
67
|
+
// Get resolved imports from the index manager (tracked during indexing)
|
|
68
|
+
const resolvedImports = this.domainLangIndexManager.getResolvedImports(docUri);
|
|
69
|
+
// Always include the current document itself
|
|
70
|
+
const importedUris = new Set([docUri]);
|
|
71
|
+
// Add all resolved import URIs
|
|
72
|
+
for (const resolvedUri of resolvedImports) {
|
|
73
|
+
importedUris.add(resolvedUri);
|
|
74
|
+
}
|
|
75
|
+
return importedUris;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Filters the global index to only include descriptions from imported documents.
|
|
79
|
+
*
|
|
80
|
+
* @param referenceType - The AST type being referenced
|
|
81
|
+
* @param currentDocument - The document making the reference
|
|
82
|
+
* @param importedUris - Set of URIs that are in scope
|
|
83
|
+
* @returns Stream of filtered descriptions
|
|
84
|
+
*/
|
|
85
|
+
filterDescriptionsByImports(referenceType, currentDocument, importedUris) {
|
|
86
|
+
// Get all descriptions of the reference type from the index
|
|
87
|
+
const allDescriptions = this.indexManager.allElements(referenceType);
|
|
88
|
+
// Filter to only those from imported documents
|
|
89
|
+
return allDescriptions.filter(desc => {
|
|
90
|
+
const descDocUri = desc.documentUri.toString();
|
|
91
|
+
return importedUris.has(descDocUri);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=domain-lang-scope-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-lang-scope-provider.js","sourceRoot":"","sources":["../../src/lsp/domain-lang-scope-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,OAAO,EACH,QAAQ,EACR,oBAAoB,EACpB,WAAW,EACX,QAAQ,EACX,MAAM,SAAS,CAAC;AAIjB;;;;GAIG;AACH,MAAM,OAAO,uBAAwB,SAAQ,oBAAoB;IAM7D,YAAY,QAA4B;QACpC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,YAAsC,CAAC;IACnG,CAAC;IAED;;;;;;;;;;;OAWG;IACgB,cAAc,CAAC,aAAqB,EAAE,OAAsB;QAC3E,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,WAAW,CAAC;QACvB,CAAC;QAED,0DAA0D;QAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAE5D,+EAA+E;QAC/E,MAAM,oBAAoB,GAAG,IAAI,CAAC,2BAA2B,CACzD,aAAa,EACb,QAAQ,EACR,YAAY,CACf,CAAC;QAEF,gDAAgD;QAChD,OAAO,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;;OAQG;IACK,uBAAuB,CAAC,QAAyB;QACrD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAEvC,wEAAwE;QACxE,MAAM,eAAe,GAAG,IAAI,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAE/E,6CAA6C;QAC7C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAE/C,+BAA+B;QAC/B,KAAK,MAAM,WAAW,IAAI,eAAe,EAAE,CAAC;YACxC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAClC,CAAC;QAED,OAAO,YAAY,CAAC;IACxB,CAAC;IAED;;;;;;;OAOG;IACK,2BAA2B,CAC/B,aAAqB,EACrB,eAAgC,EAChC,YAAyB;QAEzB,4DAA4D;QAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAErE,+CAA+C;QAC/C,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;YACjC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC/C,OAAO,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACP,CAAC;CACJ"}
|
|
@@ -23,22 +23,29 @@ export class DomainLangScopeComputation extends DefaultScopeComputation {
|
|
|
23
23
|
* @returns A promise resolving to an array of AstNodeDescription
|
|
24
24
|
*/
|
|
25
25
|
async collectExportedSymbols(document, cancelToken = CancellationToken.None) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
try {
|
|
27
|
+
const descr = [];
|
|
28
|
+
for (const modelNode of AstUtils.streamAllContents(document.parseResult.value)) {
|
|
29
|
+
await interruptAndCheck(cancelToken);
|
|
30
|
+
if (isType(modelNode)) {
|
|
31
|
+
let name = this.nameProvider.getName(modelNode);
|
|
32
|
+
if (!name) {
|
|
33
|
+
// Defensive: skip unnamed types
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (isNamespaceDeclaration(modelNode.$container)) {
|
|
37
|
+
name = this.qualifiedNameProvider.getQualifiedName(modelNode.$container, name);
|
|
38
|
+
}
|
|
39
|
+
descr.push(this.descriptions.createDescription(modelNode, name, document));
|
|
37
40
|
}
|
|
38
|
-
descr.push(this.descriptions.createDescription(modelNode, name, document));
|
|
39
41
|
}
|
|
42
|
+
return descr;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Error in collectExportedSymbols:', error);
|
|
46
|
+
// Return empty array on error to prevent crash
|
|
47
|
+
return [];
|
|
40
48
|
}
|
|
41
|
-
return descr;
|
|
42
49
|
}
|
|
43
50
|
/**
|
|
44
51
|
* Computes local scopes for all containers, recursively processing nested namespaces.
|
|
@@ -47,10 +54,17 @@ export class DomainLangScopeComputation extends DefaultScopeComputation {
|
|
|
47
54
|
* @returns A promise resolving to a LocalSymbols map
|
|
48
55
|
*/
|
|
49
56
|
async collectLocalSymbols(document, cancelToken = CancellationToken.None) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
try {
|
|
58
|
+
const model = document.parseResult.value;
|
|
59
|
+
const scopes = new MultiMap();
|
|
60
|
+
await this.processContainer(model, scopes, document, cancelToken);
|
|
61
|
+
return scopes;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error('Error in collectLocalSymbols:', error);
|
|
65
|
+
// Return empty multimap on error to prevent crash
|
|
66
|
+
return new MultiMap();
|
|
67
|
+
}
|
|
54
68
|
}
|
|
55
69
|
/**
|
|
56
70
|
* Recursively processes a container and its children, adding local descriptions and qualified names.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-lang-scope.js","sourceRoot":"","sources":["../../src/lsp/domain-lang-scope.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,uIAAuI;AAcvI,OAAO,EACH,uBAAuB,EACvB,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIrE;;;GAGG;AACH,MAAM,OAAO,0BAA2B,SAAQ,uBAAuB;IAGnE;;;OAGG;IACH,YAAY,QAA4B;QACpC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,qBAAqB,GAAG,QAAQ,CAAC,UAAU,CAAC,qBAAqB,CAAC;IAC3E,CAAC;IAED;;;;;OAKG;IACM,KAAK,CAAC,sBAAsB,CAAC,QAAyB,EAAE,WAAW,GAAG,iBAAiB,CAAC,IAAI;QACjG,MAAM,KAAK,GAAyB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"domain-lang-scope.js","sourceRoot":"","sources":["../../src/lsp/domain-lang-scope.ts"],"names":[],"mappings":"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"}
|