@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/src/validation/import.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Cancellation } from 'langium';
|
|
|
5
5
|
import type { DomainLangAstType, ImportStatement } from '../generated/ast.js';
|
|
6
6
|
import type { DomainLangServices } from '../domain-lang-module.js';
|
|
7
7
|
import type { WorkspaceManager } from '../services/workspace-manager.js';
|
|
8
|
+
import type { ImportResolver } from '../services/import-resolver.js';
|
|
8
9
|
import type { ExtendedDependencySpec, ModelManifest, LockFile } from '../services/types.js';
|
|
9
10
|
import { ValidationMessages, buildCodeDescription, IssueCodes } from './constants.js';
|
|
10
11
|
|
|
@@ -15,15 +16,18 @@ import { ValidationMessages, buildCodeDescription, IssueCodes } from './constant
|
|
|
15
16
|
* the shared WorkspaceManager service with its cached manifest/lock file reading.
|
|
16
17
|
*
|
|
17
18
|
* Checks:
|
|
19
|
+
* - All import URIs resolve to existing files
|
|
18
20
|
* - External imports require manifest + alias
|
|
19
21
|
* - Local path dependencies stay inside workspace
|
|
20
22
|
* - Lock file exists for external dependencies
|
|
21
23
|
*/
|
|
22
24
|
export class ImportValidator {
|
|
23
25
|
private readonly workspaceManager: WorkspaceManager;
|
|
26
|
+
private readonly importResolver: ImportResolver;
|
|
24
27
|
|
|
25
28
|
constructor(services: DomainLangServices) {
|
|
26
29
|
this.workspaceManager = services.imports.WorkspaceManager;
|
|
30
|
+
this.importResolver = services.imports.ImportResolver;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/**
|
|
@@ -48,6 +52,13 @@ export class ImportValidator {
|
|
|
48
52
|
return;
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
// First, verify the import resolves to a valid file
|
|
56
|
+
// This catches renamed/moved/deleted files immediately
|
|
57
|
+
const resolveError = await this.validateImportResolves(imp, document, accept);
|
|
58
|
+
if (resolveError) {
|
|
59
|
+
return; // Don't continue with other validations if can't resolve
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
if (!this.isExternalImport(imp.uri)) {
|
|
52
63
|
return;
|
|
53
64
|
}
|
|
@@ -117,6 +128,63 @@ export class ImportValidator {
|
|
|
117
128
|
return true;
|
|
118
129
|
}
|
|
119
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Validates that an import URI resolves to an existing file.
|
|
133
|
+
* Returns true if there was an error (import doesn't resolve).
|
|
134
|
+
*/
|
|
135
|
+
private async validateImportResolves(
|
|
136
|
+
imp: ImportStatement,
|
|
137
|
+
document: LangiumDocument,
|
|
138
|
+
accept: ValidationAcceptor
|
|
139
|
+
): Promise<boolean> {
|
|
140
|
+
if (!imp.uri) {
|
|
141
|
+
return true; // Error already reported
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const docDir = path.dirname(document.uri.fsPath);
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
const resolvedUri = await this.importResolver.resolveFrom(docDir, imp.uri);
|
|
148
|
+
|
|
149
|
+
// Check if the resolved file actually exists
|
|
150
|
+
const filePath = resolvedUri.fsPath;
|
|
151
|
+
const exists = await this.fileExists(filePath);
|
|
152
|
+
|
|
153
|
+
if (!exists) {
|
|
154
|
+
accept('error', ValidationMessages.IMPORT_UNRESOLVED(imp.uri), {
|
|
155
|
+
node: imp,
|
|
156
|
+
property: 'uri',
|
|
157
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
158
|
+
data: { code: IssueCodes.ImportUnresolved, uri: imp.uri }
|
|
159
|
+
});
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return false;
|
|
164
|
+
} catch {
|
|
165
|
+
// Resolution failed - report as unresolved import
|
|
166
|
+
accept('error', ValidationMessages.IMPORT_UNRESOLVED(imp.uri), {
|
|
167
|
+
node: imp,
|
|
168
|
+
property: 'uri',
|
|
169
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
170
|
+
data: { code: IssueCodes.ImportUnresolved, uri: imp.uri }
|
|
171
|
+
});
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Checks if a file exists (async).
|
|
178
|
+
*/
|
|
179
|
+
private async fileExists(filePath: string): Promise<boolean> {
|
|
180
|
+
try {
|
|
181
|
+
const stat = await fs.stat(filePath);
|
|
182
|
+
return stat.isFile();
|
|
183
|
+
} catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
120
188
|
/**
|
|
121
189
|
* Gets the normalized dependency configuration for an alias.
|
|
122
190
|
*/
|
|
@@ -296,8 +364,13 @@ export function createImportChecks(services: DomainLangServices): ValidationChec
|
|
|
296
364
|
return {
|
|
297
365
|
// Langium 4.x supports async validators via MaybePromise<void>
|
|
298
366
|
ImportStatement: async (imp, accept, cancelToken) => {
|
|
299
|
-
|
|
300
|
-
|
|
367
|
+
// Get document from root (Model), not from ImportStatement
|
|
368
|
+
// Langium sets $document only on the root AST node
|
|
369
|
+
const root = imp.$container;
|
|
370
|
+
const document = root?.$document;
|
|
371
|
+
if (!document) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
301
374
|
|
|
302
375
|
await validator.checkImportPath(imp, accept, document, cancelToken);
|
|
303
376
|
}
|
package/src/validation/maps.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ValidationAcceptor } from 'langium';
|
|
2
2
|
import type { ContextMap, DomainMap } from '../generated/ast.js';
|
|
3
|
-
import { ValidationMessages, buildCodeDescription } from './constants.js';
|
|
3
|
+
import { ValidationMessages, buildCodeDescription, IssueCodes } from './constants.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Validates that a context map contains at least one bounded context.
|
|
@@ -22,6 +22,36 @@ function validateContextMapHasContexts(
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Validates that MultiReference items in a context map resolve.
|
|
27
|
+
* Langium doesn't report errors for unresolved MultiReference items by default,
|
|
28
|
+
* so we need custom validation to catch these cases.
|
|
29
|
+
*
|
|
30
|
+
* @param map - The context map to validate
|
|
31
|
+
* @param accept - The validation acceptor for reporting issues
|
|
32
|
+
*/
|
|
33
|
+
function validateContextMapReferences(
|
|
34
|
+
map: ContextMap,
|
|
35
|
+
accept: ValidationAcceptor
|
|
36
|
+
): void {
|
|
37
|
+
if (!map.boundedContexts) return;
|
|
38
|
+
|
|
39
|
+
for (const multiRef of map.boundedContexts) {
|
|
40
|
+
// A MultiReference has a $refText (the source text) and items (resolved refs)
|
|
41
|
+
// If $refText exists but items is empty, the reference didn't resolve
|
|
42
|
+
const refText = multiRef.$refText;
|
|
43
|
+
if (refText && multiRef.items.length === 0) {
|
|
44
|
+
accept('error', ValidationMessages.UNRESOLVED_REFERENCE('BoundedContext', refText), {
|
|
45
|
+
node: map,
|
|
46
|
+
// Find the CST node for this specific reference
|
|
47
|
+
property: 'boundedContexts',
|
|
48
|
+
index: map.boundedContexts.indexOf(multiRef),
|
|
49
|
+
code: IssueCodes.UnresolvedReference
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
25
55
|
/**
|
|
26
56
|
* Validates that a context map has at least one relationship if it contains multiple contexts.
|
|
27
57
|
* Multiple unrelated contexts should have documented relationships.
|
|
@@ -66,11 +96,38 @@ function validateDomainMapHasDomains(
|
|
|
66
96
|
}
|
|
67
97
|
}
|
|
68
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Validates that MultiReference items in a domain map resolve.
|
|
101
|
+
*
|
|
102
|
+
* @param map - The domain map to validate
|
|
103
|
+
* @param accept - The validation acceptor for reporting issues
|
|
104
|
+
*/
|
|
105
|
+
function validateDomainMapReferences(
|
|
106
|
+
map: DomainMap,
|
|
107
|
+
accept: ValidationAcceptor
|
|
108
|
+
): void {
|
|
109
|
+
if (!map.domains) return;
|
|
110
|
+
|
|
111
|
+
for (const multiRef of map.domains) {
|
|
112
|
+
const refText = multiRef.$refText;
|
|
113
|
+
if (refText && multiRef.items.length === 0) {
|
|
114
|
+
accept('error', ValidationMessages.UNRESOLVED_REFERENCE('Domain', refText), {
|
|
115
|
+
node: map,
|
|
116
|
+
property: 'domains',
|
|
117
|
+
index: map.domains.indexOf(multiRef),
|
|
118
|
+
code: IssueCodes.UnresolvedReference
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
69
124
|
export const contextMapChecks = [
|
|
70
125
|
validateContextMapHasContexts,
|
|
126
|
+
validateContextMapReferences,
|
|
71
127
|
validateContextMapHasRelationships
|
|
72
128
|
];
|
|
73
129
|
|
|
74
130
|
export const domainMapChecks = [
|
|
75
|
-
validateDomainMapHasDomains
|
|
131
|
+
validateDomainMapHasDomains,
|
|
132
|
+
validateDomainMapReferences
|
|
76
133
|
];
|