@domainlang/language 0.1.20 → 0.1.82
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/domain-lang-module.d.ts +0 -2
- package/out/domain-lang-module.js +3 -11
- package/out/domain-lang-module.js.map +1 -1
- package/out/generated/ast.d.ts +19 -8
- package/out/generated/ast.js +10 -1
- package/out/generated/ast.js.map +1 -1
- package/out/generated/grammar.d.ts +1 -1
- package/out/generated/grammar.js +123 -28
- package/out/generated/grammar.js.map +1 -1
- package/out/generated/module.d.ts +1 -1
- package/out/generated/module.js +1 -1
- package/out/index.d.ts +0 -3
- package/out/index.js +0 -5
- package/out/index.js.map +1 -1
- package/out/lsp/hover/domain-lang-hover.js +4 -0
- package/out/lsp/hover/domain-lang-hover.js.map +1 -1
- package/out/sdk/index.d.ts +1 -1
- package/out/sdk/loader-node.d.ts +3 -7
- package/out/sdk/loader-node.js +9 -24
- package/out/sdk/loader-node.js.map +1 -1
- package/out/sdk/types.d.ts +21 -0
- package/out/services/dependency-analyzer.d.ts +39 -3
- package/out/services/dependency-analyzer.js +47 -22
- package/out/services/dependency-analyzer.js.map +1 -1
- package/out/services/dependency-resolver.d.ts +45 -68
- package/out/services/dependency-resolver.js +43 -243
- package/out/services/dependency-resolver.js.map +1 -1
- package/out/services/git-url-resolver.browser.d.ts +12 -4
- package/out/services/git-url-resolver.browser.js +1 -5
- package/out/services/git-url-resolver.browser.js.map +1 -1
- package/out/services/git-url-resolver.d.ts +56 -22
- package/out/services/git-url-resolver.js +36 -70
- package/out/services/git-url-resolver.js.map +1 -1
- package/out/services/governance-validator.d.ts +37 -1
- package/out/services/governance-validator.js +10 -4
- package/out/services/governance-validator.js.map +1 -1
- package/out/services/import-resolver.d.ts +6 -65
- package/out/services/import-resolver.js +5 -223
- package/out/services/import-resolver.js.map +1 -1
- package/out/services/performance-optimizer.d.ts +1 -1
- package/out/services/workspace-manager.d.ts +10 -57
- package/out/services/workspace-manager.js +21 -187
- package/out/services/workspace-manager.js.map +1 -1
- package/out/syntaxes/domain-lang.monarch.js +1 -1
- package/out/syntaxes/domain-lang.monarch.js.map +1 -1
- package/out/utils/import-utils.d.ts +12 -4
- package/out/utils/import-utils.js +135 -35
- package/out/utils/import-utils.js.map +1 -1
- package/out/validation/constants.d.ts +0 -103
- package/out/validation/constants.js +1 -140
- package/out/validation/constants.js.map +1 -1
- package/out/validation/domain.js +1 -46
- package/out/validation/domain.js.map +1 -1
- package/out/validation/import.d.ts +22 -46
- package/out/validation/import.js +85 -187
- package/out/validation/import.js.map +1 -1
- package/out/validation/maps.js +6 -10
- package/out/validation/maps.js.map +1 -1
- package/out/validation/metadata.js +1 -5
- package/out/validation/metadata.js.map +1 -1
- package/package.json +6 -8
- package/src/domain-lang-module.ts +6 -18
- package/src/domain-lang.langium +12 -7
- package/src/generated/ast.ts +20 -7
- package/src/generated/grammar.ts +123 -28
- package/src/generated/module.ts +1 -1
- package/src/index.ts +0 -7
- package/src/lsp/hover/domain-lang-hover.ts +2 -0
- package/src/sdk/index.ts +2 -0
- package/src/sdk/loader-node.ts +9 -29
- package/src/sdk/types.ts +23 -0
- package/src/services/dependency-analyzer.ts +84 -24
- package/src/services/dependency-resolver.ts +84 -301
- package/src/services/git-url-resolver.browser.ts +14 -9
- package/src/services/git-url-resolver.ts +93 -86
- package/src/services/governance-validator.ts +47 -5
- package/src/services/import-resolver.ts +8 -270
- package/src/services/performance-optimizer.ts +1 -1
- package/src/services/workspace-manager.ts +46 -237
- package/src/syntaxes/domain-lang.monarch.ts +1 -1
- package/src/utils/import-utils.ts +160 -38
- package/src/validation/constants.ts +1 -181
- package/src/validation/domain.ts +1 -54
- package/src/validation/import.ts +104 -228
- package/src/validation/maps.ts +6 -10
- package/src/validation/metadata.ts +1 -5
- package/out/lsp/domain-lang-code-actions.d.ts +0 -55
- package/out/lsp/domain-lang-code-actions.js +0 -143
- package/out/lsp/domain-lang-code-actions.js.map +0 -1
- package/out/lsp/domain-lang-workspace-manager.d.ts +0 -21
- package/out/lsp/domain-lang-workspace-manager.js +0 -93
- package/out/lsp/domain-lang-workspace-manager.js.map +0 -1
- package/out/lsp/manifest-diagnostics.d.ts +0 -82
- package/out/lsp/manifest-diagnostics.js +0 -230
- package/out/lsp/manifest-diagnostics.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/out/services/types.d.ts +0 -340
- package/out/services/types.js +0 -46
- package/out/services/types.js.map +0 -1
- package/out/validation/manifest.d.ts +0 -144
- package/out/validation/manifest.js +0 -327
- package/out/validation/manifest.js.map +0 -1
- package/src/lsp/domain-lang-code-actions.ts +0 -189
- package/src/lsp/domain-lang-workspace-manager.ts +0 -104
- package/src/lsp/manifest-diagnostics.ts +0 -290
- package/src/services/semver.ts +0 -213
- package/src/services/types.ts +0 -415
- package/src/validation/manifest.ts +0 -439
package/src/validation/import.ts
CHANGED
|
@@ -1,295 +1,171 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
1
|
import type { ValidationAcceptor, ValidationChecks } from 'langium';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
2
|
+
import type { DomainLangAstType, ImportStatement, Model } from '../generated/ast.js';
|
|
3
|
+
import { resolveImportPath } from '../utils/import-utils.js';
|
|
6
4
|
import type { DomainLangServices } from '../domain-lang-module.js';
|
|
7
5
|
import type { LangiumDocument } from 'langium';
|
|
8
|
-
import type { WorkspaceManager } from '../services/workspace-manager.js';
|
|
9
|
-
import type { ExtendedDependencySpec, ModelManifest, LockFile } from '../services/types.js';
|
|
10
|
-
import { ValidationMessages, buildCodeDescription, IssueCodes } from './constants.js';
|
|
11
6
|
|
|
12
7
|
/**
|
|
13
8
|
* Validates import statements in DomainLang.
|
|
14
|
-
*
|
|
15
|
-
* Uses async validators (Langium 4.x supports MaybePromise<void>) to leverage
|
|
16
|
-
* the shared WorkspaceManager service with its cached manifest/lock file reading.
|
|
17
|
-
*
|
|
9
|
+
*
|
|
18
10
|
* Checks:
|
|
19
|
-
* -
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
11
|
+
* - Import paths are resolvable
|
|
12
|
+
* - Named imports exist in target document
|
|
13
|
+
* - Import aliases don't conflict with local names
|
|
22
14
|
*/
|
|
23
15
|
export class ImportValidator {
|
|
24
|
-
private readonly
|
|
16
|
+
private readonly documents: DomainLangServices['shared']['workspace']['LangiumDocuments'];
|
|
25
17
|
|
|
26
18
|
constructor(services: DomainLangServices) {
|
|
27
|
-
this.
|
|
19
|
+
this.documents = services.shared.workspace.LangiumDocuments;
|
|
28
20
|
}
|
|
29
21
|
|
|
30
22
|
/**
|
|
31
|
-
* Validates an import
|
|
32
|
-
*
|
|
33
|
-
* Langium validators can return MaybePromise<void>, enabling async operations
|
|
34
|
-
* like reading manifests via the shared, cached WorkspaceManager.
|
|
23
|
+
* Validates that an import path is resolvable.
|
|
35
24
|
*/
|
|
36
25
|
async checkImportPath(
|
|
37
26
|
imp: ImportStatement,
|
|
38
27
|
accept: ValidationAcceptor,
|
|
39
|
-
document: LangiumDocument
|
|
40
|
-
_cancelToken: Cancellation.CancellationToken
|
|
28
|
+
document: LangiumDocument
|
|
41
29
|
): Promise<void> {
|
|
42
30
|
if (!imp.uri) {
|
|
43
|
-
accept('error',
|
|
31
|
+
accept('error', 'Import statement must have a URI', {
|
|
44
32
|
node: imp,
|
|
45
|
-
keyword: 'import'
|
|
46
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
47
|
-
data: { code: IssueCodes.ImportMissingUri }
|
|
33
|
+
keyword: 'import'
|
|
48
34
|
});
|
|
49
35
|
return;
|
|
50
36
|
}
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const docDir = path.dirname(document.uri.fsPath);
|
|
58
|
-
await this.workspaceManager.initialize(docDir);
|
|
59
|
-
|
|
60
|
-
const manifest = await this.workspaceManager.getManifest();
|
|
61
|
-
if (!manifest) {
|
|
62
|
-
accept('error', ValidationMessages.IMPORT_REQUIRES_MANIFEST(imp.uri), {
|
|
63
|
-
node: imp,
|
|
64
|
-
property: 'uri',
|
|
65
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
66
|
-
data: { code: IssueCodes.ImportRequiresManifest, specifier: imp.uri }
|
|
67
|
-
});
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const alias = imp.uri.split('/')[0];
|
|
72
|
-
const dependency = this.getDependency(manifest, alias);
|
|
73
|
-
|
|
74
|
-
if (!dependency) {
|
|
75
|
-
accept('error', ValidationMessages.IMPORT_NOT_IN_MANIFEST(alias), {
|
|
38
|
+
try {
|
|
39
|
+
await resolveImportPath(document, imp.uri);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
accept('error', `Cannot resolve import: ${message}`, {
|
|
76
43
|
node: imp,
|
|
77
|
-
property: 'uri'
|
|
78
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
79
|
-
data: { code: IssueCodes.ImportNotInManifest, alias }
|
|
44
|
+
property: 'uri'
|
|
80
45
|
});
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
this.validateDependencyConfig(dependency, alias, accept, imp);
|
|
85
|
-
|
|
86
|
-
// External source dependencies require lock file and cached packages
|
|
87
|
-
if (dependency.source) {
|
|
88
|
-
const lockFile = await this.workspaceManager.getLockFile();
|
|
89
|
-
if (!lockFile) {
|
|
90
|
-
accept('error', ValidationMessages.IMPORT_NOT_INSTALLED(alias), {
|
|
91
|
-
node: imp,
|
|
92
|
-
property: 'uri',
|
|
93
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
94
|
-
data: { code: IssueCodes.ImportNotInstalled, alias }
|
|
95
|
-
});
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
await this.validateCachedPackage(dependency, alias, lockFile, accept, imp);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Determines if an import URI is external (requires manifest).
|
|
105
|
-
*
|
|
106
|
-
* Per PRS-010:
|
|
107
|
-
* - Local relative: ./path, ../path
|
|
108
|
-
* - Path aliases: @/path, @alias/path (resolved via manifest paths section)
|
|
109
|
-
* - External: owner/package (requires manifest dependencies)
|
|
110
|
-
*/
|
|
111
|
-
private isExternalImport(uri: string): boolean {
|
|
112
|
-
if (uri.startsWith('./') || uri.startsWith('../')) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
if (uri.startsWith('@')) {
|
|
116
|
-
return false;
|
|
117
46
|
}
|
|
118
|
-
return true;
|
|
119
47
|
}
|
|
120
48
|
|
|
121
49
|
/**
|
|
122
|
-
*
|
|
50
|
+
* Validates that named imports exist in the target document.
|
|
123
51
|
*/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (!dep) {
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (typeof dep === 'string') {
|
|
131
|
-
return { source: alias, ref: dep };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (!dep.source && !dep.path) {
|
|
135
|
-
return { ...dep, source: alias };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return dep;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Validates dependency configuration.
|
|
143
|
-
*/
|
|
144
|
-
private validateDependencyConfig(
|
|
145
|
-
dependency: ExtendedDependencySpec,
|
|
146
|
-
alias: string,
|
|
52
|
+
async checkNamedImports(
|
|
53
|
+
imp: ImportStatement,
|
|
147
54
|
accept: ValidationAcceptor,
|
|
148
|
-
|
|
149
|
-
): void {
|
|
150
|
-
if
|
|
151
|
-
|
|
152
|
-
node: imp,
|
|
153
|
-
property: 'uri',
|
|
154
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
155
|
-
data: { code: IssueCodes.ImportConflictingSourcePath, alias }
|
|
156
|
-
});
|
|
55
|
+
document: LangiumDocument
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
// Only check if we have named imports
|
|
58
|
+
if (!imp.symbols || imp.symbols.length === 0) {
|
|
157
59
|
return;
|
|
158
60
|
}
|
|
159
61
|
|
|
160
|
-
if (!
|
|
161
|
-
|
|
162
|
-
node: imp,
|
|
163
|
-
property: 'uri',
|
|
164
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
165
|
-
data: { code: IssueCodes.ImportMissingSourceOrPath, alias }
|
|
166
|
-
});
|
|
167
|
-
return;
|
|
62
|
+
if (!imp.uri) {
|
|
63
|
+
return; // Already reported by checkImportPath
|
|
168
64
|
}
|
|
169
65
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
66
|
+
try {
|
|
67
|
+
// Resolve the target document
|
|
68
|
+
const targetUri = await resolveImportPath(document, imp.uri);
|
|
69
|
+
const targetDoc = await this.documents.getOrCreateDocument(targetUri);
|
|
70
|
+
|
|
71
|
+
if (!targetDoc.parseResult?.value) {
|
|
72
|
+
accept('error', `Cannot load imported document: ${imp.uri}`, {
|
|
73
|
+
node: imp,
|
|
74
|
+
property: 'uri'
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
178
78
|
|
|
179
|
-
|
|
180
|
-
|
|
79
|
+
// Get all exported symbols from target document
|
|
80
|
+
const targetModel = targetDoc.parseResult.value as Model;
|
|
81
|
+
const exportedSymbols = this.getExportedSymbols(targetModel);
|
|
82
|
+
|
|
83
|
+
// Check each imported symbol
|
|
84
|
+
for (const symbol of imp.symbols) {
|
|
85
|
+
if (!exportedSymbols.has(symbol)) {
|
|
86
|
+
accept('error',
|
|
87
|
+
`Symbol '${symbol}' not found in ${imp.uri}`,
|
|
88
|
+
{
|
|
89
|
+
node: imp,
|
|
90
|
+
property: 'symbols'
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// Import path error already reported by checkImportPath
|
|
97
|
+
return;
|
|
181
98
|
}
|
|
182
99
|
}
|
|
183
100
|
|
|
184
101
|
/**
|
|
185
|
-
*
|
|
102
|
+
* Gets all exportable symbols from a model.
|
|
103
|
+
*
|
|
104
|
+
* In DomainLang, top-level declarations are implicitly exported:
|
|
105
|
+
* - Domains
|
|
106
|
+
* - BoundedContexts
|
|
107
|
+
* - Classifications
|
|
108
|
+
* - Groups
|
|
186
109
|
*/
|
|
187
|
-
private
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
property: 'uri',
|
|
197
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
198
|
-
data: { code: IssueCodes.ImportAbsolutePath, alias, path: dependencyPath }
|
|
199
|
-
});
|
|
200
|
-
return;
|
|
110
|
+
private getExportedSymbols(model: Model): Set<string> {
|
|
111
|
+
const symbols = new Set<string>();
|
|
112
|
+
|
|
113
|
+
// Iterate through all structure elements
|
|
114
|
+
for (const element of model.children ?? []) {
|
|
115
|
+
// Check if element has a name and add it
|
|
116
|
+
if ('name' in element && typeof element.name === 'string') {
|
|
117
|
+
symbols.add(element.name);
|
|
118
|
+
}
|
|
201
119
|
}
|
|
202
120
|
|
|
203
|
-
|
|
204
|
-
const resolvedPath = path.resolve(workspaceRoot, dependencyPath);
|
|
205
|
-
const relativeToWorkspace = path.relative(workspaceRoot, resolvedPath);
|
|
206
|
-
|
|
207
|
-
if (relativeToWorkspace.startsWith('..') || path.isAbsolute(relativeToWorkspace)) {
|
|
208
|
-
accept('error', ValidationMessages.IMPORT_ESCAPES_WORKSPACE(alias), {
|
|
209
|
-
node: imp,
|
|
210
|
-
property: 'uri',
|
|
211
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
212
|
-
data: { code: IssueCodes.ImportEscapesWorkspace, alias }
|
|
213
|
-
});
|
|
214
|
-
}
|
|
121
|
+
return symbols;
|
|
215
122
|
}
|
|
216
123
|
|
|
217
124
|
/**
|
|
218
|
-
*
|
|
125
|
+
* Checks for unused imports.
|
|
126
|
+
*
|
|
127
|
+
* This is a warning, not an error, to avoid being too strict.
|
|
219
128
|
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// Source is guaranteed to exist when this method is called (see caller)
|
|
228
|
-
const packageKey = dependency.source ?? alias;
|
|
229
|
-
const lockedDep = lockFile.dependencies[packageKey];
|
|
230
|
-
|
|
231
|
-
if (!lockedDep) {
|
|
232
|
-
accept('error', ValidationMessages.IMPORT_NOT_INSTALLED(alias), {
|
|
233
|
-
node: imp,
|
|
234
|
-
property: 'uri',
|
|
235
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
236
|
-
data: { code: IssueCodes.ImportNotInstalled, alias }
|
|
237
|
-
});
|
|
129
|
+
checkUnusedImports(
|
|
130
|
+
imp: ImportStatement,
|
|
131
|
+
_accept: ValidationAcceptor,
|
|
132
|
+
_model: Model
|
|
133
|
+
): void {
|
|
134
|
+
// Skip check for wildcard imports (no named imports)
|
|
135
|
+
if (!imp.symbols || imp.symbols.length === 0) {
|
|
238
136
|
return;
|
|
239
137
|
}
|
|
240
138
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const cacheExists = await this.directoryExists(cacheDir);
|
|
245
|
-
if (!cacheExists) {
|
|
246
|
-
accept('error', ValidationMessages.IMPORT_NOT_INSTALLED(alias), {
|
|
247
|
-
node: imp,
|
|
248
|
-
property: 'uri',
|
|
249
|
-
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
250
|
-
data: { code: IssueCodes.ImportNotInstalled, alias }
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Gets the cache directory for a dependency.
|
|
257
|
-
* Per PRS-010: Project-local cache at .dlang/packages/{owner}/{repo}/{commit}/
|
|
258
|
-
*/
|
|
259
|
-
private getCacheDirectory(workspaceRoot: string, source: string, commitHash: string): string {
|
|
260
|
-
const [owner, repo] = source.split('/');
|
|
261
|
-
return path.join(workspaceRoot, '.dlang', 'packages', owner, repo, commitHash);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Checks if a directory exists (async).
|
|
266
|
-
*/
|
|
267
|
-
private async directoryExists(dirPath: string): Promise<boolean> {
|
|
268
|
-
try {
|
|
269
|
-
const stat = await fs.stat(dirPath);
|
|
270
|
-
return stat.isDirectory();
|
|
271
|
-
} catch {
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
139
|
+
// For now, just a placeholder - would require tracking symbol usage
|
|
140
|
+
// across the entire document, which is complex
|
|
141
|
+
// TODO: Implement symbol usage tracking
|
|
274
142
|
}
|
|
275
143
|
}
|
|
276
144
|
|
|
277
145
|
/**
|
|
278
146
|
* Creates validation checks for import statements.
|
|
279
|
-
*
|
|
280
|
-
* Returns async validators that leverage the shared WorkspaceManager
|
|
281
|
-
* for cached manifest/lock file reading.
|
|
282
147
|
*/
|
|
283
|
-
export function createImportChecks(
|
|
284
|
-
const validator = new ImportValidator(services);
|
|
148
|
+
export function createImportChecks(_services: DomainLangServices): ValidationChecks<DomainLangAstType> {
|
|
285
149
|
|
|
286
150
|
return {
|
|
287
|
-
|
|
288
|
-
ImportStatement: async (imp, accept, cancelToken) => {
|
|
151
|
+
ImportStatement: (imp, accept) => {
|
|
289
152
|
const document = imp.$document;
|
|
290
153
|
if (!document) return;
|
|
291
154
|
|
|
292
|
-
|
|
155
|
+
// Note: Langium's validation is synchronous, so async checks won't
|
|
156
|
+
// execute during document validation. These checks will run during
|
|
157
|
+
// the build phase when documents are fully loaded.
|
|
158
|
+
|
|
159
|
+
// For now, just do basic syntax validation
|
|
160
|
+
if (!imp.uri) {
|
|
161
|
+
accept('error', 'Import statement must have a URI', {
|
|
162
|
+
node: imp,
|
|
163
|
+
keyword: 'import'
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// TODO: Implement async validation in a separate build phase
|
|
168
|
+
// This would require using DocumentBuilder.onBuildPhase() or similar
|
|
293
169
|
}
|
|
294
170
|
};
|
|
295
171
|
}
|
package/src/validation/maps.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ValidationAcceptor } from 'langium';
|
|
2
2
|
import type { ContextMap, DomainMap } from '../generated/ast.js';
|
|
3
|
-
import { ValidationMessages, buildCodeDescription } from './constants.js';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Validates that a context map contains at least one bounded context.
|
|
@@ -14,10 +13,9 @@ function validateContextMapHasContexts(
|
|
|
14
13
|
accept: ValidationAcceptor
|
|
15
14
|
): void {
|
|
16
15
|
if (!map.boundedContexts || map.boundedContexts.length === 0) {
|
|
17
|
-
accept('warning',
|
|
16
|
+
accept('warning', `Context Map '${map.name}' contains no bounded contexts`, {
|
|
18
17
|
node: map,
|
|
19
|
-
keyword: 'contains'
|
|
20
|
-
codeDescription: buildCodeDescription('language.md', 'context-maps')
|
|
18
|
+
keyword: 'contains'
|
|
21
19
|
});
|
|
22
20
|
}
|
|
23
21
|
}
|
|
@@ -38,10 +36,9 @@ function validateContextMapHasRelationships(
|
|
|
38
36
|
|
|
39
37
|
// Only warn if multiple contexts exist without relationships
|
|
40
38
|
if (contextCount > 1 && relationshipCount === 0) {
|
|
41
|
-
accept('info',
|
|
39
|
+
accept('info', `Context Map '${map.name}' contains ${contextCount} contexts but no documented relationships`, {
|
|
42
40
|
node: map,
|
|
43
|
-
keyword: 'ContextMap'
|
|
44
|
-
codeDescription: buildCodeDescription('language.md', 'context-maps')
|
|
41
|
+
keyword: 'ContextMap'
|
|
45
42
|
});
|
|
46
43
|
}
|
|
47
44
|
}
|
|
@@ -58,10 +55,9 @@ function validateDomainMapHasDomains(
|
|
|
58
55
|
accept: ValidationAcceptor
|
|
59
56
|
): void {
|
|
60
57
|
if (!map.domains || map.domains.length === 0) {
|
|
61
|
-
accept('warning',
|
|
58
|
+
accept('warning', `Domain Map '${map.name}' contains no domains`, {
|
|
62
59
|
node: map,
|
|
63
|
-
keyword: 'contains'
|
|
64
|
-
codeDescription: buildCodeDescription('language.md', 'domain-maps')
|
|
60
|
+
keyword: 'contains'
|
|
65
61
|
});
|
|
66
62
|
}
|
|
67
63
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ValidationChecks } from 'langium';
|
|
2
2
|
import type { Metadata, DomainLangAstType } from '../generated/ast.js';
|
|
3
|
-
import { ValidationMessages, buildCodeDescription } from './constants.js';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Validation checks for Metadata elements.
|
|
@@ -9,10 +8,7 @@ import { ValidationMessages, buildCodeDescription } from './constants.js';
|
|
|
9
8
|
export const metadataChecks: ValidationChecks<DomainLangAstType> = {
|
|
10
9
|
Metadata(metadata: Metadata, accept) {
|
|
11
10
|
if (!metadata.name) {
|
|
12
|
-
accept('error',
|
|
13
|
-
node: metadata,
|
|
14
|
-
codeDescription: buildCodeDescription('language.md', 'metadata')
|
|
15
|
-
});
|
|
11
|
+
accept('error', 'Metadata must have a name', { node: metadata });
|
|
16
12
|
}
|
|
17
13
|
},
|
|
18
14
|
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Code Action Provider for DomainLang.
|
|
3
|
-
*
|
|
4
|
-
* Provides quick-fix code actions for validation diagnostics.
|
|
5
|
-
*
|
|
6
|
-
* Key Features:
|
|
7
|
-
* - "Add dependency to model.yaml" for unknown import aliases
|
|
8
|
-
* - "Run dlang install" for uninstalled dependencies
|
|
9
|
-
*
|
|
10
|
-
* @module
|
|
11
|
-
*/
|
|
12
|
-
import type { CodeAction, CodeActionParams, Command } from 'vscode-languageserver';
|
|
13
|
-
import type { MaybePromise, LangiumDocument } from 'langium';
|
|
14
|
-
import type { CodeActionProvider } from 'langium/lsp';
|
|
15
|
-
/**
|
|
16
|
-
* Code action provider for DomainLang LSP features.
|
|
17
|
-
*
|
|
18
|
-
* Implements quick fixes for:
|
|
19
|
-
* - Import validation errors (add to model.yaml, run install)
|
|
20
|
-
*/
|
|
21
|
-
export declare class DomainLangCodeActionProvider implements CodeActionProvider {
|
|
22
|
-
/**
|
|
23
|
-
* Generates code actions for the given diagnostics.
|
|
24
|
-
*
|
|
25
|
-
* @param document - The document containing the diagnostics
|
|
26
|
-
* @param params - Code action request parameters including diagnostics
|
|
27
|
-
* @returns Array of code actions, or undefined if none applicable
|
|
28
|
-
*/
|
|
29
|
-
getCodeActions(document: LangiumDocument, params: CodeActionParams): MaybePromise<Array<Command | CodeAction> | undefined>;
|
|
30
|
-
/**
|
|
31
|
-
* Creates code actions for a specific diagnostic.
|
|
32
|
-
*
|
|
33
|
-
* Matches on diagnostic.data.code to determine which quick fix to offer.
|
|
34
|
-
*/
|
|
35
|
-
private createCodeActions;
|
|
36
|
-
/**
|
|
37
|
-
* Creates a code action to add a dependency to model.yaml.
|
|
38
|
-
*
|
|
39
|
-
* This generates a WorkspaceEdit that modifies model.yaml to add
|
|
40
|
-
* the missing dependency with a placeholder version.
|
|
41
|
-
*/
|
|
42
|
-
private createAddToManifestAction;
|
|
43
|
-
/**
|
|
44
|
-
* Creates a code action to create model.yaml with the dependency.
|
|
45
|
-
*/
|
|
46
|
-
private createCreateManifestAction;
|
|
47
|
-
/**
|
|
48
|
-
* Creates a code action to run dlang install.
|
|
49
|
-
*/
|
|
50
|
-
private createRunInstallAction;
|
|
51
|
-
/**
|
|
52
|
-
* Creates a code action to add ref to dependency.
|
|
53
|
-
*/
|
|
54
|
-
private createAddRefAction;
|
|
55
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Code Action Provider for DomainLang.
|
|
3
|
-
*
|
|
4
|
-
* Provides quick-fix code actions for validation diagnostics.
|
|
5
|
-
*
|
|
6
|
-
* Key Features:
|
|
7
|
-
* - "Add dependency to model.yaml" for unknown import aliases
|
|
8
|
-
* - "Run dlang install" for uninstalled dependencies
|
|
9
|
-
*
|
|
10
|
-
* @module
|
|
11
|
-
*/
|
|
12
|
-
import { CodeActionKind } from 'vscode-languageserver';
|
|
13
|
-
import { IssueCodes } from '../validation/constants.js';
|
|
14
|
-
/**
|
|
15
|
-
* Code action provider for DomainLang LSP features.
|
|
16
|
-
*
|
|
17
|
-
* Implements quick fixes for:
|
|
18
|
-
* - Import validation errors (add to model.yaml, run install)
|
|
19
|
-
*/
|
|
20
|
-
export class DomainLangCodeActionProvider {
|
|
21
|
-
/**
|
|
22
|
-
* Generates code actions for the given diagnostics.
|
|
23
|
-
*
|
|
24
|
-
* @param document - The document containing the diagnostics
|
|
25
|
-
* @param params - Code action request parameters including diagnostics
|
|
26
|
-
* @returns Array of code actions, or undefined if none applicable
|
|
27
|
-
*/
|
|
28
|
-
getCodeActions(document, params) {
|
|
29
|
-
const result = [];
|
|
30
|
-
const acceptor = (ca) => {
|
|
31
|
-
if (ca)
|
|
32
|
-
result.push(ca);
|
|
33
|
-
};
|
|
34
|
-
for (const diagnostic of params.context.diagnostics) {
|
|
35
|
-
this.createCodeActions(diagnostic, document, acceptor);
|
|
36
|
-
}
|
|
37
|
-
return result.length > 0 ? result : undefined;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Creates code actions for a specific diagnostic.
|
|
41
|
-
*
|
|
42
|
-
* Matches on diagnostic.data.code to determine which quick fix to offer.
|
|
43
|
-
*/
|
|
44
|
-
createCodeActions(diagnostic, document, accept) {
|
|
45
|
-
const data = diagnostic.data;
|
|
46
|
-
if (!data?.code)
|
|
47
|
-
return;
|
|
48
|
-
switch (data.code) {
|
|
49
|
-
case IssueCodes.ImportNotInManifest:
|
|
50
|
-
if (data.alias) {
|
|
51
|
-
accept(this.createAddToManifestAction(diagnostic, document, data.alias));
|
|
52
|
-
}
|
|
53
|
-
break;
|
|
54
|
-
case IssueCodes.ImportRequiresManifest:
|
|
55
|
-
if (data.specifier) {
|
|
56
|
-
accept(this.createCreateManifestAction(diagnostic, document, data.specifier));
|
|
57
|
-
}
|
|
58
|
-
break;
|
|
59
|
-
case IssueCodes.ImportNotInstalled:
|
|
60
|
-
if (data.alias) {
|
|
61
|
-
accept(this.createRunInstallAction(diagnostic, data.alias));
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
case IssueCodes.ImportMissingRef:
|
|
65
|
-
if (data.alias) {
|
|
66
|
-
accept(this.createAddRefAction(diagnostic, data.alias));
|
|
67
|
-
}
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Creates a code action to add a dependency to model.yaml.
|
|
73
|
-
*
|
|
74
|
-
* This generates a WorkspaceEdit that modifies model.yaml to add
|
|
75
|
-
* the missing dependency with a placeholder version.
|
|
76
|
-
*/
|
|
77
|
-
createAddToManifestAction(diagnostic, _document, alias) {
|
|
78
|
-
// Create a command that will be executed to add the dependency
|
|
79
|
-
// Since we can't directly edit model.yaml from here (it's not the current document),
|
|
80
|
-
// we provide a command that the extension can handle
|
|
81
|
-
return {
|
|
82
|
-
title: `Add '${alias}' to model.yaml`,
|
|
83
|
-
kind: CodeActionKind.QuickFix,
|
|
84
|
-
diagnostics: [diagnostic],
|
|
85
|
-
isPreferred: true,
|
|
86
|
-
command: {
|
|
87
|
-
title: `Add '${alias}' to model.yaml`,
|
|
88
|
-
command: 'domainlang.addDependency',
|
|
89
|
-
arguments: [alias]
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Creates a code action to create model.yaml with the dependency.
|
|
95
|
-
*/
|
|
96
|
-
createCreateManifestAction(diagnostic, _document, specifier) {
|
|
97
|
-
const alias = specifier.split('/')[0];
|
|
98
|
-
return {
|
|
99
|
-
title: `Create model.yaml with '${alias}' dependency`,
|
|
100
|
-
kind: CodeActionKind.QuickFix,
|
|
101
|
-
diagnostics: [diagnostic],
|
|
102
|
-
isPreferred: true,
|
|
103
|
-
command: {
|
|
104
|
-
title: `Create model.yaml`,
|
|
105
|
-
command: 'domainlang.createManifest',
|
|
106
|
-
arguments: [alias, specifier]
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Creates a code action to run dlang install.
|
|
112
|
-
*/
|
|
113
|
-
createRunInstallAction(diagnostic, alias) {
|
|
114
|
-
return {
|
|
115
|
-
title: `Run 'dlang install' to fetch '${alias}'`,
|
|
116
|
-
kind: CodeActionKind.QuickFix,
|
|
117
|
-
diagnostics: [diagnostic],
|
|
118
|
-
isPreferred: true,
|
|
119
|
-
command: {
|
|
120
|
-
title: 'Install dependencies',
|
|
121
|
-
command: 'domainlang.install',
|
|
122
|
-
arguments: []
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Creates a code action to add ref to dependency.
|
|
128
|
-
*/
|
|
129
|
-
createAddRefAction(diagnostic, alias) {
|
|
130
|
-
return {
|
|
131
|
-
title: `Add git ref to '${alias}' in model.yaml`,
|
|
132
|
-
kind: CodeActionKind.QuickFix,
|
|
133
|
-
diagnostics: [diagnostic],
|
|
134
|
-
isPreferred: false,
|
|
135
|
-
command: {
|
|
136
|
-
title: 'Add ref',
|
|
137
|
-
command: 'domainlang.addRef',
|
|
138
|
-
arguments: [alias]
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
//# sourceMappingURL=domain-lang-code-actions.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"domain-lang-code-actions.js","sourceRoot":"","sources":["../../src/lsp/domain-lang-code-actions.ts"],"names":[],"mappings":"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"}
|