@domainlang/language 0.1.20
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 +163 -0
- package/out/ast-augmentation.d.ts +6 -0
- package/out/ast-augmentation.js +2 -0
- package/out/ast-augmentation.js.map +1 -0
- package/out/domain-lang-module.d.ts +57 -0
- package/out/domain-lang-module.js +67 -0
- package/out/domain-lang-module.js.map +1 -0
- package/out/generated/ast.d.ts +759 -0
- package/out/generated/ast.js +556 -0
- package/out/generated/ast.js.map +1 -0
- package/out/generated/grammar.d.ts +6 -0
- package/out/generated/grammar.js +2407 -0
- package/out/generated/grammar.js.map +1 -0
- package/out/generated/module.d.ts +13 -0
- package/out/generated/module.js +21 -0
- package/out/generated/module.js.map +1 -0
- package/out/index.d.ts +16 -0
- package/out/index.js +22 -0
- package/out/index.js.map +1 -0
- package/out/lsp/domain-lang-code-actions.d.ts +55 -0
- package/out/lsp/domain-lang-code-actions.js +143 -0
- package/out/lsp/domain-lang-code-actions.js.map +1 -0
- package/out/lsp/domain-lang-completion.d.ts +37 -0
- package/out/lsp/domain-lang-completion.js +452 -0
- package/out/lsp/domain-lang-completion.js.map +1 -0
- package/out/lsp/domain-lang-formatter.d.ts +15 -0
- package/out/lsp/domain-lang-formatter.js +43 -0
- package/out/lsp/domain-lang-formatter.js.map +1 -0
- package/out/lsp/domain-lang-naming.d.ts +34 -0
- package/out/lsp/domain-lang-naming.js +49 -0
- package/out/lsp/domain-lang-naming.js.map +1 -0
- package/out/lsp/domain-lang-scope.d.ts +59 -0
- package/out/lsp/domain-lang-scope.js +102 -0
- package/out/lsp/domain-lang-scope.js.map +1 -0
- package/out/lsp/domain-lang-workspace-manager.d.ts +21 -0
- package/out/lsp/domain-lang-workspace-manager.js +93 -0
- package/out/lsp/domain-lang-workspace-manager.js.map +1 -0
- package/out/lsp/hover/ddd-pattern-explanations.d.ts +50 -0
- package/out/lsp/hover/ddd-pattern-explanations.js +196 -0
- package/out/lsp/hover/ddd-pattern-explanations.js.map +1 -0
- package/out/lsp/hover/domain-lang-hover.d.ts +19 -0
- package/out/lsp/hover/domain-lang-hover.js +302 -0
- package/out/lsp/hover/domain-lang-hover.js.map +1 -0
- package/out/lsp/hover/domain-lang-keywords.d.ts +13 -0
- package/out/lsp/hover/domain-lang-keywords.js +47 -0
- package/out/lsp/hover/domain-lang-keywords.js.map +1 -0
- package/out/lsp/manifest-diagnostics.d.ts +82 -0
- package/out/lsp/manifest-diagnostics.js +230 -0
- package/out/lsp/manifest-diagnostics.js.map +1 -0
- package/out/main-browser.d.ts +1 -0
- package/out/main-browser.js +11 -0
- package/out/main-browser.js.map +1 -0
- package/out/main.d.ts +1 -0
- package/out/main.js +74 -0
- package/out/main.js.map +1 -0
- package/out/sdk/ast-augmentation.d.ts +136 -0
- package/out/sdk/ast-augmentation.js +62 -0
- package/out/sdk/ast-augmentation.js.map +1 -0
- package/out/sdk/index.d.ts +94 -0
- package/out/sdk/index.js +97 -0
- package/out/sdk/index.js.map +1 -0
- package/out/sdk/indexes.d.ts +16 -0
- package/out/sdk/indexes.js +97 -0
- package/out/sdk/indexes.js.map +1 -0
- package/out/sdk/loader-node.d.ts +51 -0
- package/out/sdk/loader-node.js +119 -0
- package/out/sdk/loader-node.js.map +1 -0
- package/out/sdk/loader.d.ts +49 -0
- package/out/sdk/loader.js +85 -0
- package/out/sdk/loader.js.map +1 -0
- package/out/sdk/patterns.d.ts +93 -0
- package/out/sdk/patterns.js +123 -0
- package/out/sdk/patterns.js.map +1 -0
- package/out/sdk/query.d.ts +90 -0
- package/out/sdk/query.js +679 -0
- package/out/sdk/query.js.map +1 -0
- package/out/sdk/resolution.d.ts +52 -0
- package/out/sdk/resolution.js +68 -0
- package/out/sdk/resolution.js.map +1 -0
- package/out/sdk/types.d.ts +280 -0
- package/out/sdk/types.js +8 -0
- package/out/sdk/types.js.map +1 -0
- package/out/services/dependency-analyzer.d.ts +58 -0
- package/out/services/dependency-analyzer.js +254 -0
- package/out/services/dependency-analyzer.js.map +1 -0
- package/out/services/dependency-resolver.d.ts +146 -0
- package/out/services/dependency-resolver.js +452 -0
- package/out/services/dependency-resolver.js.map +1 -0
- package/out/services/git-url-resolver.browser.d.ts +10 -0
- package/out/services/git-url-resolver.browser.js +19 -0
- package/out/services/git-url-resolver.browser.js.map +1 -0
- package/out/services/git-url-resolver.d.ts +158 -0
- package/out/services/git-url-resolver.js +416 -0
- package/out/services/git-url-resolver.js.map +1 -0
- package/out/services/governance-validator.d.ts +44 -0
- package/out/services/governance-validator.js +153 -0
- package/out/services/governance-validator.js.map +1 -0
- package/out/services/import-resolver.d.ts +77 -0
- package/out/services/import-resolver.js +240 -0
- package/out/services/import-resolver.js.map +1 -0
- package/out/services/performance-optimizer.d.ts +60 -0
- package/out/services/performance-optimizer.js +140 -0
- package/out/services/performance-optimizer.js.map +1 -0
- package/out/services/relationship-inference.d.ts +11 -0
- package/out/services/relationship-inference.js +98 -0
- package/out/services/relationship-inference.js.map +1 -0
- package/out/services/semver.d.ts +98 -0
- package/out/services/semver.js +195 -0
- package/out/services/semver.js.map +1 -0
- package/out/services/types.d.ts +340 -0
- package/out/services/types.js +46 -0
- package/out/services/types.js.map +1 -0
- package/out/services/workspace-manager.d.ts +123 -0
- package/out/services/workspace-manager.js +489 -0
- package/out/services/workspace-manager.js.map +1 -0
- package/out/syntaxes/domain-lang.monarch.d.ts +76 -0
- package/out/syntaxes/domain-lang.monarch.js +29 -0
- package/out/syntaxes/domain-lang.monarch.js.map +1 -0
- package/out/utils/import-utils.d.ts +49 -0
- package/out/utils/import-utils.js +128 -0
- package/out/utils/import-utils.js.map +1 -0
- package/out/validation/bounded-context.d.ts +11 -0
- package/out/validation/bounded-context.js +79 -0
- package/out/validation/bounded-context.js.map +1 -0
- package/out/validation/classification.d.ts +3 -0
- package/out/validation/classification.js +3 -0
- package/out/validation/classification.js.map +1 -0
- package/out/validation/constants.d.ts +180 -0
- package/out/validation/constants.js +235 -0
- package/out/validation/constants.js.map +1 -0
- package/out/validation/domain-lang-validator.d.ts +2 -0
- package/out/validation/domain-lang-validator.js +27 -0
- package/out/validation/domain-lang-validator.js.map +1 -0
- package/out/validation/domain.d.ts +11 -0
- package/out/validation/domain.js +63 -0
- package/out/validation/domain.js.map +1 -0
- package/out/validation/import.d.ts +68 -0
- package/out/validation/import.js +237 -0
- package/out/validation/import.js.map +1 -0
- package/out/validation/manifest.d.ts +144 -0
- package/out/validation/manifest.js +327 -0
- package/out/validation/manifest.js.map +1 -0
- package/out/validation/maps.d.ts +21 -0
- package/out/validation/maps.js +60 -0
- package/out/validation/maps.js.map +1 -0
- package/out/validation/metadata.d.ts +7 -0
- package/out/validation/metadata.js +16 -0
- package/out/validation/metadata.js.map +1 -0
- package/out/validation/model.d.ts +12 -0
- package/out/validation/model.js +29 -0
- package/out/validation/model.js.map +1 -0
- package/out/validation/relationships.d.ts +12 -0
- package/out/validation/relationships.js +94 -0
- package/out/validation/relationships.js.map +1 -0
- package/out/validation/shared.d.ts +6 -0
- package/out/validation/shared.js +12 -0
- package/out/validation/shared.js.map +1 -0
- package/package.json +110 -0
- package/src/ast-augmentation.ts +5 -0
- package/src/domain-lang-module.ts +112 -0
- package/src/domain-lang.langium +351 -0
- package/src/generated/ast.ts +986 -0
- package/src/generated/grammar.ts +2409 -0
- package/src/generated/module.ts +25 -0
- package/src/index.ts +24 -0
- package/src/lsp/domain-lang-code-actions.ts +189 -0
- package/src/lsp/domain-lang-completion.ts +514 -0
- package/src/lsp/domain-lang-formatter.ts +51 -0
- package/src/lsp/domain-lang-naming.ts +56 -0
- package/src/lsp/domain-lang-scope.ts +137 -0
- package/src/lsp/domain-lang-workspace-manager.ts +104 -0
- package/src/lsp/hover/ddd-pattern-explanations.ts +237 -0
- package/src/lsp/hover/domain-lang-hover.ts +338 -0
- package/src/lsp/hover/domain-lang-keywords.ts +50 -0
- package/src/lsp/manifest-diagnostics.ts +290 -0
- package/src/main-browser.ts +15 -0
- package/src/main.ts +85 -0
- package/src/sdk/README.md +297 -0
- package/src/sdk/ast-augmentation.ts +157 -0
- package/src/sdk/index.ts +126 -0
- package/src/sdk/indexes.ts +155 -0
- package/src/sdk/loader-node.ts +146 -0
- package/src/sdk/loader.ts +99 -0
- package/src/sdk/patterns.ts +147 -0
- package/src/sdk/query.ts +802 -0
- package/src/sdk/resolution.ts +78 -0
- package/src/sdk/types.ts +323 -0
- package/src/services/dependency-analyzer.ts +321 -0
- package/src/services/dependency-resolver.ts +551 -0
- package/src/services/git-url-resolver.browser.ts +26 -0
- package/src/services/git-url-resolver.ts +517 -0
- package/src/services/governance-validator.ts +177 -0
- package/src/services/import-resolver.ts +292 -0
- package/src/services/performance-optimizer.ts +170 -0
- package/src/services/relationship-inference.ts +121 -0
- package/src/services/semver.ts +213 -0
- package/src/services/types.ts +415 -0
- package/src/services/workspace-manager.ts +607 -0
- package/src/syntaxes/domain-lang.monarch.ts +29 -0
- package/src/utils/import-utils.ts +152 -0
- package/src/validation/bounded-context.ts +99 -0
- package/src/validation/classification.ts +5 -0
- package/src/validation/constants.ts +304 -0
- package/src/validation/domain-lang-validator.ts +33 -0
- package/src/validation/domain.ts +77 -0
- package/src/validation/import.ts +295 -0
- package/src/validation/manifest.ts +439 -0
- package/src/validation/maps.ts +76 -0
- package/src/validation/metadata.ts +18 -0
- package/src/validation/model.ts +37 -0
- package/src/validation/relationships.ts +154 -0
- package/src/validation/shared.ts +14 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import type { ValidationAcceptor, ValidationChecks } from 'langium';
|
|
4
|
+
import { Cancellation } from 'langium';
|
|
5
|
+
import type { DomainLangAstType, ImportStatement } from '../generated/ast.js';
|
|
6
|
+
import type { DomainLangServices } from '../domain-lang-module.js';
|
|
7
|
+
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
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 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
|
+
*
|
|
18
|
+
* Checks:
|
|
19
|
+
* - External imports require manifest + alias
|
|
20
|
+
* - Local path dependencies stay inside workspace
|
|
21
|
+
* - Lock file exists for external dependencies
|
|
22
|
+
*/
|
|
23
|
+
export class ImportValidator {
|
|
24
|
+
private readonly workspaceManager: WorkspaceManager;
|
|
25
|
+
|
|
26
|
+
constructor(services: DomainLangServices) {
|
|
27
|
+
this.workspaceManager = services.imports.WorkspaceManager;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Validates an import statement asynchronously.
|
|
32
|
+
*
|
|
33
|
+
* Langium validators can return MaybePromise<void>, enabling async operations
|
|
34
|
+
* like reading manifests via the shared, cached WorkspaceManager.
|
|
35
|
+
*/
|
|
36
|
+
async checkImportPath(
|
|
37
|
+
imp: ImportStatement,
|
|
38
|
+
accept: ValidationAcceptor,
|
|
39
|
+
document: LangiumDocument,
|
|
40
|
+
_cancelToken: Cancellation.CancellationToken
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
if (!imp.uri) {
|
|
43
|
+
accept('error', ValidationMessages.IMPORT_MISSING_URI(), {
|
|
44
|
+
node: imp,
|
|
45
|
+
keyword: 'import',
|
|
46
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
47
|
+
data: { code: IssueCodes.ImportMissingUri }
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!this.isExternalImport(imp.uri)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Initialize workspace manager from document location
|
|
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), {
|
|
76
|
+
node: imp,
|
|
77
|
+
property: 'uri',
|
|
78
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
79
|
+
data: { code: IssueCodes.ImportNotInManifest, alias }
|
|
80
|
+
});
|
|
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
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Gets the normalized dependency configuration for an alias.
|
|
123
|
+
*/
|
|
124
|
+
private getDependency(manifest: ModelManifest, alias: string): ExtendedDependencySpec | undefined {
|
|
125
|
+
const dep = manifest.dependencies?.[alias];
|
|
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,
|
|
147
|
+
accept: ValidationAcceptor,
|
|
148
|
+
imp: ImportStatement
|
|
149
|
+
): void {
|
|
150
|
+
if (dependency.source && dependency.path) {
|
|
151
|
+
accept('error', ValidationMessages.IMPORT_CONFLICTING_SOURCE_PATH(alias), {
|
|
152
|
+
node: imp,
|
|
153
|
+
property: 'uri',
|
|
154
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
155
|
+
data: { code: IssueCodes.ImportConflictingSourcePath, alias }
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!dependency.source && !dependency.path) {
|
|
161
|
+
accept('error', ValidationMessages.IMPORT_MISSING_SOURCE_OR_PATH(alias), {
|
|
162
|
+
node: imp,
|
|
163
|
+
property: 'uri',
|
|
164
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
165
|
+
data: { code: IssueCodes.ImportMissingSourceOrPath, alias }
|
|
166
|
+
});
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (dependency.source && !dependency.ref) {
|
|
171
|
+
accept('error', ValidationMessages.IMPORT_MISSING_REF(alias), {
|
|
172
|
+
node: imp,
|
|
173
|
+
property: 'uri',
|
|
174
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
175
|
+
data: { code: IssueCodes.ImportMissingRef, alias }
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (dependency.path) {
|
|
180
|
+
this.validateLocalPathDependency(dependency.path, alias, accept, imp);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Validates local path dependencies stay within workspace.
|
|
186
|
+
*/
|
|
187
|
+
private validateLocalPathDependency(
|
|
188
|
+
dependencyPath: string,
|
|
189
|
+
alias: string,
|
|
190
|
+
accept: ValidationAcceptor,
|
|
191
|
+
imp: ImportStatement
|
|
192
|
+
): void {
|
|
193
|
+
if (path.isAbsolute(dependencyPath)) {
|
|
194
|
+
accept('error', ValidationMessages.IMPORT_ABSOLUTE_PATH(alias, dependencyPath), {
|
|
195
|
+
node: imp,
|
|
196
|
+
property: 'uri',
|
|
197
|
+
codeDescription: buildCodeDescription('language.md', 'imports'),
|
|
198
|
+
data: { code: IssueCodes.ImportAbsolutePath, alias, path: dependencyPath }
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const workspaceRoot = this.workspaceManager.getWorkspaceRoot();
|
|
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
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Validates that external dependency is in lock file and cached.
|
|
219
|
+
*/
|
|
220
|
+
private async validateCachedPackage(
|
|
221
|
+
dependency: ExtendedDependencySpec,
|
|
222
|
+
alias: string,
|
|
223
|
+
lockFile: LockFile,
|
|
224
|
+
accept: ValidationAcceptor,
|
|
225
|
+
imp: ImportStatement
|
|
226
|
+
): Promise<void> {
|
|
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
|
+
});
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const workspaceRoot = this.workspaceManager.getWorkspaceRoot();
|
|
242
|
+
const cacheDir = this.getCacheDirectory(workspaceRoot, packageKey, lockedDep.commit);
|
|
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
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Creates validation checks for import statements.
|
|
279
|
+
*
|
|
280
|
+
* Returns async validators that leverage the shared WorkspaceManager
|
|
281
|
+
* for cached manifest/lock file reading.
|
|
282
|
+
*/
|
|
283
|
+
export function createImportChecks(services: DomainLangServices): ValidationChecks<DomainLangAstType> {
|
|
284
|
+
const validator = new ImportValidator(services);
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
// Langium 4.x supports async validators via MaybePromise<void>
|
|
288
|
+
ImportStatement: async (imp, accept, cancelToken) => {
|
|
289
|
+
const document = imp.$document;
|
|
290
|
+
if (!document) return;
|
|
291
|
+
|
|
292
|
+
await validator.checkImportPath(imp, accept, document, cancelToken);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|