@domainlang/language 0.6.0 → 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 +2 -0
- package/out/domain-lang-module.js.map +1 -1
- package/out/lsp/domain-lang-index-manager.d.ts +69 -1
- package/out/lsp/domain-lang-index-manager.js +173 -5
- package/out/lsp/domain-lang-index-manager.js.map +1 -1
- 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-workspace-manager.d.ts +25 -0
- package/out/lsp/domain-lang-workspace-manager.js +102 -3
- package/out/lsp/domain-lang-workspace-manager.js.map +1 -1
- package/out/main.js +114 -19
- package/out/main.js.map +1 -1
- package/out/services/import-resolver.d.ts +29 -6
- package/out/services/import-resolver.js +48 -9
- package/out/services/import-resolver.js.map +1 -1
- 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 +11 -0
- package/out/validation/import.js +62 -2
- 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 +2 -0
- package/src/lsp/domain-lang-index-manager.ts +196 -5
- package/src/lsp/domain-lang-scope-provider.ts +134 -0
- package/src/lsp/domain-lang-workspace-manager.ts +128 -3
- package/src/main.ts +153 -22
- package/src/services/import-resolver.ts +60 -9
- package/src/validation/constants.ts +24 -0
- package/src/validation/import.ts +75 -2
- package/src/validation/maps.ts +59 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @domainlang/language
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@domainlang/language)[](https://www.npmjs.com/package/@domainlang/language)[](https://sonarcloud.io/summary/new_code?id=DomainLang_DomainLang)[](https://sonarcloud.io/summary/new_code?id=DomainLang_DomainLang)
|
|
4
4
|
[](https://github.com/DomainLang/DomainLang/blob/main/LICENSE)
|
|
5
5
|
|
|
6
6
|
Core language library for [DomainLang](https://github.com/DomainLang/DomainLang) - a Domain-Driven Design modeling language built with [Langium](https://langium.org/).
|
|
@@ -4,6 +4,7 @@ import { DomainLangGeneratedModule, DomainLangGeneratedSharedModule } from './ge
|
|
|
4
4
|
import { registerValidationChecks } from './validation/domain-lang-validator.js';
|
|
5
5
|
import { QualifiedNameProvider } from './lsp/domain-lang-naming.js';
|
|
6
6
|
import { DomainLangScopeComputation } from './lsp/domain-lang-scope.js';
|
|
7
|
+
import { DomainLangScopeProvider } from './lsp/domain-lang-scope-provider.js';
|
|
7
8
|
import { DomainLangFormatter } from './lsp/domain-lang-formatter.js';
|
|
8
9
|
import { DomainLangHoverProvider } from './lsp/hover/domain-lang-hover.js';
|
|
9
10
|
import { DomainLangCompletionProvider } from './lsp/domain-lang-completion.js';
|
|
@@ -30,6 +31,7 @@ export const DomainLangModule = {
|
|
|
30
31
|
},
|
|
31
32
|
references: {
|
|
32
33
|
ScopeComputation: (services) => new DomainLangScopeComputation(services),
|
|
34
|
+
ScopeProvider: (services) => new DomainLangScopeProvider(services),
|
|
33
35
|
QualifiedNameProvider: () => new QualifiedNameProvider()
|
|
34
36
|
},
|
|
35
37
|
lsp: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-lang-module.js","sourceRoot":"","sources":["../src/domain-lang-module.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"domain-lang-module.js","sourceRoot":"","sources":["../src/domain-lang-module.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ import { CancellationToken } from 'vscode-jsonrpc';
|
|
|
14
14
|
* **How it works:**
|
|
15
15
|
* - When a document is indexed, we ensure all its imports are also loaded
|
|
16
16
|
* - Maintains a reverse dependency graph: importedUri → Set<importingUri>
|
|
17
|
+
* - Also tracks import specifiers to detect when file moves affect resolution
|
|
17
18
|
* - Overrides `isAffected()` to also check this graph
|
|
18
19
|
* - This integrates with Langium's native `DocumentBuilder.update()` flow
|
|
19
20
|
*
|
|
@@ -31,6 +32,13 @@ export declare class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
31
32
|
* Value: Set of URIs of documents that import the key document
|
|
32
33
|
*/
|
|
33
34
|
private readonly importDependencies;
|
|
35
|
+
/**
|
|
36
|
+
* Maps document URI to its import specifiers and their resolved URIs.
|
|
37
|
+
* Used to detect when file moves could affect import resolution.
|
|
38
|
+
* Key: importing document URI
|
|
39
|
+
* Value: Map of import specifier → resolved URI
|
|
40
|
+
*/
|
|
41
|
+
private readonly documentImportSpecifiers;
|
|
34
42
|
/**
|
|
35
43
|
* Tracks documents that have had their imports loaded to avoid redundant work.
|
|
36
44
|
* Cleared on workspace config changes.
|
|
@@ -68,7 +76,9 @@ export declare class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
68
76
|
isAffected(document: LangiumDocument, changedUris: Set<string>): boolean;
|
|
69
77
|
/**
|
|
70
78
|
* Tracks import dependencies for a document.
|
|
71
|
-
* For each import in the document, records
|
|
79
|
+
* For each import in the document, records:
|
|
80
|
+
* 1. That the imported URI is depended upon (for direct change detection)
|
|
81
|
+
* 2. The import specifier used (for file move detection)
|
|
72
82
|
*/
|
|
73
83
|
private trackImportDependencies;
|
|
74
84
|
/**
|
|
@@ -99,4 +109,62 @@ export declare class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
99
109
|
* Called when a document's content changes.
|
|
100
110
|
*/
|
|
101
111
|
markForReprocessing(uri: string): void;
|
|
112
|
+
/**
|
|
113
|
+
* Gets all documents that import the given URI.
|
|
114
|
+
* Used to find documents that need rebuilding when a file changes.
|
|
115
|
+
*
|
|
116
|
+
* @param uri - The URI of the changed/deleted file
|
|
117
|
+
* @returns Set of URIs (as strings) of documents that import this file
|
|
118
|
+
*/
|
|
119
|
+
getDependentDocuments(uri: string): Set<string>;
|
|
120
|
+
/**
|
|
121
|
+
* Gets the resolved import URIs for a document.
|
|
122
|
+
* Returns only URIs where import resolution succeeded (non-empty resolved URI).
|
|
123
|
+
*
|
|
124
|
+
* @param documentUri - The URI of the document
|
|
125
|
+
* @returns Set of resolved import URIs, or empty set if none
|
|
126
|
+
*/
|
|
127
|
+
getResolvedImports(documentUri: string): Set<string>;
|
|
128
|
+
/**
|
|
129
|
+
* Gets all documents that would be affected by changes to the given URIs.
|
|
130
|
+
* This includes direct dependents and transitive dependents.
|
|
131
|
+
*
|
|
132
|
+
* @param changedUris - URIs of changed/deleted files
|
|
133
|
+
* @returns Set of all affected document URIs
|
|
134
|
+
*/
|
|
135
|
+
getAllAffectedDocuments(changedUris: Iterable<string>): Set<string>;
|
|
136
|
+
/**
|
|
137
|
+
* Gets documents that have import specifiers which might be affected by file moves.
|
|
138
|
+
*
|
|
139
|
+
* When a file is moved/renamed, import specifiers that previously resolved to it
|
|
140
|
+
* (or could now resolve to it) need to be re-evaluated. This method finds documents
|
|
141
|
+
* whose imports might resolve differently after the file system change.
|
|
142
|
+
*
|
|
143
|
+
* @param changedUris - URIs of changed/deleted/created files
|
|
144
|
+
* @returns Set of document URIs that should be rebuilt
|
|
145
|
+
*/
|
|
146
|
+
getDocumentsWithPotentiallyAffectedImports(changedUris: Iterable<string>): Set<string>;
|
|
147
|
+
/**
|
|
148
|
+
* Extracts path segments from URIs for fuzzy matching.
|
|
149
|
+
*/
|
|
150
|
+
private extractPathSegments;
|
|
151
|
+
/**
|
|
152
|
+
* Adds path segments from a single URI to the set.
|
|
153
|
+
*/
|
|
154
|
+
private addPathSegmentsFromUri;
|
|
155
|
+
/**
|
|
156
|
+
* Finds documents with import specifiers matching any of the given paths.
|
|
157
|
+
*/
|
|
158
|
+
private findDocumentsMatchingPaths;
|
|
159
|
+
/**
|
|
160
|
+
* Checks if any specifier OR its resolved URI matches the changed paths.
|
|
161
|
+
*
|
|
162
|
+
* This handles both regular imports and path aliases:
|
|
163
|
+
* - Regular: `./domains/sales.dlang` matches path `sales.dlang`
|
|
164
|
+
* - Aliased: `@domains/sales.dlang` resolves to `/full/path/domains/sales.dlang`
|
|
165
|
+
* When the file moves, the resolved URI matches but the specifier doesn't
|
|
166
|
+
*
|
|
167
|
+
* We check both to ensure moves of aliased imports trigger revalidation.
|
|
168
|
+
*/
|
|
169
|
+
private hasMatchingSpecifierOrResolvedUri;
|
|
102
170
|
}
|
|
@@ -14,6 +14,7 @@ import { resolveImportPath } from '../utils/import-utils.js';
|
|
|
14
14
|
* **How it works:**
|
|
15
15
|
* - When a document is indexed, we ensure all its imports are also loaded
|
|
16
16
|
* - Maintains a reverse dependency graph: importedUri → Set<importingUri>
|
|
17
|
+
* - Also tracks import specifiers to detect when file moves affect resolution
|
|
17
18
|
* - Overrides `isAffected()` to also check this graph
|
|
18
19
|
* - This integrates with Langium's native `DocumentBuilder.update()` flow
|
|
19
20
|
*
|
|
@@ -33,6 +34,13 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
33
34
|
* Value: Set of URIs of documents that import the key document
|
|
34
35
|
*/
|
|
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();
|
|
36
44
|
/**
|
|
37
45
|
* Tracks documents that have had their imports loaded to avoid redundant work.
|
|
38
46
|
* Cleared on workspace config changes.
|
|
@@ -97,13 +105,16 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
97
105
|
}
|
|
98
106
|
/**
|
|
99
107
|
* Tracks import dependencies for a document.
|
|
100
|
-
* For each import in the document, records
|
|
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)
|
|
101
111
|
*/
|
|
102
112
|
async trackImportDependencies(document) {
|
|
103
113
|
const importingUri = document.uri.toString();
|
|
104
114
|
// First, remove old dependencies from this document
|
|
105
115
|
// (in case imports changed)
|
|
106
116
|
this.removeDocumentFromDependencies(importingUri);
|
|
117
|
+
this.documentImportSpecifiers.delete(importingUri);
|
|
107
118
|
// Skip if document isn't ready (no parse result)
|
|
108
119
|
if (document.state < DocumentState.Parsed) {
|
|
109
120
|
return;
|
|
@@ -112,12 +123,15 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
112
123
|
if (!model.imports) {
|
|
113
124
|
return;
|
|
114
125
|
}
|
|
126
|
+
const specifierMap = new Map();
|
|
115
127
|
for (const imp of model.imports) {
|
|
116
128
|
if (!imp.uri)
|
|
117
129
|
continue;
|
|
118
130
|
try {
|
|
119
131
|
const resolvedUri = await resolveImportPath(document, imp.uri);
|
|
120
132
|
const importedUri = resolvedUri.toString();
|
|
133
|
+
// Track the specifier → resolved URI mapping
|
|
134
|
+
specifierMap.set(imp.uri, importedUri);
|
|
121
135
|
// Add to reverse dependency graph: importedUri → importingUri
|
|
122
136
|
let dependents = this.importDependencies.get(importedUri);
|
|
123
137
|
if (!dependents) {
|
|
@@ -127,9 +141,13 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
127
141
|
dependents.add(importingUri);
|
|
128
142
|
}
|
|
129
143
|
catch {
|
|
130
|
-
// Import resolution failed -
|
|
144
|
+
// Import resolution failed - still track the specifier with empty resolution
|
|
145
|
+
specifierMap.set(imp.uri, '');
|
|
131
146
|
}
|
|
132
147
|
}
|
|
148
|
+
if (specifierMap.size > 0) {
|
|
149
|
+
this.documentImportSpecifiers.set(importingUri, specifierMap);
|
|
150
|
+
}
|
|
133
151
|
}
|
|
134
152
|
/**
|
|
135
153
|
* Ensures all imported documents are loaded and available.
|
|
@@ -168,8 +186,10 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
168
186
|
}
|
|
169
187
|
// Load or create the imported document
|
|
170
188
|
const importedDoc = await langiumDocuments.getOrCreateDocument(resolvedUri);
|
|
171
|
-
// If document is
|
|
172
|
-
|
|
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) {
|
|
173
193
|
newDocs.push(importedDoc);
|
|
174
194
|
}
|
|
175
195
|
}
|
|
@@ -177,7 +197,7 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
177
197
|
// Import resolution failed - validation will report the error
|
|
178
198
|
}
|
|
179
199
|
}
|
|
180
|
-
// Build any newly discovered documents
|
|
200
|
+
// Build any newly discovered documents to Validated state
|
|
181
201
|
// This triggers indexing which will recursively load their imports
|
|
182
202
|
if (newDocs.length > 0) {
|
|
183
203
|
await documentBuilder.build(newDocs, { validation: true });
|
|
@@ -208,6 +228,7 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
208
228
|
*/
|
|
209
229
|
clearImportDependencies() {
|
|
210
230
|
this.importDependencies.clear();
|
|
231
|
+
this.documentImportSpecifiers.clear();
|
|
211
232
|
this.importsLoaded.clear();
|
|
212
233
|
}
|
|
213
234
|
/**
|
|
@@ -217,5 +238,152 @@ export class DomainLangIndexManager extends DefaultIndexManager {
|
|
|
217
238
|
markForReprocessing(uri) {
|
|
218
239
|
this.importsLoaded.delete(uri);
|
|
219
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
|
+
}
|
|
220
388
|
}
|
|
221
389
|
//# sourceMappingURL=domain-lang-index-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-lang-index-manager.js","sourceRoot":"","sources":["../../src/lsp/domain-lang-index-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D
|
|
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"}
|
|
@@ -52,6 +52,31 @@ export declare class DomainLangWorkspaceManager extends DefaultWorkspaceManager
|
|
|
52
52
|
shouldIncludeEntry(entry: FileSystemNode): boolean;
|
|
53
53
|
initializeWorkspace(folders: WorkspaceFolder[], cancelToken?: CancellationToken): Promise<void>;
|
|
54
54
|
protected loadAdditionalDocuments(folders: WorkspaceFolder[], collector: (document: LangiumDocument) => void): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Loads standalone .dlang files from workspace folders recursively.
|
|
57
|
+
*
|
|
58
|
+
* Skips:
|
|
59
|
+
* - Module directories (directories with model.yaml) - loaded via import graph
|
|
60
|
+
* - `.dlang/cache` directory - package cache managed by CLI
|
|
61
|
+
*
|
|
62
|
+
* @param folders - Workspace folders to scan
|
|
63
|
+
* @param moduleDirectories - Set of directories containing model.yaml (to skip)
|
|
64
|
+
* @param collector - Document collector callback
|
|
65
|
+
*/
|
|
66
|
+
private loadStandaloneFiles;
|
|
67
|
+
/**
|
|
68
|
+
* Recursively loads .dlang files from a directory.
|
|
69
|
+
* Skips module directories and the .dlang/cache package cache.
|
|
70
|
+
*/
|
|
71
|
+
private loadDlangFilesRecursively;
|
|
72
|
+
/**
|
|
73
|
+
* Checks if a directory entry is a .dlang file.
|
|
74
|
+
*/
|
|
75
|
+
private isDlangFile;
|
|
76
|
+
/**
|
|
77
|
+
* Attempts to load a document, returning undefined on failure.
|
|
78
|
+
*/
|
|
79
|
+
private tryLoadDocument;
|
|
55
80
|
/**
|
|
56
81
|
* Finds ALL model.yaml files in the workspace.
|
|
57
82
|
* Delegates to shared manifest utilities.
|